Merge pull request #2545 from SiboVG/issue-2224

[#2224] Add hex color input field in appearance panel
This commit is contained in:
Sibo Van Gool 2024-08-29 23:33:00 +02:00 committed by GitHub
commit e286eea144
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 126 additions and 22 deletions

View File

@ -1105,6 +1105,8 @@ AppearanceCfg.lbl.ttip.separateInsideOutside = Use a separate appearance for out
AppearanceCfg.lbl.ttip.separateLeftSideRightSide = Use a separate appearance for left and right side(s)
AppearanceCfg.lbl.AppearanceEdges = Appearance for edges:
AppearanceCfg.lbl.ttip.AppearanceEdges = Select the appearance that should be used for the edges
AppearanceCfg.placeholder.HexColor = Hex color
AppearanceCfg.ttip.HexColor = Hexadecimal representation of the color
! Texture Wrap Modes
TextureWrap.Repeat = Repeat

View File

@ -4,6 +4,8 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventObject;
@ -17,6 +19,7 @@ import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;
@ -27,6 +30,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import info.openrocket.core.util.Invalidatable;
import info.openrocket.swing.gui.widgets.PlaceholderTextField;
import net.miginfocom.swing.MigLayout;
import info.openrocket.core.appearance.Appearance;
import info.openrocket.core.appearance.AppearanceBuilder;
@ -126,7 +130,7 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
}
}
private class ColorActionListener implements ActionListener {
private abstract class ColorActionListener {
private final String valueName;
private final Object o;
@ -139,23 +143,35 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
Changes the color of the selected component to <color>
@param color: color to change the component to
*/
private void changeComponentColor(Color color) {
protected void setComponentColor(Color color) {
try {
final Method setMethod = o.getClass().getMethod(
"set" + valueName, ORColor.class);
final Method setMethod = o.getClass().getMethod("set" + valueName, ORColor.class);
if (color == null)
return;
try {
setMethod.invoke(o, ColorConversion
.fromAwtColor(color));
setMethod.invoke(o, ColorConversion.fromAwtColor(color));
} catch (Throwable e1) {
Application.getExceptionHandler()
.handleErrorCondition(e1);
Application.getExceptionHandler().handleErrorCondition(e1);
}
} catch (Throwable e1) {
Application.getExceptionHandler().handleErrorCondition(e1);
}
}
protected ORColor getComponentColor() {
try {
final Method getMethod = o.getClass().getMethod("get" + valueName);
return (ORColor) getMethod.invoke(o);
} catch (Throwable e1) {
Application.getExceptionHandler().handleErrorCondition(e1);
return null;
}
}
}
private class ColorButtonActionListener extends ColorActionListener implements ActionListener {
ColorButtonActionListener(final Object o, final String valueName) {
super(o, valueName);
}
/**
@ -166,10 +182,7 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
@Override
public void actionPerformed(ActionEvent colorClickEvent) {
try {
final Method getMethod = o.getClass().getMethod(
"get" + valueName);
ORColor c = (ORColor) getMethod
.invoke(o);
ORColor c = getComponentColor();
Color awtColor = ColorConversion.toAwtColor(c);
colorChooser.setColor(awtColor);
@ -180,7 +193,7 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
ChangeListener changeListener = new ChangeListener() {
public void stateChanged(ChangeEvent changeEvent) {
Color selected = colorChooser.getColor();
changeComponentColor(selected);
setComponentColor(selected);
}
};
model.addChangeListener(changeListener);
@ -191,14 +204,14 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
new ActionListener() {
@Override
public void actionPerformed(ActionEvent okEvent) {
changeComponentColor(colorChooser.getColor());
setComponentColor(colorChooser.getColor());
// Unbind listener to avoid the current component's appearance to change with other components
model.removeChangeListener(changeListener);
}
}, new ActionListener() {
@Override
public void actionPerformed(ActionEvent cancelEvent) {
changeComponentColor(awtColor);
setComponentColor(awtColor);
// Unbind listener to avoid the current component's appearance to change with other components
model.removeChangeListener(changeListener);
}
@ -210,6 +223,41 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
}
}
private class HexColorListener extends ColorActionListener implements ActionListener, FocusListener {
public HexColorListener(final Object o, final String valueName) {
super(o, valueName);
}
@Override
public void actionPerformed(ActionEvent e) {
updateColorFromHex((JTextField) e.getSource());
}
@Override
public void focusLost(FocusEvent e) {
updateColorFromHex((JTextField) e.getSource());
}
@Override
public void focusGained(FocusEvent e) {
// Do nothing
}
private void updateColorFromHex(JTextField field) {
String hex = field.getText();
try {
ORColor color = ColorConversion.fromHexColor(hex);
if (color == null) {
field.setText(ColorConversion.toHexColor(getComponentColor()));
return;
}
setComponentColor(ColorConversion.toAwtColor(color));
} catch (IllegalArgumentException ex) {
field.setText(ColorConversion.toHexColor(getComponentColor()));
}
}
}
/**
* Appearance panel for the appearance of a rocket component.
* @param document current document
@ -271,10 +319,17 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
}
final JButton figureColorButton = new JButton(
new ColorIcon(figureColor));
PlaceholderTextField figureColorHexField = new PlaceholderTextField(7);
figureColorHexField.setPlaceholder(trans.get("AppearanceCfg.placeholder.HexColor"));
figureColorHexField.setToolTipText(trans.get("AppearanceCfg.ttip.HexColor"));
figureColorHexField.setText(ColorConversion.toHexColor(c.getColor()));
ab.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) { figureColorButton.setIcon(new ColorIcon(c.getColor())); }
public void stateChanged(EventObject e) {
figureColorButton.setIcon(new ColorIcon(c.getColor()));
figureColorHexField.setText(ColorConversion.toHexColor(c.getColor()));
}
});
c.addChangeListener(new StateChangeListener() {
@ -285,11 +340,14 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
col = ((SwingPreferences) Application.getPreferences()).getDefaultColor(c.getClass());
}
figureColorButton.setIcon(new ColorIcon(col));
figureColorHexField.setText(ColorConversion.toHexColor(col));
}
});
figureColorButton
.addActionListener(new ColorActionListener(c, "Color"));
figureColorButton.addActionListener(new ColorButtonActionListener(c, "Color"));
HexColorListener colorHexListener = new HexColorListener(c, "Color");
figureColorHexField.addActionListener(colorHexListener);
figureColorHexField.addFocusListener(colorHexListener);
BooleanModel fDefault = new BooleanModel(c.getColor() == null);
register(fDefault);
@ -342,9 +400,15 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
{// Figure Color
add(new JLabel(trans.get("RocketCompCfg.lbl.Componentcolor")));
JPanel colorPanel = new JPanel(new MigLayout("ins 0"));
colorPanel.add(figureColorButton);
figureColorHexField.setColumns(7);
colorPanel.add(figureColorHexField);
fDefault.addEnableComponent(figureColorButton, false);
add(figureColorButton);
fDefault.addEnableComponent(figureColorHexField, false);
add(colorPanel, "growx");
order.add(figureColorButton);
order.add(figureColorHexField);
}
order.add(saveAsDefault);
@ -532,8 +596,15 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
});
JButton colorButton = new JButton(new ColorIcon(builder.getPaint()));
PlaceholderTextField colorHexField = new PlaceholderTextField(7);
colorHexField.setPlaceholder(trans.get("AppearanceCfg.placeholder.HexColor"));
colorHexField.setToolTipText(trans.get("AppearanceCfg.ttip.HexColor"));
colorHexField.setText(ColorConversion.toHexColor(builder.getPaint()));
colorButton.addActionListener(new ColorActionListener(builder, "Paint"));
colorButton.addActionListener(new ColorButtonActionListener(builder, "Paint"));
HexColorListener colorHexListener = new HexColorListener(builder, "Paint");
colorHexField.addActionListener(colorHexListener);
colorHexField.addFocusListener(colorHexListener);
// Texture Header Row
panel.add(new StyledLabel(trans.get("AppearanceCfg.lbl.Appearance"),
@ -630,9 +701,15 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
// TODO: move the separate columns in two separate panels instead of adding them in a zig-zag way
// Color
panel.add(new JLabel(trans.get("AppearanceCfg.lbl.color.Color")));
JPanel colorPanel = new JPanel(new MigLayout("ins 0"));
colorPanel.add(colorButton);
colorHexField.setColumns(7);
colorPanel.add(colorHexField);
mDefault.addEnableComponent(colorButton, false);
panel.add(colorButton);
mDefault.addEnableComponent(colorHexField, false);
panel.add(colorPanel, "growx");
order.add(colorButton);
order.add(colorHexField);
// Scale
panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.scale")), "gapleft para");
@ -674,7 +751,7 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
panel.add(spinShine, "split 3, w 60");
panel.add(unitShine);
panel.add(slideShine, "w 100lp");
order.add(order.indexOf(colorButton) + 1, ((SpinnerEditor) spinShine.getEditor()).getTextField());
order.add(order.indexOf(colorHexField) + 1, ((SpinnerEditor) spinShine.getEditor()).getTextField());
// Offset
panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset")), "gapleft para");
@ -749,6 +826,7 @@ public class AppearancePanel extends JPanel implements Invalidatable, Invalidati
@Override
public void stateChanged(EventObject e) {
colorButton.setIcon(new ColorIcon(builder.getPaint()));
colorHexField.setText(ColorConversion.toHexColor(builder.getPaint()));
if (lastOpacity != builder.getOpacity()) {
opacityModel.stateChanged(null);
lastOpacity = builder.getOpacity();

View File

@ -27,4 +27,28 @@ public class ColorConversion {
String hexColor = String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue());
return String.format("<font color=\"%s\">%s</font>", hexColor, content);
}
public static String toHexColor(ORColor c) {
if (c == null) {
return null;
}
return String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()).toUpperCase();
}
public static ORColor fromHexColor(String hexColor) {
if (hexColor == null || hexColor.isBlank()) {
return null;
}
if (hexColor.startsWith("#")) {
hexColor = hexColor.substring(1);
}
hexColor = hexColor.trim();
if (hexColor.length() != 6 || hexColor.matches("^#[0-9A-Fa-f]{6}$")) {
throw new IllegalArgumentException("Invalid hex color: " + hexColor);
}
int red = Integer.parseInt(hexColor.substring(0, 2), 16);
int green = Integer.parseInt(hexColor.substring(2, 4), 16);
int blue = Integer.parseInt(hexColor.substring(4, 6), 16);
return new ORColor(red, green, blue);
}
}