Refined theme customization mechanism

* Created abstract SettingsPanel class for defining settings screen
pages
* Moves theme customization related settings to new class
ThemeCustomizationPanel
* Changes Theme to use a map internally
This commit is contained in:
Kai S. K. Engelbart 2019-12-21 00:29:16 +01:00
parent c7959e5287
commit 10dd3635a5
7 changed files with 496 additions and 535 deletions

View File

@ -29,6 +29,7 @@ import envoy.client.LocalDB;
import envoy.client.Settings; import envoy.client.Settings;
import envoy.client.event.EventBus; import envoy.client.event.EventBus;
import envoy.client.event.ThemeChangeEvent; import envoy.client.event.ThemeChangeEvent;
import envoy.client.ui.settings.SettingsScreen;
import envoy.client.util.EnvoyLog; import envoy.client.util.EnvoyLog;
import envoy.schema.Message; import envoy.schema.Message;
import envoy.schema.User; import envoy.schema.User;
@ -157,7 +158,6 @@ public class ChatWindow extends JFrame {
settingsButton.addActionListener((evt) -> { settingsButton.addActionListener((evt) -> {
try { try {
new SettingsScreen().setVisible(true); new SettingsScreen().setVisible(true);
changeChatWindowColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "An error occured while opening the settings screen", e); logger.log(Level.WARNING, "An error occured while opening the settings screen", e);
e.printStackTrace(); e.printStackTrace();

View File

@ -1,458 +0,0 @@
package envoy.client.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.ListSelectionModel;
import envoy.client.Settings;
import envoy.client.util.EnvoyLog;
import envoy.client.event.EventBus;
import envoy.client.event.ThemeChangeEvent;
/**
* This class provides the GUI to change the user specific settings.
*
* Project: <strong>envoy-client</strong><br>
* File: <strong>SettingsScreen.java</strong><br>
* Created: <strong>31 Oct 2019</strong><br>
*
* @author Leon Hofmeister
* @author Maximilian K&auml;fer
* @author Kai S. K. Engelbart
*/
public class SettingsScreen extends JDialog {
private static final long serialVersionUID = -4476913491263077107L;
private final JPanel contentPanel = new JPanel();
private DefaultListModel<String> optionsListModel = new DefaultListModel<>();
private final JList<String> options = new JList<>();
private JPanel buttonPane = new JPanel();
private JPanel themeContent = new JPanel();
private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]);
private JComboBox<String> themes = new JComboBox<>(themeArray);
private GridBagConstraints gbc_themeContent = new GridBagConstraints();
private JButton createNewThemeButton = new JButton("Create New Theme");
private JPanel colorsPanel = new JPanel();
private JButton okButton = new JButton("Save");
private JButton cancelButton = new JButton("Cancel");
private static int space = 5;
private Theme temporaryTheme, selectedTheme;
private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName());
/**
* Builds the settings screen.
*
* @since Envoy v0.1-alpha
*/
public SettingsScreen() {
logger.info(Settings.getInstance().getCurrentTheme());
setBounds(10, 10, 450, 650);
getContentPane().setLayout(new BorderLayout());
{
createNewThemeButton.setEnabled(false);
temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
// Content pane
GridBagLayout gbl_contentPanel = new GridBagLayout();
gbl_contentPanel.columnWidths = new int[] { 1, 1 };
gbl_contentPanel.rowHeights = new int[] { 1 };
gbl_contentPanel.columnWeights = new double[] { 0.05, 1.0 };
gbl_contentPanel.rowWeights = new double[] { 1.0 };
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(gbl_contentPanel);
options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
options.addListSelectionListener((listSelectionEvent) -> {
if (!listSelectionEvent.getValueIsAdjusting()) {
@SuppressWarnings("unchecked")
final JList<String> selectedOption = (JList<String>) listSelectionEvent.getSource();
final String option = selectedOption.getSelectedValue();
logger.log(Level.FINEST, option);
switch (option) {
case "Color Themes":
setContent(themeContent, gbc_themeContent);
getContentPane().repaint();
getContentPane().revalidate();
break;
}
}
});
options.setFont(new Font("Arial", Font.PLAIN, 14));
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
GridBagConstraints gbc_optionsList = new GridBagConstraints();
gbc_optionsList.fill = GridBagConstraints.BOTH;
gbc_optionsList.gridx = 0;
gbc_optionsList.gridy = 0;
gbc_optionsList.anchor = GridBagConstraints.PAGE_START;
gbc_optionsList.insets = new Insets(space, space, space, space);
optionsListModel.addElement("Color Themes");
options.setModel(optionsListModel);
contentPanel.add(options, gbc_optionsList);
// Theme content
gbc_themeContent = new GridBagConstraints();
gbc_themeContent.fill = GridBagConstraints.BOTH;
gbc_themeContent.gridx = 1;
gbc_themeContent.gridy = 0;
gbc_themeContent.anchor = GridBagConstraints.PAGE_START;
gbc_themeContent.insets = new Insets(space, space, space, space);
GridBagLayout gbl_themeLayout = new GridBagLayout();
gbl_themeLayout.columnWidths = new int[] { 1, 1 };
gbl_themeLayout.rowHeights = new int[] { 1, 1 };
gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 };
gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 };
themeContent.setLayout(gbl_themeLayout);
themes.setSelectedItem(Settings.getInstance().getCurrentTheme());
themes.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
String selectedValue = (String) themes.getSelectedItem();
logger.log(Level.FINEST, selectedValue);
selectedTheme = Settings.getInstance().getThemes().get(selectedValue);
}
});
GridBagConstraints gbc_themes = new GridBagConstraints();
gbc_themes.fill = GridBagConstraints.HORIZONTAL;
gbc_themes.gridx = 0;
gbc_themes.gridy = 0;
gbc_themes.anchor = GridBagConstraints.NORTHWEST;
gbc_themes.insets = new Insets(space, space, space, space);
themeContent.add(themes, gbc_themes);
colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS));
colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 0);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 1);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getInteractableForegroundColor(),
"Interactable Foreground",
2);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getInteractableBackgroundColor(),
"Interactable Background",
3);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 4);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 5);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 6);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 7);
buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 8);
GridBagConstraints gbc_colorsPanel = new GridBagConstraints();
gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_colorsPanel.gridx = 0;
gbc_colorsPanel.gridy = 1;
gbc_colorsPanel.gridwidth = 2;
gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST;
gbc_colorsPanel.insets = new Insets(space, 0, 0, 0);
themeContent.add(colorsPanel, gbc_colorsPanel);
createNewThemeButton.setBackground(theme.getInteractableBackgroundColor());
createNewThemeButton.setForeground(theme.getInteractableForegroundColor());
colorsPanel.setBackground(theme.getCellColor());
createNewThemeButton.addActionListener((evt) -> {
try {
String s = JOptionPane.showInputDialog("Enter a name for the new theme");
logger.log(Level.FINEST, s);
Settings.getInstance()
.addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(),
temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(),
temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(),
temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor()));
themeArray = Arrays.copyOf(themeArray, themeArray.length + 1);
themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName();
temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
createNewThemeButton.setEnabled(false);
themes.addItem(themeArray[themeArray.length - 1]);
contentPanel.revalidate();
contentPanel.repaint();
} catch (Exception e) {
logger.info("New theme couldn't be created! " + e);
e.printStackTrace();
}
});
GridBagConstraints gbc_createNewTheme = new GridBagConstraints();
gbc_createNewTheme.gridx = 0;
gbc_createNewTheme.gridy = 10;
colorsPanel.add(createNewThemeButton, gbc_createNewTheme);
// ButtonPane-------------------------------------------------------
GridBagLayout gbl_buttonPane = new GridBagLayout();
gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 };
gbl_buttonPane.rowHeights = new int[] { 25, 0 };
gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE };
gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
getContentPane().add(buttonPane, BorderLayout.SOUTH);
buttonPane.setLayout(gbl_buttonPane);
{
cancelButton.setActionCommand("Cancel");
cancelButton.setBorderPainted(false);
GridBagConstraints gbc_cancelButton = new GridBagConstraints();
gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST;
gbc_cancelButton.insets = new Insets(space, space, space, space);
gbc_cancelButton.gridx = 0;
gbc_cancelButton.gridy = 0;
buttonPane.add(cancelButton, gbc_cancelButton);
cancelButton.addActionListener((evt) -> { dispose(); });
}
{
okButton.setActionCommand("OK");
okButton.setBorderPainted(false);
GridBagConstraints gbc_okButton = new GridBagConstraints();
gbc_okButton.anchor = GridBagConstraints.NORTHEAST;
gbc_okButton.fill = GridBagConstraints.EAST;
gbc_okButton.insets = new Insets(space, space, space, space);
gbc_okButton.gridx = 2;
gbc_okButton.gridy = 0;
buttonPane.add(okButton, gbc_okButton);
getRootPane().setDefaultButton(okButton);
okButton.addActionListener((evt) -> {
try {
Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary
Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName());
logger.log(Level.FINER, selectedTheme.getThemeName());
final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
changeSettingsScreenColors(currentTheme);
updateColorVariables(currentTheme);
EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme));
Settings.getInstance().save();
revalidate();
repaint();
} catch (Exception e) {
logger.warning("Something went wrong when changing the setting");
JOptionPane.showMessageDialog(this, "Something went wrong when changing the setting");
dispose();
}
});
}
}
changeSettingsScreenColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModal(true);
}
private void changeSettingsScreenColors(Theme theme) {
// whole JDialog
setBackground(theme.getBackgroundColor());
// contentPanel
contentPanel.setBackground(theme.getBackgroundColor());
// buttonPane
buttonPane.setBackground(theme.getCellColor());
// cancelButton
cancelButton.setBackground(theme.getInteractableBackgroundColor());
cancelButton.setForeground(theme.getInteractableForegroundColor());
// okButton
okButton.setBackground(theme.getInteractableBackgroundColor());
okButton.setForeground(theme.getInteractableForegroundColor());
// options
options.setSelectionForeground(theme.getUserNameColor());
options.setSelectionBackground(theme.getSelectionColor());
options.setForeground(theme.getUserNameColor());
options.setBackground(theme.getCellColor());
// themeContent
themeContent.setForeground(theme.getUserNameColor());
themeContent.setBackground(theme.getCellColor());
// themes
themes.setBackground(theme.getBackgroundColor());
themes.setForeground(getInvertedColor(theme.getBackgroundColor()));
createNewThemeButton.setBackground(theme.getInteractableBackgroundColor());
createNewThemeButton.setForeground(theme.getInteractableForegroundColor());
colorsPanel.setBackground(theme.getCellColor());
}
private void updateColorVariables(Theme theme) {
temporaryTheme = new Theme("temporaryTheme", theme);
colorsPanel.removeAll();
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getBackgroundColor(),
"Background",
0);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getCellColor(),
"Cells",
1);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getInteractableForegroundColor(),
"Interactable Foreground",
2);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getInteractableBackgroundColor(),
"Interactable Background",
3);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getMessageColorChat(),
"Messages Chat",
4);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getDateColorChat(),
"Date Chat",
5);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getSelectionColor(),
"Selection",
6);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getTypingMessageColor(),
"Typing Message",
7);
buildCustomizeElement(new JPanel(),
new JButton(),
new JTextPane(),
theme,
theme.getUserNameColor(),
"User Names",
8);
GridBagConstraints gbc_createNewTheme = new GridBagConstraints();
gbc_createNewTheme.gridx = 0;
gbc_createNewTheme.gridy = 10;
colorsPanel.add(createNewThemeButton, gbc_createNewTheme);
}
private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); }
private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) {
textPane.setFont(new Font("Arial", Font.PLAIN, 14));
textPane.setBackground(theme.getBackgroundColor());
textPane.setForeground(getInvertedColor(theme.getBackgroundColor()));
textPane.setText(name);
textPane.setEditable(false);
button.setBackground(color);
button.setPreferredSize(new Dimension(25, 25));
button.addActionListener((evt) -> {
try {
Color newColor = JColorChooser.showDialog(null, "Choose a color", color);
if (newColor.getRGB() != color.getRGB()) {
logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB()));
// TODO: When Theme changed in same settings screen, color variable doesnt
// update.
temporaryTheme.setColor(yIndex, newColor);
createNewThemeButton.setEnabled(true);
}
button.setBackground(newColor);
} catch (Exception e) {
logger.info("An error occured while opening Color Chooser: " + e);
e.printStackTrace();
}
});
panel.add(textPane);
panel.add(button);
panel.setBackground(theme.getCellColor());
panel.setAlignmentX(Component.LEFT_ALIGNMENT);
colorsPanel.add(panel);
}
private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); }
}

