package net.sf.openrocket.gui.configdialog;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.EventObject;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.appearance.Appearance;
import net.sf.openrocket.appearance.AppearanceBuilder;
import net.sf.openrocket.appearance.Decal.EdgeMode;
import net.sf.openrocket.appearance.DecalImage;
import net.sf.openrocket.appearance.defaults.DefaultAppearance;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.SpinnerEditor;
import net.sf.openrocket.gui.adaptors.BooleanModel;
import net.sf.openrocket.gui.adaptors.DecalModel;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.adaptors.EnumModel;
import net.sf.openrocket.gui.components.BasicSlider;
import net.sf.openrocket.gui.components.ColorIcon;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.util.ColorConversion;
import net.sf.openrocket.gui.util.EditDecalHelper;
import net.sf.openrocket.gui.util.EditDecalHelper.EditDecalHelperException;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.GeneralUnit;
import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.LineStyle;
import net.sf.openrocket.util.StateChangeListener;
public class AppearancePanel extends JPanel {
private static final Translator trans = Application.getTranslator();
private EditDecalHelper editDecalHelper = Application.getInjector()
.getInstance(EditDecalHelper.class);
private AppearanceBuilder ab;
// We hang on to the user selected appearance when switching to default
// appearance.
// this appearance is restored if the user unchecks the "default" button.
private Appearance previousUserSelectedAppearance = null;
// We cache the default appearance for this component to make switching
// faster.
private Appearance defaultAppearance = null;
/**
* A non-unit that adjusts by a small amount, suitable for values that are
* on the 0-1 scale
*/
private final static UnitGroup TEXTURE_UNIT = new UnitGroup();
static {
Unit no_unit = new GeneralUnit(1, "", 2) {
@Override
public double getNextValue(double value) {
return value + .1;
}
@Override
public double getPreviousValue(double value) {
return value - .1;
}
};
TEXTURE_UNIT.addUnit(no_unit);
}
private static final JColorChooser colorChooser = new JColorChooser();
private class ColorActionListener implements ActionListener {
private final String valueName;
private final Object o;
ColorActionListener(final Object o, final String valueName) {
this.valueName = valueName;
this.o = o;
}
@Override
public void actionPerformed(ActionEvent colorClickEvent) {
try {
final Method getMethod = o.getClass().getMethod(
"get" + valueName);
final Method setMethod = o.getClass().getMethod(
"set" + valueName, net.sf.openrocket.util.Color.class);
net.sf.openrocket.util.Color c = (net.sf.openrocket.util.Color) getMethod
.invoke(o);
Color awtColor = ColorConversion.toAwtColor(c);
colorChooser.setColor(awtColor);
JDialog d = JColorChooser.createDialog(AppearancePanel.this,
trans.get("RocketCompCfg.lbl.Choosecolor"), true,
colorChooser, new ActionListener() {
@Override
public void actionPerformed(ActionEvent okEvent) {
Color selected = colorChooser.getColor();
if (selected == null)
return;
try {
setMethod.invoke(o, ColorConversion
.fromAwtColor(selected));
} catch (Throwable e1) {
Application.getExceptionHandler()
.handleErrorCondition(e1);
}
}
}, null);
d.setVisible(true);
} catch (Throwable e1) {
Application.getExceptionHandler().handleErrorCondition(e1);
}
}
}
public AppearancePanel(final OpenRocketDocument document,
final RocketComponent c) {
super(new MigLayout("fill", "[150][grow][150][grow]"));
previousUserSelectedAppearance = c.getAppearance();
defaultAppearance = DefaultAppearance.getDefaultAppearance(c);
if (previousUserSelectedAppearance == null) {
previousUserSelectedAppearance = new AppearanceBuilder()
.getAppearance();
ab = new AppearanceBuilder(defaultAppearance);
} else {
ab = new AppearanceBuilder(previousUserSelectedAppearance);
}
net.sf.openrocket.util.Color figureColor = c.getColor();
if (figureColor == null) {
figureColor = Application.getPreferences().getDefaultColor(
c.getClass());
}
final JButton figureColorButton = new JButton(
new ColorIcon(figureColor));
final JButton colorButton = new JButton(new ColorIcon(ab.getPaint()));
final DecalModel decalModel = new DecalModel(this, document, ab);
final JComboBox textureDropDown = new JComboBox(decalModel);
ab.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
figureColorButton.setIcon(new ColorIcon(c.getColor()));
colorButton.setIcon(new ColorIcon(ab.getPaint()));
c.setAppearance(ab.getAppearance());
decalModel.refresh();
}
});
c.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
net.sf.openrocket.util.Color col = c.getColor();
if (col == null) {
col = Application.getPreferences().getDefaultColor(
c.getClass());
}
figureColorButton.setIcon(new ColorIcon(col));
}
});
figureColorButton
.addActionListener(new ColorActionListener(c, "Color"));
colorButton.addActionListener(new ColorActionListener(ab, "Paint"));
BooleanModel mDefault = new BooleanModel(c.getAppearance() == null);
BooleanModel fDefault = new BooleanModel(c.getColor() == null);
{// Style Header Row
final JCheckBox colorDefault = new JCheckBox(fDefault);
colorDefault.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (colorDefault.isSelected()) {
c.setColor(null);
c.setLineStyle(null);
} else {
c.setColor(((SwingPreferences) Application
.getPreferences()).getDefaultColor(c.getClass()));
c.setLineStyle(((SwingPreferences) Application
.getPreferences()).getDefaultLineStyle(c
.getClass()));
}
}
});
colorDefault.setText(trans
.get("RocketCompCfg.checkbox.Usedefaultcolor"));
add(new StyledLabel(trans.get("RocketCompCfg.lbl.Figurestyle"),
Style.BOLD));
add(colorDefault);
JButton button = new JButton(
trans.get("RocketCompCfg.but.Saveasdefstyle"));
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (c.getColor() != null) {
((SwingPreferences) Application.getPreferences())
.setDefaultColor(c.getClass(), c.getColor());
c.setColor(null);
}
if (c.getLineStyle() != null) {
Application.getPreferences().setDefaultLineStyle(
c.getClass(), c.getLineStyle());
c.setLineStyle(null);
}
}
});
fDefault.addEnableComponent(button, false);
add(button, "span 2, align right, wrap");
}
{// Figure Color
add(new JLabel(trans.get("RocketCompCfg.lbl.Componentcolor")));
fDefault.addEnableComponent(figureColorButton, false);
add(figureColorButton);
}
{// Line Style
add(new JLabel(trans.get("RocketCompCfg.lbl.Complinestyle")));
LineStyle[] list = new LineStyle[LineStyle.values().length + 1];
System.arraycopy(LineStyle.values(), 0, list, 1,
LineStyle.values().length);
JComboBox combo = new JComboBox(new EnumModel<LineStyle>(c,
"LineStyle",
// // Default style
list, trans.get("LineStyle.Defaultstyle")));
fDefault.addEnableComponent(combo, false);
add(combo, "wrap");
}
add(new JSeparator(SwingConstants.HORIZONTAL), "span, wrap, growx");
{// Texture Header Row
add(new StyledLabel(trans.get("AppearanceCfg.lbl.Appearance"),
Style.BOLD));
final JCheckBox materialDefault = new JCheckBox(mDefault);
materialDefault.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (materialDefault.isSelected()) {
previousUserSelectedAppearance = (ab == null) ? null
: ab.getAppearance();
ab.setAppearance(defaultAppearance);
} else {
ab.setAppearance(previousUserSelectedAppearance);
}
}
});
materialDefault.setText(trans.get("AppearanceCfg.lbl.Usedefault"));
add(materialDefault, "wrap");
}
{// Texture File
add(new JLabel(trans.get("AppearanceCfg.lbl.Texture")));
JPanel p = new JPanel(new MigLayout("fill, ins 0", "[grow][]"));
mDefault.addEnableComponent(textureDropDown, false);
p.add(textureDropDown, "grow");
add(p, "span 3, growx, wrap");
final JButton editBtn = new JButton(
trans.get("AppearanceCfg.but.edit"));
editBtn.setEnabled(ab.getImage() != null);
// Enable the editBtn only when the appearance builder has an Image
// assigned to it.
ab.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
editBtn.setEnabled(ab.getImage() != null);
}
});
editBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
DecalImage newImage = editDecalHelper.editDecal(
SwingUtilities
.getWindowAncestor(AppearancePanel.this),
document, c, ab.getImage());
ab.setImage(newImage);
} catch (EditDecalHelperException ex) {
JOptionPane.showMessageDialog(AppearancePanel.this,
ex.getMessage(), "", JOptionPane.ERROR_MESSAGE);
}
}
});
p.add(editBtn);
}
{ // Color
add(new JLabel(trans.get("AppearanceCfg.lbl.color.Color")));
mDefault.addEnableComponent(colorButton, false);
add(colorButton);
}
{ // Scale
add(new JLabel(trans.get("AppearanceCfg.lbl.texture.scale")));
add(new JLabel("x:"), "split 4");
JSpinner scaleU = new JSpinner(new DoubleModel(ab, "ScaleX",
TEXTURE_UNIT).getSpinnerModel());
scaleU.setEditor(new SpinnerEditor(scaleU));
mDefault.addEnableComponent(scaleU, false);
add(scaleU, "w 40");
add(new JLabel("y:"));
JSpinner scaleV = new JSpinner(new DoubleModel(ab, "ScaleY",
TEXTURE_UNIT).getSpinnerModel());
scaleV.setEditor(new SpinnerEditor(scaleV));
mDefault.addEnableComponent(scaleV, false);
add(scaleV, "wrap, w 40");
}
{// Shine
add(new JLabel(trans.get("AppearanceCfg.lbl.shine")));
DoubleModel shineModel = new DoubleModel(ab, "Shine",
UnitGroup.UNITS_RELATIVE);
JSpinner spin = new JSpinner(shineModel.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
JSlider slide = new JSlider(shineModel.getSliderModel(0, 1));
UnitSelector unit = new UnitSelector(shineModel);
mDefault.addEnableComponent(slide, false);
mDefault.addEnableComponent(spin, false);
mDefault.addEnableComponent(unit, false);
add(spin, "split 3, w 50");
add(unit);
add(slide, "w 50");
}
{ // Offset
add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset")));
add(new JLabel("x:"), "split 4");
JSpinner offsetU = new JSpinner(new DoubleModel(ab, "OffsetU",
TEXTURE_UNIT).getSpinnerModel());
offsetU.setEditor(new SpinnerEditor(offsetU));
mDefault.addEnableComponent(offsetU, false);
add(offsetU, "w 40");
add(new JLabel("y:"));
JSpinner offsetV = new JSpinner(new DoubleModel(ab, "OffsetV",
TEXTURE_UNIT).getSpinnerModel());
offsetV.setEditor(new SpinnerEditor(offsetV));
mDefault.addEnableComponent(offsetV, false);
add(offsetV, "wrap, w 40");
}
{ // Repeat
add(new JLabel(trans.get("AppearanceCfg.lbl.texture.repeat")));
EdgeMode[] list = new EdgeMode[EdgeMode.values().length];
System.arraycopy(EdgeMode.values(), 0, list, 0,
EdgeMode.values().length);
JComboBox combo = new JComboBox(new EnumModel<EdgeMode>(ab,
"EdgeMode", list));
mDefault.addEnableComponent(combo, false);
add(combo);
}
{ // Rotation
add(new JLabel(trans.get("AppearanceCfg.lbl.texture.rotation")));
DoubleModel rotationModel = new DoubleModel(ab, "Rotation",
UnitGroup.UNITS_ANGLE);
JSpinner rotation = new JSpinner(rotationModel.getSpinnerModel());
rotation.setEditor(new SpinnerEditor(rotation));
mDefault.addEnableComponent(rotation, false);
add(rotation, "split 3, w 50");
add(new UnitSelector(rotationModel));
BasicSlider bs = new BasicSlider(rotationModel.getSliderModel(
-Math.PI, Math.PI));
mDefault.addEnableComponent(bs, false);
add(bs, "w 50, wrap");
}
}
}