From fb5909afa295a40d14ad1469e2da11afa271f5ac Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Wed, 23 Jun 2021 14:39:25 +0200 Subject: [PATCH 1/4] Fix inside color tube --- .../net/sf/openrocket/gui/figure3d/RealisticRenderer.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java index d3c94b006..e584db68f 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java @@ -91,12 +91,7 @@ public class RealisticRenderer extends RocketRenderer { @Override public void renderComponent(final GL2 gl, Geometry geom, final float alpha) { Appearance app = getAppearance( geom.getComponent() ); - if (app.getPaint().getAlpha()<255){ - // if transparent, draw inside the same as the outside so we dont get a cardboard interior on a clear payload bay - render(gl, geom, Surface.INSIDE, app, true, alpha); - }else{ - render(gl, geom, Surface.INSIDE, DefaultAppearance.getDefaultAppearance(geom.getComponent()), true, 1.0f); - } + render(gl, geom, Surface.INSIDE, app, true, alpha); render(gl, geom, Surface.OUTSIDE, app, true, alpha); render(gl, geom, Surface.EDGES, app, false, alpha); } From 5fa3b2cd3a79a4409214a2707d0abfda34e1215e Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Mon, 28 Jun 2021 18:40:19 +0200 Subject: [PATCH 2/4] Add custom outside and inside appearance --- core/resources/l10n/messages.properties | 6 + .../openrocket/rocketcomponent/BodyTube.java | 62 ++- .../rocketcomponent/InsideColorComponent.java | 68 ++++ .../openrocket/rocketcomponent/LaunchLug.java | 57 ++- .../openrocket/rocketcomponent/NoseCone.java | 59 ++- .../rocketcomponent/Transition.java | 55 ++- .../rocketcomponent/TubeFinSet.java | 60 ++- .../gui/configdialog/AppearancePanel.java | 381 +++++++++++------- .../gui/figure3d/RealisticRenderer.java | 34 +- 9 files changed, 613 insertions(+), 169 deletions(-) create mode 100644 core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index f84c5e7b3..e4d779394 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -809,6 +809,10 @@ AppearanceCfg.lbl.texture.offset = Offset: AppearanceCfg.lbl.texture.center = Center: AppearanceCfg.lbl.texture.rotation = Rotation: AppearanceCfg.lbl.texture.repeat = Repeat: +AppearanceCfg.lbl.InsideSameAsOutside = Same as outside +AppearanceCfg.lbl.ttip.InsideSameAsOutside = Use the same appearance for the inside as for the outside +AppearanceCfg.lbl.EdgesSameAsInside = Use inside appearance for edges +AppearanceCfg.lbl.ttip.EdgesSameAsInside = Use the inside appearance (checked) or outside appearance (unchecked) for the edges ! Texture Wrap Modes TextureWrap.Repeat = Repeat @@ -871,6 +875,8 @@ RocketCompCfg.border.Foreshoulder = Fore shoulder !RocketCompCfg.lbl.Length = Length: RocketCompCfg.lbl.InstanceCount = Instance Count RocketCompCfg.lbl.InstanceSeparation = Instance Separation +RocketCompCfg.tab.Outside = Outside +RocketCompCfg.tab.Inside = Inside ! BulkheadConfig BulkheadCfg.tab.Diameter = Diameter: diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index 4428dfac4..837dd5cf0 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -1,19 +1,17 @@ package net.sf.openrocket.rocketcomponent; -import java.util.ArrayList; -import java.util.Collection; +import java.util.EventObject; import java.util.Iterator; +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.motor.MotorConfigurationSet; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.BoundingBox; -import net.sf.openrocket.util.BugException; -import net.sf.openrocket.util.Coordinate; -import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.*; /** @@ -22,7 +20,7 @@ import net.sf.openrocket.util.MathUtil; * @author Sampo Niskanen */ -public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMount, Coaxial { +public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMount, Coaxial, InsideColorComponent { private static final Translator trans = Application.getTranslator(); private double outerRadius = 0; @@ -33,6 +31,11 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou private boolean isActingMount = false; private MotorConfigurationSet motors; + + // Settings for inside/edge appearance + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; public BodyTube() { this(8 * DEFAULT_RADIUS, DEFAULT_RADIUS); @@ -455,4 +458,49 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou public ClusterConfiguration getClusterConfiguration() { return ClusterConfiguration.SINGLE; } + + @Override + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + @Override + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + @Override + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + @Override + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + @Override + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + @Override + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java new file mode 100644 index 000000000..3605cc322 --- /dev/null +++ b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java @@ -0,0 +1,68 @@ +package net.sf.openrocket.rocketcomponent; + +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; +import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.position.AxialMethod; +import net.sf.openrocket.util.StateChangeListener; + +import java.util.EventObject; + +/** + * This is a marker interface which, if applied to a component, will mark that component as having the possibility to + * have a different inside and outside color. This will cause the appearance editor of that component to have a separate + * section for the inside and outside color and will consequently also render the inside and outside of that component + * (in a 3D figure) differently. + * + * @author Sibo Van Gool + */ +public interface InsideColorComponent { + /** + * Get the realistic inside appearance of this component. + * null = use the default for this material + * + * @return The component's realistic inner appearance, or null + */ + Appearance getInsideAppearance(); + + /** + * Set the realistic inside appearance of this component. + * Use null for default. + * + * @param appearance the inner appearance to be set + */ + void setInsideAppearance(Appearance appearance); + + /** + * Checks whether the component uses for the edges the same appearance as the inside (return true) or as the + * outside (return false) + * + * @return true if edges should use the same appearance as the inside, + * false if edges should use the same appearance as the outside + */ + boolean isEdgesSameAsInside(); + + /** + * Sets the new state for edgesUseInsideAppearance to newState + * + * @param newState new edgesUseInsideAppearance value + */ + void setEdgesSameAsInside(boolean newState); + + /** + * Checks whether the component should use the same appearance for the inside as the outside (return true) or as the + * outside (return false) + * + * @return true if edges should use the same appearance as the inside, + * false if edges should use the same appearance as the outside + */ + boolean isInsideSameAsOutside(); + + /** + * Sets the new state for insideSameAsOutside to newState + * + * @param newState new edgesUseInsideAppearance value + */ + void setInsideSameAsOutside(boolean newState); +} diff --git a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java index 92ef86e72..cbd2bd28f 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java +++ b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java @@ -2,7 +2,10 @@ package net.sf.openrocket.rocketcomponent; import java.util.ArrayList; import java.util.Collection; +import java.util.EventObject; +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset.Type; @@ -11,10 +14,10 @@ import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.StateChangeListener; - -public class LaunchLug extends ExternalComponent implements AnglePositionable, BoxBounded, Coaxial, LineInstanceable { +public class LaunchLug extends ExternalComponent implements AnglePositionable, BoxBounded, Coaxial, LineInstanceable, InsideColorComponent { private static final Translator trans = Application.getTranslator(); @@ -26,6 +29,11 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, B private int instanceCount = 1; private double instanceSeparation = 0; // front-front along the positive rocket axis. i.e. [1,0,0]; + + // Settings for inside/edge appearance + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; public LaunchLug() { super(AxialMethod.MIDDLE); @@ -279,4 +287,49 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, B public void setAngleMethod(AngleMethod newMethod) { // no-op } + + @Override + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + @Override + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + @Override + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + @Override + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + @Override + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + @Override + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java index f58f40bd2..3ca204336 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java +++ b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java @@ -1,9 +1,14 @@ package net.sf.openrocket.rocketcomponent; +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset.Type; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.util.StateChangeListener; + +import java.util.EventObject; /** * Rocket nose cones of various types. Implemented as a transition with the @@ -12,9 +17,13 @@ import net.sf.openrocket.startup.Application; * @author Sampo Niskanen */ -public class NoseCone extends Transition { +public class NoseCone extends Transition implements InsideColorComponent { private static final Translator trans = Application.getTranslator(); - + + // Settings for inside/edge appearance + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; /********* Constructors **********/ public NoseCone() { @@ -135,5 +144,49 @@ public class NoseCone extends Transition { //// Nose cone return trans.get("NoseCone.NoseCone"); } - + + @Override + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + @Override + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + @Override + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + @Override + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + @Override + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + @Override + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index d89f6de69..1d446a147 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -5,16 +5,20 @@ import static net.sf.openrocket.util.MathUtil.pow2; import static net.sf.openrocket.util.MathUtil.pow3; import java.util.Collection; +import java.util.EventObject; +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset.Type; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.StateChangeListener; -public class Transition extends SymmetricComponent { +public class Transition extends SymmetricComponent implements InsideColorComponent { private static final Translator trans = Application.getTranslator(); private static final double CLIP_PRECISION = 0.0001; @@ -40,6 +44,11 @@ public class Transition extends SymmetricComponent { // Used to cache the clip length private double clipLength = -1; + // Settings for inside/edge appearance + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; + public Transition() { super(); @@ -938,4 +947,48 @@ public class Transition extends SymmetricComponent { } } + @Override + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + @Override + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + @Override + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + @Override + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + @Override + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + @Override + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java index 820e6896d..92aca3409 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -2,8 +2,11 @@ package net.sf.openrocket.rocketcomponent; import java.util.ArrayList; import java.util.Collection; +import java.util.EventObject; import java.util.List; +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset.Type; @@ -12,12 +15,9 @@ import net.sf.openrocket.rocketcomponent.position.AxialMethod; import net.sf.openrocket.rocketcomponent.position.AxialPositionable; import net.sf.openrocket.rocketcomponent.position.RadiusMethod; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.BoundingBox; -import net.sf.openrocket.util.Coordinate; -import net.sf.openrocket.util.MathUtil; -import net.sf.openrocket.util.Transformation; +import net.sf.openrocket.util.*; -public class TubeFinSet extends ExternalComponent implements AxialPositionable, BoxBounded, RingInstanceable { +public class TubeFinSet extends ExternalComponent implements AxialPositionable, BoxBounded, RingInstanceable, InsideColorComponent { private static final Translator trans = Application.getTranslator(); private final static double DEFAULT_RADIUS = 0.025; @@ -27,6 +27,11 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable, protected double thickness = 0.002; private AngleMethod angleMethod = AngleMethod.FIXED; protected RadiusMethod radiusMethod = RadiusMethod.RELATIVE; + + // Settings for inside/edge appearance + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; /** * Rotation angle of the first fin. Zero corresponds to the positive y-axis. @@ -452,5 +457,50 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable, // TODO Auto-generated method stub } + + @Override + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + @Override + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + @Override + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + @Override + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + @Override + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + @Override + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java index b2d00a6b8..22d63fe73 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java @@ -6,19 +6,7 @@ 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 javax.swing.*; import javax.swing.colorchooser.ColorSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -45,6 +33,8 @@ 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.ComponentChangeEvent; +import net.sf.openrocket.rocketcomponent.InsideColorComponent; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.GeneralUnit; @@ -58,15 +48,18 @@ public class AppearancePanel extends JPanel { private static final Translator trans = Application.getTranslator(); - private EditDecalHelper editDecalHelper = Application.getInjector() + final private EditDecalHelper editDecalHelper = Application.getInjector() .getInstance(EditDecalHelper.class); - private AppearanceBuilder ab; + // Outside and inside appearance builder + final private AppearanceBuilder ab; + private AppearanceBuilder insideAb; // 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; + private Appearance previousUserSelectedInsideAppearance = null; // We cache the default appearance for this component to make switching // faster. @@ -105,7 +98,7 @@ public class AppearancePanel extends JPanel { } /** - Changes the color of the selected color to + Changes the color of the selected component to @param color: color to change the component to */ private void changeComponentColor(Color color) { @@ -182,8 +175,9 @@ public class AppearancePanel extends JPanel { final RocketComponent c) { super(new MigLayout("fill", "[150][grow][150][grow]")); - previousUserSelectedAppearance = c.getAppearance(); defaultAppearance = DefaultAppearance.getDefaultAppearance(c); + + previousUserSelectedAppearance = c.getAppearance(); if (previousUserSelectedAppearance == null) { previousUserSelectedAppearance = new AppearanceBuilder() .getAppearance(); @@ -192,6 +186,17 @@ public class AppearancePanel extends JPanel { ab = new AppearanceBuilder(previousUserSelectedAppearance); } + if (c instanceof InsideColorComponent) { + previousUserSelectedInsideAppearance = ((InsideColorComponent) c).getInsideAppearance(); + if (previousUserSelectedInsideAppearance == null) { + previousUserSelectedInsideAppearance = new AppearanceBuilder() + .getAppearance(); + insideAb = new AppearanceBuilder(defaultAppearance); + } else { + insideAb = new AppearanceBuilder(previousUserSelectedInsideAppearance); + } + } + net.sf.openrocket.util.Color figureColor = c.getColor(); if (figureColor == null) { figureColor = Application.getPreferences().getDefaultColor( @@ -200,19 +205,9 @@ public class AppearancePanel extends JPanel { 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(); - } + public void stateChanged(EventObject e) { figureColorButton.setIcon(new ColorIcon(c.getColor())); } }); c.addChangeListener(new StateChangeListener() { @@ -229,9 +224,7 @@ public class AppearancePanel extends JPanel { 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 @@ -285,7 +278,6 @@ public class AppearancePanel extends JPanel { } {// Line Style - add(new JLabel(trans.get("RocketCompCfg.lbl.Complinestyle"))); LineStyle[] list = new LineStyle[LineStyle.values().length + 1]; @@ -304,148 +296,241 @@ public class AppearancePanel extends JPanel { 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() { + // Display a tabbed panel for choosing the outside and inside appearance, if the object is of type InsideColorComponent + if (c instanceof InsideColorComponent) { + JTabbedPane tabbedPane = new JTabbedPane(); + JPanel outsidePanel = new JPanel(new MigLayout("fill", "[150][grow][150][grow]")); + JPanel insidePanel = new JPanel(new MigLayout("fill", "[150][grow][150][grow]")); + + appearanceSection(document, c, false, outsidePanel); + appearanceSection(document, c, true, insidePanel); + + tabbedPane.addTab(trans.get("RocketCompCfg.tab.Outside"), null, outsidePanel, + "Outside Tool Tip"); + tabbedPane.addTab(trans.get("RocketCompCfg.tab.Inside"), null, insidePanel, + "Inside Tool Tip"); + add(tabbedPane, "span 4, growx, wrap"); + + // Checkbox to set edges the same as inside/outside + BooleanModel b = new BooleanModel(((InsideColorComponent) c).isEdgesSameAsInside()); + JCheckBox edges = new JCheckBox(b); + edges.setText(trans.get("AppearanceCfg.lbl.EdgesSameAsInside")); + edges.setToolTipText(trans.get("AppearanceCfg.lbl.ttip.EdgesSameAsInside")); + add(edges, "wrap"); + + edges.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); - } + ((InsideColorComponent) c).setEdgesSameAsInside(edges.isSelected()); + c.fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } }); - materialDefault.setText(trans.get("AppearanceCfg.lbl.Usedefault")); - add(materialDefault, "wrap"); } + else + appearanceSection(document, c, false, this); + } - {// 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); + /** + * + * @param document + * @param c + * @param insideBuilder flag to check whether you are on the inside builder (true) or outside builder + * @param panel + */ + private void appearanceSection(OpenRocketDocument document, RocketComponent c, + boolean insideBuilder, JPanel panel) { + AppearanceBuilder builder; + BooleanModel mDefault; + if (!insideBuilder) { + builder = ab; + mDefault = new BooleanModel(c.getAppearance() == null); + } + else if (c instanceof InsideColorComponent) { + builder = insideAb; + mDefault = new BooleanModel(((InsideColorComponent)c).getInsideAppearance() == null); + } + else return; + + DecalModel decalModel = new DecalModel(panel, document, builder); + JComboBox textureDropDown = new JComboBox(decalModel); + + JButton colorButton = new JButton(new ColorIcon(builder.getPaint())); + + builder.addChangeListener(new StateChangeListener() { + @Override + public void stateChanged(EventObject e) { + colorButton.setIcon(new ColorIcon(builder.getPaint())); + if (!insideBuilder) + c.setAppearance(builder.getAppearance()); + else + ((InsideColorComponent)c).setInsideAppearance(builder.getAppearance()); + decalModel.refresh(); + } + }); + + colorButton.addActionListener(new ColorActionListener(builder, "Paint")); + + // Texture Header Row + panel.add(new StyledLabel(trans.get("AppearanceCfg.lbl.Appearance"), + Style.BOLD)); + JCheckBox materialDefault = new JCheckBox(mDefault); + materialDefault.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (materialDefault.isSelected()) { + if (!insideBuilder) { + previousUserSelectedAppearance = (builder == null) ? null + : builder.getAppearance(); + } + else { + previousUserSelectedInsideAppearance = (builder == null) ? null + : builder.getAppearance(); + } + builder.setAppearance(defaultAppearance); + } else { + if (!insideBuilder) + builder.setAppearance(previousUserSelectedAppearance); + else + builder.setAppearance(previousUserSelectedInsideAppearance); } - }); - editBtn.addActionListener(new ActionListener() { + } + }); + materialDefault.setText(trans.get("AppearanceCfg.lbl.Usedefault")); + if (insideBuilder) + panel.add(materialDefault); + else + panel.add(materialDefault, "wrap"); + // Custom inside color + if (insideBuilder) { + BooleanModel b = new BooleanModel(((InsideColorComponent) c).isInsideSameAsOutside()); + JCheckBox customInside = new JCheckBox(b); + customInside.setText(trans.get("AppearanceCfg.lbl.InsideSameAsOutside")); + customInside.setToolTipText(trans.get("AppearanceCfg.lbl.ttip.InsideSameAsOutside")); + customInside.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); - } + ((InsideColorComponent) c).setInsideSameAsOutside(customInside.isSelected()); + c.fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } - }); - p.add(editBtn); + panel.add(customInside, "wrap"); } - { // Color - add(new JLabel(trans.get("AppearanceCfg.lbl.color.Color"))); - mDefault.addEnableComponent(colorButton, false); - add(colorButton); - } + // Texture File + panel.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"); + panel.add(p, "span 3, growx, wrap"); + JButton editBtn = new JButton( + trans.get("AppearanceCfg.but.edit")); + editBtn.setEnabled(builder.getImage() != null); + // Enable the editBtn only when the appearance builder has an Image + // assigned to it. + builder.addChangeListener(new StateChangeListener() { + @Override + public void stateChanged(EventObject e) { + editBtn.setEnabled(builder.getImage() != null); + } + }); - { // Scale - add(new JLabel(trans.get("AppearanceCfg.lbl.texture.scale"))); + editBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + DecalImage newImage = editDecalHelper.editDecal( + SwingUtilities + .getWindowAncestor(panel), + document, c, builder.getImage()); + builder.setImage(newImage); + } catch (EditDecalHelperException ex) { + JOptionPane.showMessageDialog(panel, + ex.getMessage(), "", JOptionPane.ERROR_MESSAGE); + } + } - 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"); + }); + p.add(editBtn); - 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"); - } + // Color + panel.add(new JLabel(trans.get("AppearanceCfg.lbl.color.Color"))); + mDefault.addEnableComponent(colorButton, false); + panel.add(colorButton); - {// 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); + // Scale + panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.scale"))); - mDefault.addEnableComponent(slide, false); - mDefault.addEnableComponent(spin, false); - mDefault.addEnableComponent(unit, false); + panel.add(new JLabel("x:"), "split 4"); + JSpinner scaleU = new JSpinner(new DoubleModel(builder, "ScaleX", + TEXTURE_UNIT).getSpinnerModel()); + scaleU.setEditor(new SpinnerEditor(scaleU)); + mDefault.addEnableComponent(scaleU, false); + panel.add(scaleU, "w 40"); - add(spin, "split 3, w 50"); - add(unit); - add(slide, "w 50"); - } + panel.add(new JLabel("y:")); + JSpinner scaleV = new JSpinner(new DoubleModel(builder, "ScaleY", + TEXTURE_UNIT).getSpinnerModel()); + scaleV.setEditor(new SpinnerEditor(scaleV)); + mDefault.addEnableComponent(scaleV, false); + panel.add(scaleV, "wrap, w 40"); - { // Offset - add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset"))); + // Shine + panel.add(new JLabel(trans.get("AppearanceCfg.lbl.shine"))); + DoubleModel shineModel = new DoubleModel(builder, "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); - 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"); + mDefault.addEnableComponent(slide, false); + mDefault.addEnableComponent(spin, false); + mDefault.addEnableComponent(unit, false); - 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"); - } + panel.add(spin, "split 3, w 50"); + panel.add(unit); + panel.add(slide, "w 50"); - { // 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(ab, - "EdgeMode", list)); - mDefault.addEnableComponent(combo, false); - add(combo); - } + // Offset + panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset"))); - { // 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"); - } + panel.add(new JLabel("x:"), "split 4"); + JSpinner offsetU = new JSpinner(new DoubleModel(builder, "OffsetU", + TEXTURE_UNIT).getSpinnerModel()); + offsetU.setEditor(new SpinnerEditor(offsetU)); + mDefault.addEnableComponent(offsetU, false); + panel.add(offsetU, "w 40"); + panel.add(new JLabel("y:")); + JSpinner offsetV = new JSpinner(new DoubleModel(builder, "OffsetV", + TEXTURE_UNIT).getSpinnerModel()); + offsetV.setEditor(new SpinnerEditor(offsetV)); + mDefault.addEnableComponent(offsetV, false); + panel.add(offsetV, "wrap, w 40"); + + // Repeat + panel.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(builder, + "EdgeMode", list)); + mDefault.addEnableComponent(combo, false); + panel.add(combo); + + // Rotation + panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.rotation"))); + DoubleModel rotationModel = new DoubleModel(builder, "Rotation", + UnitGroup.UNITS_ANGLE); + JSpinner rotation = new JSpinner(rotationModel.getSpinnerModel()); + rotation.setEditor(new SpinnerEditor(rotation)); + mDefault.addEnableComponent(rotation, false); + panel.add(rotation, "split 3, w 50"); + panel.add(new UnitSelector(rotationModel)); + BasicSlider bs = new BasicSlider(rotationModel.getSliderModel( + -Math.PI, Math.PI)); + mDefault.addEnableComponent(bs, false); + panel.add(bs, "w 50, wrap"); } } diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java index e584db68f..e799f886c 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java @@ -14,6 +14,7 @@ import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.figure3d.geometry.Geometry; import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface; import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.rocketcomponent.InsideColorComponent; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.Color; @@ -90,10 +91,24 @@ public class RealisticRenderer extends RocketRenderer { @Override public void renderComponent(final GL2 gl, Geometry geom, final float alpha) { - Appearance app = getAppearance( geom.getComponent() ); - render(gl, geom, Surface.INSIDE, app, true, alpha); + RocketComponent c = geom.getComponent(); + Appearance app = getAppearance(c); + if (c instanceof InsideColorComponent) { + Appearance innerApp = getInsideAppearance(c); + if (((InsideColorComponent) c).isInsideSameAsOutside()) innerApp = app; + + render(gl, geom, Surface.INSIDE, innerApp, true, alpha); + if (((InsideColorComponent) c).isEdgesSameAsInside()) + render(gl, geom, Surface.EDGES, innerApp, false, alpha); + else + render(gl, geom, Surface.EDGES, app, false, alpha); + } + else { + render(gl, geom, Surface.INSIDE, app, true, alpha); + render(gl, geom, Surface.EDGES, app, false, alpha); + } render(gl, geom, Surface.OUTSIDE, app, true, alpha); - render(gl, geom, Surface.EDGES, app, false, alpha); + } protected float[] convertColor(Appearance a, float alpha) { @@ -190,6 +205,19 @@ public class RealisticRenderer extends RocketRenderer { } return ret; } + + protected Appearance getInsideAppearance(RocketComponent c) { + if (c instanceof InsideColorComponent) { + Appearance ret = ((InsideColorComponent)c).getInsideAppearance(); + if (ret == null) { + ret = DefaultAppearance.getDefaultAppearance(c); + } + return ret; + } + else { + return DefaultAppearance.getDefaultAppearance(c); + } + } private int toEdgeMode(Decal.EdgeMode m) { switch (m) { From 46d9841947848640093bda672c295c110d1fc0dd Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Wed, 30 Jun 2021 00:11:21 +0200 Subject: [PATCH 3/4] Fix saving inner appearance --- .../document/OpenRocketDocument.java | 35 ++++++++-- .../openrocket/file/GeneralRocketSaver.java | 26 ++++--- .../openrocket/importt/AppearanceHandler.java | 18 +++-- .../importt/ComponentParameterHandler.java | 7 +- .../importt/InsideAppearanceHandler.java | 45 +++++++++++++ .../savers/RocketComponentSaver.java | 67 ++++++++++--------- .../gui/configdialog/AppearancePanel.java | 2 +- .../openrocket/gui/util/EditDecalHelper.java | 25 ++++++- 8 files changed, 166 insertions(+), 59 deletions(-) create mode 100644 core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java diff --git a/core/src/net/sf/openrocket/document/OpenRocketDocument.java b/core/src/net/sf/openrocket/document/OpenRocketDocument.java index 8efe1460e..c5cdb94cc 100644 --- a/core/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/core/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -9,6 +9,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import net.sf.openrocket.rocketcomponent.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,12 +20,6 @@ import net.sf.openrocket.document.events.DocumentChangeEvent; import net.sf.openrocket.document.events.DocumentChangeListener; import net.sf.openrocket.document.events.SimulationChangeEvent; import net.sf.openrocket.logging.Markers; -import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; -import net.sf.openrocket.rocketcomponent.ComponentChangeListener; -import net.sf.openrocket.rocketcomponent.FlightConfiguration; -import net.sf.openrocket.rocketcomponent.FlightConfigurationId; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.customexpression.CustomExpression; import net.sf.openrocket.simulation.extension.SimulationExtension; @@ -259,7 +254,10 @@ public class OpenRocketDocument implements ComponentChangeListener { Iterator it = rocket.iterator(); while (it.hasNext()) { - if(hasDecal(it.next(),img)) + RocketComponent c = it.next(); + if(hasDecal(c ,img)) + count++; + else if (hasDecalInside(c, img)) count++; } return count; @@ -284,6 +282,29 @@ public class OpenRocketDocument implements ComponentChangeListener { return true; return false; } + + //TODO: LOW: move this method to rocketComponent, Appearance and decal + //I see 3 layers of object accessed, seems unsafe + /** + * checks if a rocket component has the given inside decalImage + * @param comp the RocketComponent to be searched + * @param img the DecalImage to be checked + * @return if the comp has img + */ + private boolean hasDecalInside(RocketComponent comp, DecalImage img) { + if (comp instanceof InsideColorComponent) { + Appearance a = ((InsideColorComponent)comp).getInsideAppearance(); + if (a == null) + return false; + Decal d = a.getTexture(); + if (d == null) + return false; + if (img.equals(d.getImage())) + return true; + return false; + } + return false; + } /** * gets a unique identification for the given decal diff --git a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java index 877435ab2..7e1a1827c 100644 --- a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java +++ b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java @@ -20,6 +20,7 @@ import net.sf.openrocket.document.StorageOptions; import net.sf.openrocket.document.StorageOptions.FileType; import net.sf.openrocket.file.openrocket.OpenRocketSaver; import net.sf.openrocket.file.rocksim.export.RocksimSaver; +import net.sf.openrocket.rocketcomponent.InsideColorComponent; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.MathUtil; @@ -84,7 +85,7 @@ public class GeneralRocketSaver { * * @param dest the destination stream. * @param doc the document to save. - * @param options the storage options. + * @param opts the storage options. * @param progress a SavingProgress object used to provide progress information * @throws IOException in case of an I/O error. */ @@ -159,17 +160,22 @@ public class GeneralRocketSaver { // Look for all decals used in the rocket. for (RocketComponent c : document.getRocket()) { - if (c.getAppearance() == null) { - continue; - } Appearance ap = c.getAppearance(); - if (ap.getTexture() == null) { - continue; + Appearance ap_in = null; + if (c instanceof InsideColorComponent) + ap_in = ((InsideColorComponent)c).getInsideAppearance(); + + if ((ap == null) && (ap_in == null)) continue; + if (ap != null) { + Decal decal = ap.getTexture(); + if (decal != null) + usedDecals.add(decal.getImage()); + } + if (ap_in != null) { + Decal decal = ap_in.getTexture(); + if (decal != null) + usedDecals.add(decal.getImage()); } - - Decal decal = ap.getTexture(); - - usedDecals.add(decal.getImage()); } saveAllPartsZipFile(output, document, options, usedDecals); diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/AppearanceHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/AppearanceHandler.java index b59cea9cd..4d7445d14 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/AppearanceHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/AppearanceHandler.java @@ -16,11 +16,11 @@ import net.sf.openrocket.util.Color; import org.xml.sax.SAXException; class AppearanceHandler extends AbstractElementHandler { - private final DocumentLoadingContext context; - private final RocketComponent component; - - private final AppearanceBuilder builder = new AppearanceBuilder(); - private boolean isInDecal = false; + protected final DocumentLoadingContext context; + protected final RocketComponent component; + + protected final AppearanceBuilder builder = new AppearanceBuilder(); + protected boolean isInDecal = false; public AppearanceHandler(RocketComponent component, DocumentLoadingContext context) { this.context = context; @@ -44,7 +44,7 @@ class AppearanceHandler extends AbstractElementHandler { } return PlainTextHandler.INSTANCE; } - + @Override public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { if ("paint".equals(element)) { @@ -99,8 +99,12 @@ class AppearanceHandler extends AbstractElementHandler { isInDecal = false; return; } - component.setAppearance(builder.getAppearance()); + setAppearance(); super.endHandler(element, attributes, content, warnings); } + + protected void setAppearance() { + component.setAppearance(builder.getAppearance()); + } } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/ComponentParameterHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/ComponentParameterHandler.java index 7bc42fe54..89bb2fd6d 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/ComponentParameterHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/ComponentParameterHandler.java @@ -40,6 +40,9 @@ class ComponentParameterHandler extends AbstractElementHandler { if ( element.equals("appearance")) { return new AppearanceHandler(component,context); } + if (element.equals("inside-appearance")) { + return new InsideAppearanceHandler(component, context); + } if (element.equals("motormount")) { if (!(component instanceof MotorMount)) { warnings.add(Warning.fromString("Illegal component defined as motor mount.")); @@ -92,8 +95,8 @@ class ComponentParameterHandler extends AbstractElementHandler { if (element.equals("subcomponents") || element.equals("motormount") || element.equals("finpoints") || element.equals("motorconfiguration") || - element.equals("appearance") || element.equals("deploymentconfiguration") || - element.equals("separationconfiguration")) { + element.equals("appearance") || element.equals("inside-appearance") || + element.equals("deploymentconfiguration") || element.equals("separationconfiguration")) { return; } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java new file mode 100644 index 000000000..16c3e6753 --- /dev/null +++ b/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java @@ -0,0 +1,45 @@ +package net.sf.openrocket.file.openrocket.importt; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.appearance.AppearanceBuilder; +import net.sf.openrocket.appearance.Decal; +import net.sf.openrocket.document.Attachment; +import net.sf.openrocket.file.DocumentLoadingContext; +import net.sf.openrocket.file.simplesax.AbstractElementHandler; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.rocketcomponent.InsideColorComponent; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +public class InsideAppearanceHandler extends AppearanceHandler { + public InsideAppearanceHandler(RocketComponent component, DocumentLoadingContext context) { + super(component, context); + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + if ("edgesSameAsInside".equals(element)) { + boolean edgesSameAsInside = Boolean.parseBoolean(content); + if (component instanceof InsideColorComponent) + ((InsideColorComponent)component).setEdgesSameAsInside(edgesSameAsInside); + return; + } + if ("insideSameAsOutside".equals(element)) { + boolean insideSameAsOutside = Boolean.parseBoolean(content); + if (component instanceof InsideColorComponent) + ((InsideColorComponent)component).setInsideSameAsOutside(insideSameAsOutside); + return; + } + + super.closeElement(element, attributes, content, warnings); + } + + @Override + protected void setAppearance() { + if ((component instanceof InsideColorComponent)) + ((InsideColorComponent)component).setInsideAppearance(builder.getAppearance()); + } +} diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java index 293550cb6..29664b387 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java @@ -15,14 +15,7 @@ import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.preset.ComponentPreset; -import net.sf.openrocket.rocketcomponent.Clusterable; -import net.sf.openrocket.rocketcomponent.ComponentAssembly; -import net.sf.openrocket.rocketcomponent.FlightConfigurationId; -import net.sf.openrocket.rocketcomponent.Instanceable; -import net.sf.openrocket.rocketcomponent.LineInstanceable; -import net.sf.openrocket.rocketcomponent.MotorMount; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.*; import net.sf.openrocket.rocketcomponent.position.AnglePositionable; import net.sf.openrocket.rocketcomponent.position.AxialMethod; import net.sf.openrocket.rocketcomponent.position.RadiusPositionable; @@ -49,29 +42,26 @@ public class RocketComponentSaver { "\" manufacturer=\"" + preset.getManufacturer().getSimpleName() + "\" partno=\"" + preset.getPartNo() + "\" digest=\"" + preset.getDigest() + "\"/>"); } - + + // Save outside appearance Appearance ap = c.getAppearance(); if (ap != null) { elements.add(""); - Color paint = ap.getPaint(); - emitColor("paint", elements, paint); - elements.add("" + ap.getShine() + ""); - Decal decal = ap.getTexture(); - if (decal != null) { - String name = decal.getImage().getName(); - double rotation = decal.getRotation(); - EdgeMode edgeMode = decal.getEdgeMode(); - elements.add(""); - Coordinate center = decal.getCenter(); - elements.add("
"); - Coordinate offset = decal.getOffset(); - elements.add(""); - Coordinate scale = decal.getScale(); - elements.add(""); - elements.add(""); - } + buildAppearanceElements(elements, ap); elements.add(""); } + + // Save inside appearance + if (c instanceof InsideColorComponent) { + Appearance ap_in = ((InsideColorComponent)c).getInsideAppearance(); + if (ap_in != null) { + elements.add(""); + elements.add("" + ((InsideColorComponent) c).isEdgesSameAsInside() + ""); + elements.add("" + ((InsideColorComponent) c).isInsideSameAsOutside() + ""); + buildAppearanceElements(elements, ap_in); + elements.add(""); + } + } // Save color and line style if significant if (!(c instanceof Rocket || c instanceof ComponentAssembly)) { @@ -147,10 +137,27 @@ public class RocketComponentSaver { } } - - - - + + private void buildAppearanceElements(List elements, Appearance a) { + Color paint = a.getPaint(); + emitColor("paint", elements, paint); + elements.add("" + a.getShine() + ""); + Decal decal = a.getTexture(); + if (decal != null) { + String name = decal.getImage().getName(); + double rotation = decal.getRotation(); + EdgeMode edgeMode = decal.getEdgeMode(); + elements.add(""); + Coordinate center = decal.getCenter(); + elements.add("
"); + Coordinate offset = decal.getOffset(); + elements.add(""); + Coordinate scale = decal.getScale(); + elements.add(""); + elements.add(""); + } + } + protected final String materialParam(Material mat) { return materialParam("material", mat); } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java index 22d63fe73..9fb0f9fff 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java @@ -442,7 +442,7 @@ public class AppearancePanel extends JPanel { DecalImage newImage = editDecalHelper.editDecal( SwingUtilities .getWindowAncestor(panel), - document, c, builder.getImage()); + document, c, builder.getImage(), insideBuilder); builder.setImage(newImage); } catch (EditDecalHelperException ex) { JOptionPane.showMessageDialog(panel, diff --git a/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java b/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java index 864f3b2a1..b6ed0c1a5 100644 --- a/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java +++ b/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java @@ -16,6 +16,7 @@ import net.sf.openrocket.gui.watcher.FileWatcher; import net.sf.openrocket.gui.watcher.WatchEvent; import net.sf.openrocket.gui.watcher.WatchService; import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.InsideColorComponent; import net.sf.openrocket.rocketcomponent.RocketComponent; import com.google.inject.Inject; @@ -67,10 +68,12 @@ public class EditDecalHelper { * @param doc * @param component * @param decal + * @param insideApp flag to check whether it is the inside appearance that is edited * @return * @throws EditDecalHelperException */ - public DecalImage editDecal(Window parent, OpenRocketDocument doc, RocketComponent component, DecalImage decal) throws EditDecalHelperException { + public DecalImage editDecal(Window parent, OpenRocketDocument doc, RocketComponent component, DecalImage decal, + boolean insideApp) throws EditDecalHelperException { boolean sysPrefSet = prefs.isDecalEditorPreferenceSet(); int usageCount = doc.countDecalUsage(decal); @@ -111,7 +114,10 @@ public class EditDecalHelper { } if (dialog.isEditOne()) { - decal = makeDecalUnique(doc, component, decal); + if (insideApp) + decal = makeDecalUnique(doc, component, decal); + else + decal = makeDecalUniqueInside(doc, component, decal); } launchEditor(useSystemEditor, commandLine, decal); @@ -131,6 +137,21 @@ public class EditDecalHelper { return newImage; } + + private static DecalImage makeDecalUniqueInside(OpenRocketDocument doc, RocketComponent component, DecalImage decal) { + + DecalImage newImage = doc.makeUniqueDecal(decal); + + if (component instanceof InsideColorComponent) { + InsideColorComponent c = ((InsideColorComponent)component); + AppearanceBuilder appearanceBuilder = new AppearanceBuilder(c.getInsideAppearance()); + appearanceBuilder.setImage(newImage); + + c.setInsideAppearance(appearanceBuilder.getAppearance()); + } + + return newImage; + } private void launchEditor(boolean useSystemEditor, String commandTemplate, final DecalImage decal) throws EditDecalHelperException { From 744dbeb9c7ee52ab5cbdf26b3ec8514b2013bac5 Mon Sep 17 00:00:00 2001 From: Sibo Van Gool Date: Tue, 6 Jul 2021 21:04:51 +0200 Subject: [PATCH 4/4] [fixes #905] use of InsideColorComponentHandler --- .../document/OpenRocketDocument.java | 2 +- .../openrocket/file/GeneralRocketSaver.java | 2 +- .../importt/InsideAppearanceHandler.java | 6 +- .../savers/RocketComponentSaver.java | 7 +- .../openrocket/rocketcomponent/BodyTube.java | 48 +-------- .../rocketcomponent/InsideColorComponent.java | 47 +-------- .../InsideColorComponentHandler.java | 97 +++++++++++++++++++ .../openrocket/rocketcomponent/LaunchLug.java | 49 +--------- .../openrocket/rocketcomponent/NoseCone.java | 48 +-------- .../rocketcomponent/Transition.java | 53 ++-------- .../rocketcomponent/TubeFinSet.java | 49 +--------- .../gui/configdialog/AppearancePanel.java | 20 ++-- .../gui/figure3d/RealisticRenderer.java | 6 +- .../openrocket/gui/util/EditDecalHelper.java | 7 +- 14 files changed, 146 insertions(+), 295 deletions(-) create mode 100644 core/src/net/sf/openrocket/rocketcomponent/InsideColorComponentHandler.java diff --git a/core/src/net/sf/openrocket/document/OpenRocketDocument.java b/core/src/net/sf/openrocket/document/OpenRocketDocument.java index c5cdb94cc..022ad0902 100644 --- a/core/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/core/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -293,7 +293,7 @@ public class OpenRocketDocument implements ComponentChangeListener { */ private boolean hasDecalInside(RocketComponent comp, DecalImage img) { if (comp instanceof InsideColorComponent) { - Appearance a = ((InsideColorComponent)comp).getInsideAppearance(); + Appearance a = ((InsideColorComponent)comp).getInsideColorComponentHandler().getInsideAppearance(); if (a == null) return false; Decal d = a.getTexture(); diff --git a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java index 7e1a1827c..4a4ecbec6 100644 --- a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java +++ b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java @@ -163,7 +163,7 @@ public class GeneralRocketSaver { Appearance ap = c.getAppearance(); Appearance ap_in = null; if (c instanceof InsideColorComponent) - ap_in = ((InsideColorComponent)c).getInsideAppearance(); + ap_in = ((InsideColorComponent)c).getInsideColorComponentHandler().getInsideAppearance(); if ((ap == null) && (ap_in == null)) continue; if (ap != null) { diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java index 16c3e6753..37ec07d23 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/InsideAppearanceHandler.java @@ -24,13 +24,13 @@ public class InsideAppearanceHandler extends AppearanceHandler { if ("edgesSameAsInside".equals(element)) { boolean edgesSameAsInside = Boolean.parseBoolean(content); if (component instanceof InsideColorComponent) - ((InsideColorComponent)component).setEdgesSameAsInside(edgesSameAsInside); + ((InsideColorComponent)component).getInsideColorComponentHandler().setEdgesSameAsInside(edgesSameAsInside); return; } if ("insideSameAsOutside".equals(element)) { boolean insideSameAsOutside = Boolean.parseBoolean(content); if (component instanceof InsideColorComponent) - ((InsideColorComponent)component).setInsideSameAsOutside(insideSameAsOutside); + ((InsideColorComponent)component).getInsideColorComponentHandler().setInsideSameAsOutside(insideSameAsOutside); return; } @@ -40,6 +40,6 @@ public class InsideAppearanceHandler extends AppearanceHandler { @Override protected void setAppearance() { if ((component instanceof InsideColorComponent)) - ((InsideColorComponent)component).setInsideAppearance(builder.getAppearance()); + ((InsideColorComponent)component).getInsideColorComponentHandler().setInsideAppearance(builder.getAppearance()); } } diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java index 29664b387..1c4acc289 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java @@ -53,11 +53,12 @@ public class RocketComponentSaver { // Save inside appearance if (c instanceof InsideColorComponent) { - Appearance ap_in = ((InsideColorComponent)c).getInsideAppearance(); + InsideColorComponentHandler handler = ((InsideColorComponent)c).getInsideColorComponentHandler(); + Appearance ap_in = handler.getInsideAppearance(); if (ap_in != null) { elements.add(""); - elements.add("" + ((InsideColorComponent) c).isEdgesSameAsInside() + ""); - elements.add("" + ((InsideColorComponent) c).isInsideSameAsOutside() + ""); + elements.add("" + handler.isEdgesSameAsInside() + ""); + elements.add("" + handler.isInsideSameAsOutside() + ""); buildAppearanceElements(elements, ap_in); elements.add(""); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index 837dd5cf0..2a43e7279 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -32,10 +32,7 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou private MotorConfigurationSet motors; - // Settings for inside/edge appearance - private Appearance insideAppearance = null; - private boolean insideSameAsOutside = true; - private boolean edgesSameAsInside = true; + private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this); public BodyTube() { this(8 * DEFAULT_RADIUS, DEFAULT_RADIUS); @@ -459,48 +456,9 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou return ClusterConfiguration.SINGLE; } - @Override - public Appearance getInsideAppearance() { - return this.insideAppearance; - } @Override - public void setInsideAppearance(Appearance appearance) { - this.insideAppearance = appearance; - if (this.insideAppearance != null) { - Decal d = this.insideAppearance.getTexture(); - if (d != null) { - d.getImage().addChangeListener(new StateChangeListener() { - - @Override - public void stateChanged(EventObject e) { - fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); - } - - }); - } - } - // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? - fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); - } - - @Override - public boolean isEdgesSameAsInside() { - return this.edgesSameAsInside; - } - - @Override - public void setEdgesSameAsInside(boolean newState) { - this.edgesSameAsInside = newState; - } - - @Override - public boolean isInsideSameAsOutside() { - return this.insideSameAsOutside; - } - - @Override - public void setInsideSameAsOutside(boolean newState) { - this.insideSameAsOutside = newState; + public InsideColorComponentHandler getInsideColorComponentHandler() { + return this.insideColorComponentHandler; } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java index 3605cc322..c964b902a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponent.java @@ -19,50 +19,7 @@ import java.util.EventObject; */ public interface InsideColorComponent { /** - * Get the realistic inside appearance of this component. - * null = use the default for this material - * - * @return The component's realistic inner appearance, or null + * @return the InsideColorComponentHandler */ - Appearance getInsideAppearance(); - - /** - * Set the realistic inside appearance of this component. - * Use null for default. - * - * @param appearance the inner appearance to be set - */ - void setInsideAppearance(Appearance appearance); - - /** - * Checks whether the component uses for the edges the same appearance as the inside (return true) or as the - * outside (return false) - * - * @return true if edges should use the same appearance as the inside, - * false if edges should use the same appearance as the outside - */ - boolean isEdgesSameAsInside(); - - /** - * Sets the new state for edgesUseInsideAppearance to newState - * - * @param newState new edgesUseInsideAppearance value - */ - void setEdgesSameAsInside(boolean newState); - - /** - * Checks whether the component should use the same appearance for the inside as the outside (return true) or as the - * outside (return false) - * - * @return true if edges should use the same appearance as the inside, - * false if edges should use the same appearance as the outside - */ - boolean isInsideSameAsOutside(); - - /** - * Sets the new state for insideSameAsOutside to newState - * - * @param newState new edgesUseInsideAppearance value - */ - void setInsideSameAsOutside(boolean newState); + InsideColorComponentHandler getInsideColorComponentHandler(); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponentHandler.java b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponentHandler.java new file mode 100644 index 000000000..44f966418 --- /dev/null +++ b/core/src/net/sf/openrocket/rocketcomponent/InsideColorComponentHandler.java @@ -0,0 +1,97 @@ +package net.sf.openrocket.rocketcomponent; + +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; +import net.sf.openrocket.util.StateChangeListener; + +import java.util.EventObject; + +/** + * This component handles the necessary functionalities of an InsideColorComponent. + * + * @author Sibo Van Gool + */ +public class InsideColorComponentHandler { + private final RocketComponent component; + private Appearance insideAppearance = null; + private boolean insideSameAsOutside = true; + private boolean edgesSameAsInside = true; + + public InsideColorComponentHandler(RocketComponent component) { + this.component = component; + } + + /** + * Get the realistic inside appearance of this component. + * null = use the default for this material + * + * @return The component's realistic inner appearance, or null + */ + public Appearance getInsideAppearance() { + return this.insideAppearance; + } + + /** + * Set the realistic inside appearance of this component. + * Use null for default. + * + * @param appearance the inner appearance to be set + */ + public void setInsideAppearance(Appearance appearance) { + this.insideAppearance = appearance; + if (this.insideAppearance != null) { + Decal d = this.insideAppearance.getTexture(); + if (d != null) { + d.getImage().addChangeListener(new StateChangeListener() { + + @Override + public void stateChanged(EventObject e) { + component.fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); + } + + }); + } + } + component.fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + /** + * Checks whether the component uses for the edges the same appearance as the inside (return true) or as the + * outside (return false) + * + * @return true if edges should use the same appearance as the inside, + * false if edges should use the same appearance as the outside + */ + public boolean isEdgesSameAsInside() { + return this.edgesSameAsInside; + } + + /** + * Sets the new state for edgesUseInsideAppearance to newState + * + * @param newState new edgesUseInsideAppearance value + */ + public void setEdgesSameAsInside(boolean newState) { + this.edgesSameAsInside = newState; + } + + /** + * Checks whether the component should use the same appearance for the inside as the outside (return true) or as the + * outside (return false) + * + * @return true if edges should use the same appearance as the inside, + * false if edges should use the same appearance as the outside + */ + public boolean isInsideSameAsOutside() { + return this.insideSameAsOutside; + } + + /** + * Sets the new state for insideSameAsOutside to newState + * + * @param newState new edgesUseInsideAppearance value + */ + public void setInsideSameAsOutside(boolean newState) { + this.insideSameAsOutside = newState; + } +} diff --git a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java index cbd2bd28f..26a4a126c 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java +++ b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java @@ -30,10 +30,7 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, B private int instanceCount = 1; private double instanceSeparation = 0; // front-front along the positive rocket axis. i.e. [1,0,0]; - // Settings for inside/edge appearance - private Appearance insideAppearance = null; - private boolean insideSameAsOutside = true; - private boolean edgesSameAsInside = true; + private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this); public LaunchLug() { super(AxialMethod.MIDDLE); @@ -289,47 +286,7 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, B } @Override - public Appearance getInsideAppearance() { - return this.insideAppearance; - } - - @Override - public void setInsideAppearance(Appearance appearance) { - this.insideAppearance = appearance; - if (this.insideAppearance != null) { - Decal d = this.insideAppearance.getTexture(); - if (d != null) { - d.getImage().addChangeListener(new StateChangeListener() { - - @Override - public void stateChanged(EventObject e) { - fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); - } - - }); - } - } - // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? - fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); - } - - @Override - public boolean isEdgesSameAsInside() { - return this.edgesSameAsInside; - } - - @Override - public void setEdgesSameAsInside(boolean newState) { - this.edgesSameAsInside = newState; - } - - @Override - public boolean isInsideSameAsOutside() { - return this.insideSameAsOutside; - } - - @Override - public void setInsideSameAsOutside(boolean newState) { - this.insideSameAsOutside = newState; + public InsideColorComponentHandler getInsideColorComponentHandler() { + return this.insideColorComponentHandler; } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java index 3ca204336..bc9855953 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java +++ b/core/src/net/sf/openrocket/rocketcomponent/NoseCone.java @@ -20,10 +20,7 @@ import java.util.EventObject; public class NoseCone extends Transition implements InsideColorComponent { private static final Translator trans = Application.getTranslator(); - // Settings for inside/edge appearance - private Appearance insideAppearance = null; - private boolean insideSameAsOutside = true; - private boolean edgesSameAsInside = true; + private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this); /********* Constructors **********/ public NoseCone() { @@ -145,48 +142,9 @@ public class NoseCone extends Transition implements InsideColorComponent { return trans.get("NoseCone.NoseCone"); } - @Override - public Appearance getInsideAppearance() { - return this.insideAppearance; - } @Override - public void setInsideAppearance(Appearance appearance) { - this.insideAppearance = appearance; - if (this.insideAppearance != null) { - Decal d = this.insideAppearance.getTexture(); - if (d != null) { - d.getImage().addChangeListener(new StateChangeListener() { - - @Override - public void stateChanged(EventObject e) { - fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); - } - - }); - } - } - // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? - fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); - } - - @Override - public boolean isEdgesSameAsInside() { - return this.edgesSameAsInside; - } - - @Override - public void setEdgesSameAsInside(boolean newState) { - this.edgesSameAsInside = newState; - } - - @Override - public boolean isInsideSameAsOutside() { - return this.insideSameAsOutside; - } - - @Override - public void setInsideSameAsOutside(boolean newState) { - this.insideSameAsOutside = newState; + public InsideColorComponentHandler getInsideColorComponentHandler() { + return this.insideColorComponentHandler; } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index 1d446a147..f8852c12a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -44,10 +44,7 @@ public class Transition extends SymmetricComponent implements InsideColorCompone // Used to cache the clip length private double clipLength = -1; - // Settings for inside/edge appearance - private Appearance insideAppearance = null; - private boolean insideSameAsOutside = true; - private boolean edgesSameAsInside = true; + private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this); public Transition() { super(); @@ -607,6 +604,11 @@ public class Transition extends SymmetricComponent implements InsideColorCompone } + @Override + public InsideColorComponentHandler getInsideColorComponentHandler() { + return this.insideColorComponentHandler; + } + /** * An enumeration listing the possible shapes of transitions. * @@ -947,48 +949,5 @@ public class Transition extends SymmetricComponent implements InsideColorCompone } } - @Override - public Appearance getInsideAppearance() { - return this.insideAppearance; - } - @Override - public void setInsideAppearance(Appearance appearance) { - this.insideAppearance = appearance; - if (this.insideAppearance != null) { - Decal d = this.insideAppearance.getTexture(); - if (d != null) { - d.getImage().addChangeListener(new StateChangeListener() { - - @Override - public void stateChanged(EventObject e) { - fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); - } - - }); - } - } - // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? - fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); - } - - @Override - public boolean isEdgesSameAsInside() { - return this.edgesSameAsInside; - } - - @Override - public void setEdgesSameAsInside(boolean newState) { - this.edgesSameAsInside = newState; - } - - @Override - public boolean isInsideSameAsOutside() { - return this.insideSameAsOutside; - } - - @Override - public void setInsideSameAsOutside(boolean newState) { - this.insideSameAsOutside = newState; - } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java index 92aca3409..4dd4843b6 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -28,10 +28,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable, private AngleMethod angleMethod = AngleMethod.FIXED; protected RadiusMethod radiusMethod = RadiusMethod.RELATIVE; - // Settings for inside/edge appearance - private Appearance insideAppearance = null; - private boolean insideSameAsOutside = true; - private boolean edgesSameAsInside = true; + private final InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this); /** * Rotation angle of the first fin. Zero corresponds to the positive y-axis. @@ -458,49 +455,9 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable, } - @Override - public Appearance getInsideAppearance() { - return this.insideAppearance; - } @Override - public void setInsideAppearance(Appearance appearance) { - this.insideAppearance = appearance; - if (this.insideAppearance != null) { - Decal d = this.insideAppearance.getTexture(); - if (d != null) { - d.getImage().addChangeListener(new StateChangeListener() { - - @Override - public void stateChanged(EventObject e) { - fireComponentChangeEvent(ComponentChangeEvent.TEXTURE_CHANGE); - } - - }); - } - } - // CHECK - should this be a TEXTURE_CHANGE and not NONFUNCTIONAL_CHANGE? - fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + public InsideColorComponentHandler getInsideColorComponentHandler() { + return this.insideColorComponentHandler; } - - @Override - public boolean isEdgesSameAsInside() { - return this.edgesSameAsInside; - } - - @Override - public void setEdgesSameAsInside(boolean newState) { - this.edgesSameAsInside = newState; - } - - @Override - public boolean isInsideSameAsOutside() { - return this.insideSameAsOutside; - } - - @Override - public void setInsideSameAsOutside(boolean newState) { - this.insideSameAsOutside = newState; - } - } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java index 9fb0f9fff..a0bee20fa 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java @@ -35,6 +35,7 @@ import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; import net.sf.openrocket.rocketcomponent.InsideColorComponent; +import net.sf.openrocket.rocketcomponent.InsideColorComponentHandler; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.GeneralUnit; @@ -187,7 +188,8 @@ public class AppearancePanel extends JPanel { } if (c instanceof InsideColorComponent) { - previousUserSelectedInsideAppearance = ((InsideColorComponent) c).getInsideAppearance(); + previousUserSelectedInsideAppearance = ((InsideColorComponent) c).getInsideColorComponentHandler() + .getInsideAppearance(); if (previousUserSelectedInsideAppearance == null) { previousUserSelectedInsideAppearance = new AppearanceBuilder() .getAppearance(); @@ -298,6 +300,8 @@ public class AppearancePanel extends JPanel { // Display a tabbed panel for choosing the outside and inside appearance, if the object is of type InsideColorComponent if (c instanceof InsideColorComponent) { + InsideColorComponentHandler handler = ((InsideColorComponent)c).getInsideColorComponentHandler(); + JTabbedPane tabbedPane = new JTabbedPane(); JPanel outsidePanel = new JPanel(new MigLayout("fill", "[150][grow][150][grow]")); JPanel insidePanel = new JPanel(new MigLayout("fill", "[150][grow][150][grow]")); @@ -312,7 +316,7 @@ public class AppearancePanel extends JPanel { add(tabbedPane, "span 4, growx, wrap"); // Checkbox to set edges the same as inside/outside - BooleanModel b = new BooleanModel(((InsideColorComponent) c).isEdgesSameAsInside()); + BooleanModel b = new BooleanModel(handler.isEdgesSameAsInside()); JCheckBox edges = new JCheckBox(b); edges.setText(trans.get("AppearanceCfg.lbl.EdgesSameAsInside")); edges.setToolTipText(trans.get("AppearanceCfg.lbl.ttip.EdgesSameAsInside")); @@ -321,7 +325,7 @@ public class AppearancePanel extends JPanel { edges.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ((InsideColorComponent) c).setEdgesSameAsInside(edges.isSelected()); + handler.setEdgesSameAsInside(edges.isSelected()); c.fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } }); @@ -347,7 +351,8 @@ public class AppearancePanel extends JPanel { } else if (c instanceof InsideColorComponent) { builder = insideAb; - mDefault = new BooleanModel(((InsideColorComponent)c).getInsideAppearance() == null); + mDefault = new BooleanModel( + ((InsideColorComponent)c).getInsideColorComponentHandler().getInsideAppearance() == null); } else return; @@ -363,7 +368,7 @@ public class AppearancePanel extends JPanel { if (!insideBuilder) c.setAppearance(builder.getAppearance()); else - ((InsideColorComponent)c).setInsideAppearance(builder.getAppearance()); + ((InsideColorComponent)c).getInsideColorComponentHandler().setInsideAppearance(builder.getAppearance()); decalModel.refresh(); } }); @@ -403,14 +408,15 @@ public class AppearancePanel extends JPanel { // Custom inside color if (insideBuilder) { - BooleanModel b = new BooleanModel(((InsideColorComponent) c).isInsideSameAsOutside()); + InsideColorComponentHandler handler = ((InsideColorComponent)c).getInsideColorComponentHandler(); + BooleanModel b = new BooleanModel(handler.isInsideSameAsOutside()); JCheckBox customInside = new JCheckBox(b); customInside.setText(trans.get("AppearanceCfg.lbl.InsideSameAsOutside")); customInside.setToolTipText(trans.get("AppearanceCfg.lbl.ttip.InsideSameAsOutside")); customInside.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ((InsideColorComponent) c).setInsideSameAsOutside(customInside.isSelected()); + handler.setInsideSameAsOutside(customInside.isSelected()); c.fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); } }); diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java index e799f886c..9b155748a 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java @@ -95,10 +95,10 @@ public class RealisticRenderer extends RocketRenderer { Appearance app = getAppearance(c); if (c instanceof InsideColorComponent) { Appearance innerApp = getInsideAppearance(c); - if (((InsideColorComponent) c).isInsideSameAsOutside()) innerApp = app; + if (((InsideColorComponent) c).getInsideColorComponentHandler().isInsideSameAsOutside()) innerApp = app; render(gl, geom, Surface.INSIDE, innerApp, true, alpha); - if (((InsideColorComponent) c).isEdgesSameAsInside()) + if (((InsideColorComponent) c).getInsideColorComponentHandler().isEdgesSameAsInside()) render(gl, geom, Surface.EDGES, innerApp, false, alpha); else render(gl, geom, Surface.EDGES, app, false, alpha); @@ -208,7 +208,7 @@ public class RealisticRenderer extends RocketRenderer { protected Appearance getInsideAppearance(RocketComponent c) { if (c instanceof InsideColorComponent) { - Appearance ret = ((InsideColorComponent)c).getInsideAppearance(); + Appearance ret = ((InsideColorComponent)c).getInsideColorComponentHandler().getInsideAppearance(); if (ret == null) { ret = DefaultAppearance.getDefaultAppearance(c); } diff --git a/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java b/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java index b6ed0c1a5..7fbf24e17 100644 --- a/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java +++ b/swing/src/net/sf/openrocket/gui/util/EditDecalHelper.java @@ -17,6 +17,7 @@ import net.sf.openrocket.gui.watcher.WatchEvent; import net.sf.openrocket.gui.watcher.WatchService; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.InsideColorComponent; +import net.sf.openrocket.rocketcomponent.InsideColorComponentHandler; import net.sf.openrocket.rocketcomponent.RocketComponent; import com.google.inject.Inject; @@ -143,11 +144,11 @@ public class EditDecalHelper { DecalImage newImage = doc.makeUniqueDecal(decal); if (component instanceof InsideColorComponent) { - InsideColorComponent c = ((InsideColorComponent)component); - AppearanceBuilder appearanceBuilder = new AppearanceBuilder(c.getInsideAppearance()); + InsideColorComponentHandler handler = ((InsideColorComponent)component).getInsideColorComponentHandler(); + AppearanceBuilder appearanceBuilder = new AppearanceBuilder(handler.getInsideAppearance()); appearanceBuilder.setImage(newImage); - c.setInsideAppearance(appearanceBuilder.getAppearance()); + handler.setInsideAppearance(appearanceBuilder.getAppearance()); } return newImage;