View File

@ -2,6 +2,8 @@ package envoy.client.ui;
import java.awt.Color; import java.awt.Color;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/** /**
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
@ -15,16 +17,8 @@ public class Theme implements Serializable {
private static final long serialVersionUID = 141727847527060352L; private static final long serialVersionUID = 141727847527060352L;
private String themeName; private String themeName;
private Color backgroundColor; private Map<String, Color> colors = new HashMap<>();
private Color cellColor;
private Color interactableBackgroundColor;
private Color userNameColor;
private Color interactableForegroundColor;
private Color messageColorChat;
private Color dateColorChat;
private Color selectionColor;
private Color typingMessageColor;
/** /**
* Initializes a {@link Theme} with all colors relevant to the application GUI. * Initializes a {@link Theme} with all colors relevant to the application GUI.
@ -47,15 +41,15 @@ public class Theme implements Serializable {
this.themeName = themeName; this.themeName = themeName;
this.backgroundColor = backgroundColor; colors.put("backgroundColor", backgroundColor);
this.cellColor = cellColor; colors.put("cellColor", cellColor);
this.interactableForegroundColor = interactableForegroundColor; colors.put("interactableForegroundColor", interactableForegroundColor);
this.interactableBackgroundColor = interactableBackgroundColor; colors.put("interactableBackgroundColor", interactableBackgroundColor);
this.messageColorChat = messageColorChat; colors.put("messageColorChat", messageColorChat);
this.dateColorChat = dateColorChat; colors.put("dateColorChat", dateColorChat);
this.selectionColor = selectionColor; colors.put("selectionColor", selectionColor);
this.typingMessageColor = typingMessageColor; colors.put("typingMessageColor", typingMessageColor);
this.userNameColor = userNameColor; colors.put("userNameColor", userNameColor);
} }
/** /**
@ -66,11 +60,16 @@ public class Theme implements Serializable {
* @param other the {@link Theme} to copy * @param other the {@link Theme} to copy
*/ */
public Theme(String name, Theme other) { public Theme(String name, Theme other) {
this(name, other.backgroundColor, other.cellColor, other.interactableForegroundColor, themeName = name;
other.interactableBackgroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, colors.putAll(other.colors);
other.typingMessageColor, other.userNameColor);
} }
/**
* @return a {@code Map<String, Color>} of all colors defined for this theme
* with their names as keys
*/
public Map<String, Color> getColors() { return colors; }
/** /**
* @return name of the theme * @return name of the theme
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
@ -81,104 +80,62 @@ public class Theme implements Serializable {
* @return interactableForegroundColor * @return interactableForegroundColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getInteractableForegroundColor() { return interactableForegroundColor; } public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); }
/** /**
* @return messageColorChat * @return messageColorChat
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getMessageColorChat() { return messageColorChat; } public Color getMessageColorChat() { return colors.get("messageColorChat"); }
/** /**
* @return dateColorChat * @return dateColorChat
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getDateColorChat() { return dateColorChat; } public Color getDateColorChat() { return colors.get("dateColorChat"); }
/** /**
* @return selectionColor * @return selectionColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getSelectionColor() { return selectionColor; } public Color getSelectionColor() { return colors.get("selectionColor"); }
/** /**
* @return typingMessageColor * @return typingMessageColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getTypingMessageColor() { return typingMessageColor; } public Color getTypingMessageColor() { return colors.get("typingMessageColor"); }
/** /**
* @return backgroundColor * @return backgroundColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getBackgroundColor() { return backgroundColor; } public Color getBackgroundColor() { return colors.get("backgroundColor"); }
/** /**
* @return cellColor * @return cellColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getCellColor() { return cellColor; } public Color getCellColor() { return colors.get("cellColor"); }
/** /**
* @return interactableBackgroundColor * @return interactableBackgroundColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getInteractableBackgroundColor() { return interactableBackgroundColor; } public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); }
/** /**
* @return userNameColor * @return userNameColor
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getUserNameColor() { return userNameColor; } public Color getUserNameColor() { return colors.get("userNameColor"); }
/** /**
* Sets the a specific {@link Color} in this theme to a new {@link Color} * Sets the a specific {@link Color} in this theme to a new {@link Color}
* *
* @param index - index of the color </br> * @param colorName the name of the {@link Color} to set
* 0 = backgroundColor </br> * @param newColor the new {@link Color} to be set
* 1 = cellColor </br>
* 2 = interactableForegroundColor </br>
* 3 = interactableBackgroundColor </br>
* 4 = messageColorChat </br>
* 5 = dateColorChat </br>
* 6 = selectionColor </br>
* 7 = typingMessageColor </br>
* 8 = userNameColor </br>
* </br>
*
* @param newColor - new {@link Color} to be set
* @since Envoy 0.2-alpha * @since Envoy 0.2-alpha
*/ */
public void setColor(int index, Color newColor) { public void setColor(String colorName, Color newColor) { colors.put(colorName, newColor); }
switch (index) {
case 0:
backgroundColor = newColor;
break;
case 1:
cellColor = newColor;
break;
case 2:
interactableForegroundColor = newColor;
break;
case 3:
interactableBackgroundColor = newColor;
break;
case 4:
messageColorChat = newColor;
break;
case 5:
dateColorChat = newColor;
break;
case 6:
selectionColor = newColor;
break;
case 7:
typingMessageColor = newColor;
break;
case 8:
userNameColor = newColor;
break;
}
}
} }

