Source code: com/arranger/jarl/trait/base/PositionPath.java
1 package com.arranger.jarl.trait.base;
2
3 import com.arranger.jarl.base.IContext;
4 import com.arranger.jarl.base.IJarlObjectInfo;
5 import com.arranger.jarl.base.Time;
6 import com.arranger.jarl.trait.BaseSegmentTrait;
7 import com.arranger.jarl.util.*;
8 import com.arranger.jarl.widget.IWidget;
9 import com.arranger.jarl.widget.IWidgetDef;
10 import org.w3c.dom.Element;
11
12 import java.awt.*;
13 import java.awt.geom.Point2D;
14
15 /**
16 * PositionPath is similar to position, but places the widget on the current position
17 * of another shape... In other words, if the shape is an ellipse, the motion path of the
18 * widget will follow the ellipse
19 *
20 * @traitAttribute pathDef ## xs:string ## the name of the widget that defines the path
21 * @traitAttribute offset ## xs:string ## the percentage throgh the shape to start at (eg 0%)
22 * @traitAttribute clockwise ## xs:boolean ## the direction to go (true|false)
23 *
24 * @traitAttribute startPathDef ## xs:string ## the (starting) name of the widget that defines the path (for consitency's sake)
25 * @traitAttribute endPathDef ## xs:string ## the (ending) name of the widget that defines the path (for consitency's sake)
26 * @traitAttribute startOffset ## xs:string ## the starting percentage throgh the shape to start at (eg 0%)
27 * @traitAttribute startClockwise ## xs:boolean ## the starting direction to go (true|false)
28 * @traitAttribute endOffset ## xs:string ## the ending percentage throgh the shape to end at (eg 0%)
29 * @traitAttribute endClockwise ## xs:boolean ## the ending direction to go (true|false)
30 */
31 public class PositionPath extends BaseSegmentTrait {
32
33 protected String m_pathDef;
34 protected double m_offset = Double.NEGATIVE_INFINITY;
35 protected boolean m_clockwise = true;
36
37 protected String m_startPathDef;
38 protected String m_endPathDef;
39 protected double m_startOffset = Double.NEGATIVE_INFINITY;
40 protected boolean m_startClockwise = true;
41 protected double m_endOffset = Double.NEGATIVE_INFINITY;
42 protected boolean m_endClockwise = true;
43
44 public Graphics2D prePaint(IWidget widget, IContext context, Graphics2D graphics2D) {
45 graphics2D = initGraphicsTransform(graphics2D);
46 store(context);
47
48 //get the m_pathDef
49 String pathDef;
50 if (m_pathDef != null) {
51 pathDef = m_pathDef;
52 } else if (m_startPathDef != null && m_endPathDef != null) {
53 pathDef = m_startPathDef; //no interp
54 } else {
55 PositionPathConfigSegment positionSegment = (PositionPathConfigSegment) getCurrentSegment(widget, context);
56 pathDef = positionSegment.getStartPathDef(); //no interp
57 }
58
59 //lookit up
60 IWidgetDef widgetDef = (IWidgetDef) context.getJarl().getWidgetDefs().get(pathDef);
61 if (widgetDef == null) {
62 throw new IllegalStateException("PositionPath can't locate pathDef for: " + pathDef);
63 }
64 widgetDef.setStartTime(new Time(widget.getStartTime().getFrame()));
65 widgetDef.setEndTime(new Time(widget.getEndTime().getFrame()));
66
67 //now that we have the widget, let's get a shape for it...
68 //todo store any old shape
69 Graphics2D tempGraphics = (Graphics2D) context.createImage().getGraphics();
70
71 //get the shape
72 widgetDef.paint(context, tempGraphics);
73 Shape shape = (Shape) context.getAttributes().get(Shape.class);
74 Point2D[] points = WidgetUtil.getPoints(shape);
75
76 //dispose
77 tempGraphics.dispose();
78
79 double currentOffset;
80 boolean currentClockwise;
81 //base the clockwise off of offset
82 if (m_offset != Double.NEGATIVE_INFINITY) {
83 currentOffset = m_offset;
84 currentClockwise = m_clockwise;
85 } else if (m_startOffset != Double.NEGATIVE_INFINITY && m_endOffset != Double.NEGATIVE_INFINITY) {
86 double currentWidgetPct = InterpolateUtil.interpolate(widget, context.getTime());
87 currentOffset = InterpolateUtil.interpolate(0,
88 1,
89 m_startOffset,
90 m_endOffset,
91 currentWidgetPct);
92 currentClockwise = m_startClockwise;
93 } else {
94 PositionPathConfigSegment positionPathConfigSegment = (PositionPathConfigSegment) getCurrentSegment(widget, context);
95 double currentSegmentWidgetPct = getCurrentSegmentTimePct(widget, context, positionPathConfigSegment);
96 currentOffset = InterpolateUtil.interpolate(0,
97 1,
98 positionPathConfigSegment.getStartOffset(),
99 positionPathConfigSegment.getEndOffset(),
100 currentSegmentWidgetPct);
101 currentClockwise = positionPathConfigSegment.isStartClockwise();
102 }
103 currentOffset %= 1.0; //normalize
104 /*System.out.println(widget.getStartTime().getFrame() + " --> " + widget.getEndTime().getFrame());
105 System.out.println(currentOffset + " time: " + context.getTime().getFrame());*/
106
107 //get point
108 double index = (points.length - 1) * ((currentClockwise) ? currentOffset : 1.0 - currentOffset);
109 Point2D position = points[(int)index];
110
111 graphics2D.translate(
112 position.getX() - (context.getWidth() / 2),
113 position.getY() - (context.getHeight() / 2));
114
115 restoreContext(context);
116 return graphics2D;
117 }
118
119 /**
120 * After the call to {@link IWidget#paint} is called
121 * the trait can restore some state
122 * @param widget the widget that is being painted
123 * @param context the current context
124 * @param graphics2D the current graphics object
125 * @return the new graphics, or the same
126 */
127 public Graphics2D postPaint(IWidget widget, IContext context, Graphics2D graphics2D) {
128 restoreTransform(graphics2D);
129 return graphics2D;
130 }
131
132 protected void initAttributes(IContext context) {
133 super.initAttributes(context);
134
135 ObjectUtil.initializeField("pathDef", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
136 ObjectUtil.initializeField("clockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
137 ObjectUtil.initializeField("offset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
138
139 ObjectUtil.initializeField("startPathDef", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
140 ObjectUtil.initializeField("endPathDef", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
141 ObjectUtil.initializeField("startClockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
142 ObjectUtil.initializeField("startOffset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
143 ObjectUtil.initializeField("endClockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
144 ObjectUtil.initializeField("endOffset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
145 }
146
147 protected void addJarlObjectInfo(IJarlObjectInfo jarlObjectInfo) {
148 super.addJarlObjectInfo(jarlObjectInfo);
149 populateInfo(jarlObjectInfo, "pathDef", "Path Definition", JarlInfoUtil.PRIMITIVE_DISPLAY);
150 populateInfo(jarlObjectInfo, "clockwise", "Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
151 populateInfo(jarlObjectInfo, "offset", "Offset", JarlInfoUtil.PCT_DISPLAY);
152
153 populateInfo(jarlObjectInfo, "startPathDef", "Start Path Definition", JarlInfoUtil.PRIMITIVE_DISPLAY);
154 populateInfo(jarlObjectInfo, "startClockwise", "Start Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
155 populateInfo(jarlObjectInfo, "endClockwise", "End Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
156 populateInfo(jarlObjectInfo, "endPathDef", "End Path Definition", JarlInfoUtil.PRIMITIVE_DISPLAY);
157 populateInfo(jarlObjectInfo, "startOffset", "Start Offset", JarlInfoUtil.PCT_DISPLAY);
158 populateInfo(jarlObjectInfo, "endOffset", "End Offset", JarlInfoUtil.PCT_DISPLAY);
159 }
160
161 public WidgetConfigSegment createSegment(Element element) {
162 return new PositionPathConfigSegment(element);
163 }
164
165 protected static class PositionPathConfigSegment extends WidgetConfigSegment {
166
167 protected String m_startPathDef;
168 protected String m_endPathDef;
169
170 protected double m_startOffset = Double.NEGATIVE_INFINITY;
171 protected boolean m_startClockwise = true;
172 protected double m_endOffset = Double.NEGATIVE_INFINITY;
173 protected boolean m_endClockwise = true;
174
175 public PositionPathConfigSegment(Element element) {
176 super(element);
177
178 ObjectUtil.initializeFieldStrict("startPathDef", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
179 ObjectUtil.initializeFieldStrict("endPathDef", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
180 ObjectUtil.initializeFieldStrict("startClockwise", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
181 ObjectUtil.initializeFieldStrict("startOffset", element, this, ObjectUtil.NORMALIZING_CONVERSION);
182 ObjectUtil.initializeFieldStrict("endClockwise", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
183 ObjectUtil.initializeFieldStrict("endOffset", element, this, ObjectUtil.NORMALIZING_CONVERSION);
184 }
185
186 protected void addJarlObjectInfo(IJarlObjectInfo jarlObjectInfo) {
187 super.addJarlObjectInfo(jarlObjectInfo);
188
189 populateInfo(jarlObjectInfo, "startPathDef", "Start Path Definition", JarlInfoUtil.PRIMITIVE_DISPLAY);
190 populateInfo(jarlObjectInfo, "startClockwise", "Start Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
191 populateInfo(jarlObjectInfo, "endClockwise", "End Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
192 populateInfo(jarlObjectInfo, "endPathDef", "End Path Definition", JarlInfoUtil.PRIMITIVE_DISPLAY);
193 populateInfo(jarlObjectInfo, "startOffset", "Start Offset", JarlInfoUtil.PCT_DISPLAY);
194 populateInfo(jarlObjectInfo, "endOffset", "End Offset", JarlInfoUtil.PCT_DISPLAY);
195 }
196
197 public String getStartPathDef() {
198 return m_startPathDef;
199 }
200
201 public String getEndPathDef() {
202 return m_endPathDef;
203 }
204
205 public double getStartOffset() {
206 return m_startOffset;
207 }
208
209 public boolean isStartClockwise() {
210 return m_startClockwise;
211 }
212
213 public double getEndOffset() {
214 return m_endOffset;
215 }
216
217 public boolean isEndClockwise() {
218 return m_endClockwise;
219 }
220 }
221 }