package net.sf.openrocket.appearance; import net.sf.openrocket.appearance.Decal.EdgeMode; import net.sf.openrocket.util.AbstractChangeSource; import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Coordinate; /** * Use this class to build an immutable Appearance object in a friendly way. Set * the various values one at a time with the setter methods and then call * getAppearance(). Each call to getAppearance will return a new appearance. * * You can use this class repeatedly and resetToDefaults() in between, or create * a new one every time. * * @author Bill Kuker <bkuker@billkuker.com> * */ public class AppearanceBuilder extends AbstractChangeSource { private Color paint; //current cached color private double shine; //current cached shine private double offsetU, offsetV;//current offset to be used private double centerU, centerV;//current values for the center of the appearance private double scaleU, scaleV; //current values for scaling private double rotation; // private DecalImage image; private Decal.EdgeMode edgeMode; private boolean batch; /** * Default constructor * Set the builder to make appearance of null values * */ public AppearanceBuilder() { resetToDefaults(); } /** * Constructor that initializes already with a * * @param a the appearance to be copied */ public AppearanceBuilder(Appearance a) { setAppearance(a); } /** * Clears the builder cache and set to build blank appearances */ private void resetToDefaults() { paint = new Color(0, 0, 0); shine = 0; offsetU = offsetV = 0; centerU = centerV = 0; scaleU = scaleV = 1; rotation = 0; image = null; edgeMode = EdgeMode.REPEAT; fireChangeEvent();//shouldn't this fire change event? } /** * Sets the builder to create appearance equals to an existing appearance * Fires change only once, hence the call to batch * * @param a the appearance to be used as the new template */ public void setAppearance(final Appearance a) { batch(new Runnable() { @Override public void run() { resetToDefaults(); if (a != null) { setPaint(a.getPaint()); setShine(a.getShine()); setDecal(a.getTexture()); } } }); } /** * makes a full copy of a decal, including information of offsets, center and scale * * @param d The decal */ public void setDecal(Decal d){ if (d != null) { setOffset(d.getOffset().x, d.getOffset().y); setCenter(d.getCenter().x, d.getCenter().y); setScaleUV(d.getScale().x, d.getScale().y); setRotation(d.getRotation()); setEdgeMode(d.getEdgeMode()); setImage(d.getImage()); } fireChangeEvent(); } /** * Method creates another object of Appearance * @return the created appearance */ public Appearance getAppearance() { Decal t = null; if (image != null) { t = new Decal( // new Coordinate(offsetU, offsetV), // new Coordinate(centerU, centerV), // new Coordinate(scaleU, scaleV), // rotation, // image, // edgeMode); } return new Appearance(paint, shine, t); } /** * get current paint in template * * return the color used in the current paint */ public Color getPaint() { return paint; } /** * sets a new paint color to be used * fires change event * * @param paint the new color */ public void setPaint(Color paint) { this.paint = paint; fireChangeEvent(); } /** * gets the current shine * * @return current shine in template */ public double getShine() { return shine; } /** * Sets a new shine for template * fires change event * * @param shine the new shine for template */ public void setShine(double shine) { this.shine = shine; fireChangeEvent(); } /** * gets the current offset axis U used * * @return offset in axis U */ public double getOffsetU() { return offsetU; } /** * sets a new offset in axis U for template * fires change event * * @param offsetU the new offset to be used */ public void setOffsetU(double offsetU) { this.offsetU = offsetU; fireChangeEvent(); } /** * gets the current offset axis V used * * @return offset in axis V */ public double getOffsetV() { return offsetV; } /** * sets a new offset in axis V for template * fires change event * * @param offsetV the new offset to be used */ public void setOffsetV(double offsetV) { this.offsetV = offsetV; fireChangeEvent(); } /** * sets a new offset to be used for template * fires change event * * @param u offset in axis u * @param v offset in axis v */ public void setOffset(double u, double v) { setOffsetU(u); setOffsetV(v); } /** * gets the current center in axis U used in template * * @return the current value of U of cente in template */ public double getCenterU() { return centerU; } /** * set a new value for axis U for center in template * fires change event * * @param centerU value of axis U for center */ public void setCenterU(double centerU) { this.centerU = centerU; fireChangeEvent(); } /** * gets the current center in axis V used in template * * @return the current value of V of cente in template */ public double getCenterV() { return centerV; } /** * set a new value for axis V for center in template * fires change event * * @param centerU value of axis V for center */ public void setCenterV(double centerV) { this.centerV = centerV; fireChangeEvent(); } /** * sets a new center for template * fires chenge event * * @param u new value for axis u of the center * @param v new value for axis v of the center */ public void setCenter(double u, double v) { setCenterU(u); setCenterV(v); } /** * gets the current scale value of axis u in template * * @return current value for axis u of scale */ public double getScaleU() { return scaleU; } /** * sets a new value of axis U for scaling in the template * fires change event * * @param scaleU new value of scalling in axis U */ public void setScaleU(double scaleU) { this.scaleU = scaleU; fireChangeEvent(); } /** * gets the current scale value of axis V in template * * @return current value for axis V of scale */ public double getScaleV() { return scaleV; } /** * sets a new value of axis V for scaling in the template * fires change event * * @param scaleV new value of scalling in axis V */ public void setScaleV(double scaleV) { this.scaleV = scaleV; fireChangeEvent(); } /** * sets a new value of both axis for scaling in the template * fires change event * * @param u new value of scalling in axis U * @param v new value of scalling in axis v */ public void setScaleUV(double u, double v) { setScaleU(u); setScaleV(v); } /** * gets the current value of X axis for scalling in the template * * @return value of scalling in axis x */ public double getScaleX() { return 1.0 / getScaleU(); } /** * sets a new value of axis X for scalling in template * fires change event * * @param scaleX the new value for axis X */ public void setScaleX(double scaleX) { setScaleU(1.0 / scaleX); } /** * gets the current value of Y axis for scalling in the template * * @return value of scalling in axis Y */ public double getScaleY() { return 1.0 / getScaleV(); } /** * sets a new value of axis Y for scalling in template * fires change event * * @param scaleX the new value for axis Y */ public void setScaleY(double scaleY) { setScaleV(1.0 / scaleY); } /** * gets the current value of rotation in template * * @return the current rotation in template */ public double getRotation() { return rotation; } /** * sets a new value of rotation in template * fires chenge event * * @param rotation the new value for rotation in template */ public void setRotation(double rotation) { this.rotation = rotation; fireChangeEvent(); } /** * gets the current image in template * * @param the current image in template */ public DecalImage getImage() { return image; } /** * sets a new image in template * fires change event * * @param image the new image to be used as template */ public void setImage(DecalImage image) { this.image = image; fireChangeEvent(); } /** * gets the current Edge mode in use * * @return the current edge mode in template */ public Decal.EdgeMode getEdgeMode() { return edgeMode; } /** * sets a new edge mode to be used in template * fires change event * * @param edgeMode the new edgeMode to be used */ public void setEdgeMode(Decal.EdgeMode edgeMode) { this.edgeMode = edgeMode; fireChangeEvent(); } /** * only applies change if there is no more changes comming */ @Override protected void fireChangeEvent() { if (!batch) super.fireChangeEvent(); } /** * function that garantees that chenges event only occurs after all changes are made * * param r the functor to be executed */ public void batch(Runnable r) { batch = true; r.run(); batch = false; fireChangeEvent(); } }