View File

@ -0,0 +1,23 @@
package envoy.client.ui.settings;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>SettingsPanel.java</strong><br>
* Created: <strong>20 Dec 2019</strong><br>
*
* @author Kai S. K. Engelbart
*/
public abstract class SettingsPanel extends JPanel {
private static final long serialVersionUID = -3069212622468626050L;
/**
* @return an {@link ActionListener} that should be invoked when the OK button
* is pressed in the {@link SettingsScreen}
*/
public abstract ActionListener getOkButtonAction();
}

View File

@ -0,0 +1,187 @@
package envoy.client.ui.settings;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import envoy.client.Settings;
import envoy.client.event.EventBus;
import envoy.client.event.ThemeChangeEvent;
import envoy.client.ui.Theme;
import envoy.client.util.EnvoyLog;
/**
* This class provides the GUI to change the user specific settings.<br>
* <br>
* Project: <strong>envoy-client</strong><br>
* File: <strong>SettingsScreen.java</strong><br>
* Created: <strong>31 Oct 2019</strong><br>
*
* @author Leon Hofmeister
* @author Maximilian K&auml;fer
* @author Kai S. K. Engelbart
*/
public class SettingsScreen extends JDialog {
private static final long serialVersionUID = -4476913491263077107L;
private final JPanel contentPanel = new JPanel();
// Settings panel list
private final DefaultListModel<String> optionsListModel = new DefaultListModel<>();
private final JList<String> options = new JList<>(optionsListModel);
// OK and cancel buttons
private final JPanel buttonPane = new JPanel();
private final JButton okButton = new JButton("Save");
private final JButton cancelButton = new JButton("Cancel");
private final int space = 5;
private SettingsPanel settingsPanel;
private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName());
/**
* Initializes the settings screen.
*
* @since Envoy v0.1-alpha
*/
public SettingsScreen() {
logger.info("Currently selected theme: " + Settings.getInstance().getCurrentTheme());
Map<String, Class<? extends SettingsPanel>> panels = new HashMap<>();
panels.put("Color Themes", ThemeCustomizationPanel.class);
setBounds(10, 10, 450, 650);
getContentPane().setLayout(new BorderLayout());
{
// Content pane
GridBagLayout gbl_contentPanel = new GridBagLayout();
gbl_contentPanel.columnWidths = new int[] { 1, 1 };
gbl_contentPanel.rowHeights = new int[] { 1 };
gbl_contentPanel.columnWeights = new double[] { 0.05, 1.0 };
gbl_contentPanel.rowWeights = new double[] { 1.0 };
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(gbl_contentPanel);
options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
options.addListSelectionListener((listSelectionEvent) -> {
if (!listSelectionEvent.getValueIsAdjusting()) {
// Get selected settings panel
final String option = options.getSelectedValue();
logger.log(Level.FINEST, "Selected settings panel: " + option);
// Remove previous settings panel
if (settingsPanel != null)
contentPanel.remove(settingsPanel);
try {
settingsPanel = panels.get(option).getDeclaredConstructor().newInstance();
// Add selected settings panel
contentPanel.add(settingsPanel);
revalidate();
repaint();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
});
options.setFont(new Font("Arial", Font.PLAIN, 14));
GridBagConstraints gbc_optionsList = new GridBagConstraints();
gbc_optionsList.fill = GridBagConstraints.BOTH;
gbc_optionsList.gridx = 0;
gbc_optionsList.gridy = 0;
gbc_optionsList.anchor = GridBagConstraints.PAGE_START;
gbc_optionsList.insets = new Insets(space, space, space, space);
panels.keySet().forEach(name -> optionsListModel.addElement(name));
contentPanel.add(options, gbc_optionsList);
// ButtonPane
GridBagLayout gbl_buttonPane = new GridBagLayout();
gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 };
gbl_buttonPane.rowHeights = new int[] { 25, 0 };
gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE };
gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
getContentPane().add(buttonPane, BorderLayout.SOUTH);
buttonPane.setLayout(gbl_buttonPane);
{
cancelButton.setActionCommand("Cancel");
cancelButton.setBorderPainted(false);
GridBagConstraints gbc_cancelButton = new GridBagConstraints();
gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST;
gbc_cancelButton.insets = new Insets(space, space, space, space);
gbc_cancelButton.gridx = 0;
gbc_cancelButton.gridy = 0;
buttonPane.add(cancelButton, gbc_cancelButton);
cancelButton.addActionListener((evt) -> { dispose(); });
}
{
okButton.setActionCommand("OK");
okButton.setBorderPainted(false);
GridBagConstraints gbc_okButton = new GridBagConstraints();
gbc_okButton.anchor = GridBagConstraints.NORTHEAST;
gbc_okButton.fill = GridBagConstraints.EAST;
gbc_okButton.insets = new Insets(space, space, space, space);
gbc_okButton.gridx = 2;
gbc_okButton.gridy = 0;
buttonPane.add(okButton, gbc_okButton);
getRootPane().setDefaultButton(okButton);
// Invoke settings panel action on button press
okButton.addActionListener((evt) -> { if (settingsPanel != null) settingsPanel.getOkButtonAction().actionPerformed(evt); });
}
}
// Apply current theme
applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
// Respond to theme changes
EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get()));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModal(true);
}
private void applyTheme(Theme theme) {
// whole JDialog
setBackground(theme.getBackgroundColor());
// contentPanel
contentPanel.setBackground(theme.getBackgroundColor());
// buttonPane
buttonPane.setBackground(theme.getCellColor());
// cancelButton
cancelButton.setBackground(theme.getInteractableBackgroundColor());
cancelButton.setForeground(theme.getInteractableForegroundColor());
// okButton
okButton.setBackground(theme.getInteractableBackgroundColor());
okButton.setForeground(theme.getInteractableForegroundColor());
// options
options.setSelectionForeground(theme.getUserNameColor());
options.setSelectionBackground(theme.getSelectionColor());
options.setForeground(theme.getUserNameColor());
options.setBackground(theme.getCellColor());
}
}

