Merge pull request #2545 from SiboVG/issue-2224
[#2224] Add hex color input field in appearance panel
This commit is contained in:
commit
e286eea144
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user