View File

@ -0,0 +1,252 @@
package envoy.client.ui.settings;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import envoy.client.Settings;
import envoy.client.event.EventBus;
import envoy.client.event.ThemeChangeEvent;
import envoy.client.ui.Theme;
import envoy.client.util.EnvoyLog;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>ThemeCustomizationPanel.java</strong><br>
* Created: <strong>20 Dec 2019</strong><br>
*
* @author Kai S. K. Engelbart
*/
public class ThemeCustomizationPanel extends SettingsPanel {
private static final long serialVersionUID = -8697897390666456624L;
private JPanel colorsPanel = new JPanel();
private JButton createNewThemeButton = new JButton("Create New Theme");
private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]);
private JComboBox<String> themes = new JComboBox<>(themeArray);
private Theme temporaryTheme, selectedTheme;
private final int space = 5;
private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName());
/**
* Initializes a {@link ThemeCustomizationPanel} that enables the user to change
* the current {@link Theme} and create new themes as part of the
* {@link SettingsScreen}.
*/
public ThemeCustomizationPanel() {
temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
// Theme content
GridBagConstraints gbc_themeContent = new GridBagConstraints();
gbc_themeContent.fill = GridBagConstraints.BOTH;
gbc_themeContent.gridx = 1;
gbc_themeContent.gridy = 0;
gbc_themeContent.anchor = GridBagConstraints.PAGE_START;
gbc_themeContent.insets = new Insets(space, space, space, space);
GridBagLayout gbl_themeLayout = new GridBagLayout();
gbl_themeLayout.columnWidths = new int[] { 1, 1 };
gbl_themeLayout.rowHeights = new int[] { 1, 1 };
gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 };
gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 };
setLayout(gbl_themeLayout);
themes.setSelectedItem(Settings.getInstance().getCurrentTheme());
themes.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
String selectedValue = (String) themes.getSelectedItem();
logger.log(Level.FINEST, selectedValue);
selectedTheme = Settings.getInstance().getThemes().get(selectedValue);
}
});
GridBagConstraints gbc_themes = new GridBagConstraints();
gbc_themes.fill = GridBagConstraints.HORIZONTAL;
gbc_themes.gridx = 0;
gbc_themes.gridy = 0;
gbc_themes.anchor = GridBagConstraints.NORTHWEST;
gbc_themes.insets = new Insets(space, space, space, space);
add(themes, gbc_themes);
colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS));
colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
buildCustomizeElements(theme);
GridBagConstraints gbc_colorsPanel = new GridBagConstraints();
gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_colorsPanel.gridx = 0;
gbc_colorsPanel.gridy = 1;
gbc_colorsPanel.gridwidth = 2;
gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST;
gbc_colorsPanel.insets = new Insets(space, 0, 0, 0);
add(colorsPanel, gbc_colorsPanel);
createNewThemeButton.setEnabled(false);
createNewThemeButton.setBackground(theme.getInteractableBackgroundColor());
createNewThemeButton.setForeground(theme.getInteractableForegroundColor());
colorsPanel.setBackground(theme.getCellColor());
createNewThemeButton.addActionListener((evt) -> {
try {
String s = JOptionPane.showInputDialog("Enter a name for the new theme");
logger.log(Level.FINEST, s);
Settings.getInstance()
.addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(),
temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(),
temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(),
temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor()));
themeArray = Arrays.copyOf(themeArray, themeArray.length + 1);
themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName();
temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
createNewThemeButton.setEnabled(false);
themes.addItem(themeArray[themeArray.length - 1]);
} catch (Exception e) {
logger.info("New theme couldn't be created! " + e);
e.printStackTrace();
}
});
GridBagConstraints gbc_createNewTheme = new GridBagConstraints();
gbc_createNewTheme.gridx = 0;
gbc_createNewTheme.gridy = 10;
colorsPanel.add(createNewThemeButton, gbc_createNewTheme);
// Apply current theme
applyTheme(theme);
// Respond to theme changes
EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get()));
}
@Override
public ActionListener getOkButtonAction() {
return (evt) -> {
Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName());
logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName());
final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
updateColorVariables(currentTheme);
EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme));
revalidate();
repaint();
};
}
private void applyTheme(Theme theme) {
// themeContent
setForeground(theme.getUserNameColor());
setBackground(theme.getCellColor());
// themes
themes.setBackground(theme.getBackgroundColor());
themes.setForeground(getInvertedColor(theme.getBackgroundColor()));
createNewThemeButton.setBackground(theme.getInteractableBackgroundColor());
createNewThemeButton.setForeground(theme.getInteractableForegroundColor());
colorsPanel.setBackground(theme.getCellColor());
}
private void updateColorVariables(Theme theme) {
temporaryTheme = new Theme("temporaryTheme", theme);
colorsPanel.removeAll();
buildCustomizeElements(theme);
GridBagConstraints gbc_createNewTheme = new GridBagConstraints();
gbc_createNewTheme.gridx = 0;
gbc_createNewTheme.gridy = 10;
colorsPanel.add(createNewThemeButton, gbc_createNewTheme);
}
private void buildCustomizeElements(Theme theme) {
buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor");
buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor");
buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor");
buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor");
buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat");
buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat");
buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor");
buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor");
buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor");
}
private void buildCustomizeElement(Theme theme, Color color, String name, String colorName) {
JPanel panel = new JPanel();
JButton button = new JButton();
JTextPane textPane = new JTextPane();
textPane.setFont(new Font("Arial", Font.PLAIN, 14));
textPane.setBackground(theme.getBackgroundColor());
textPane.setForeground(getInvertedColor(theme.getBackgroundColor()));
textPane.setText(name);
textPane.setEditable(false);
button.setBackground(color);
button.setPreferredSize(new Dimension(25, 25));
button.addActionListener((evt) -> {
try {
Color newColor = JColorChooser.showDialog(null, "Choose a color", color);
if (newColor.getRGB() != color.getRGB()) {
logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB()));
// TODO: When Theme changed in same settings screen, color variable doesn't
// update
temporaryTheme.setColor(colorName, newColor);
createNewThemeButton.setEnabled(true);
}
button.setBackground(newColor);
} catch (Exception e) {
logger.info("An error occured while opening Color Chooser: " + e);
e.printStackTrace();
}
});
panel.add(textPane);
panel.add(button);
panel.setBackground(theme.getCellColor());
panel.setAlignmentX(Component.LEFT_ALIGNMENT);
colorsPanel.add(panel);
}
private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); }
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB