1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jcurl.zui.piccolo;
20
21 import java.awt.BasicStroke;
22 import java.awt.Color;
23 import java.awt.Cursor;
24 import java.awt.Paint;
25 import java.awt.Shape;
26 import java.awt.Stroke;
27 import java.awt.geom.AffineTransform;
28 import java.awt.geom.Arc2D;
29 import java.awt.geom.Line2D;
30 import java.awt.geom.Point2D;
31 import java.beans.PropertyChangeEvent;
32 import java.beans.PropertyChangeListener;
33
34 import javax.swing.BoundedRangeModel;
35 import javax.swing.event.ChangeEvent;
36 import javax.swing.event.ChangeListener;
37
38 import org.apache.commons.logging.Log;
39 import org.jcurl.core.api.IceSize;
40 import org.jcurl.core.api.RockProps;
41 import org.jcurl.core.api.RockSet;
42 import org.jcurl.core.log.JCLoggerFactory;
43 import org.jcurl.core.ui.BroomPromptModel;
44 import org.jcurl.core.ui.ChangeManager;
45 import org.jcurl.core.ui.IceShapes;
46 import org.jcurl.core.ui.Memento;
47 import org.jcurl.core.ui.BroomPromptModel.HandleMemento;
48 import org.jcurl.core.ui.BroomPromptModel.SplitMemento;
49 import org.jcurl.core.ui.BroomPromptModel.XYMemento;
50 import org.jcurl.math.MathVec;
51
52 import edu.umd.cs.piccolo.PNode;
53 import edu.umd.cs.piccolo.event.PDragEventHandler;
54 import edu.umd.cs.piccolo.event.PInputEvent;
55 import edu.umd.cs.piccolo.nodes.PPath;
56 import edu.umd.cs.piccolo.util.PPaintContext;
57 import edu.umd.cs.piccolo.util.PPickPath;
58
59
60 public class BroomPromptSimple extends PNode implements PropertyChangeListener,
61 ChangeListener {
62 private static final Color dark = new IceShapes.RockColors().dark;
63 private static final Color light = new IceShapes.RockColors().light;
64 private static final Log log = JCLoggerFactory
65 .getLogger(BroomPromptSimple.class);
66 private static final Cursor MOVE_CURSOR = new Cursor(Cursor.MOVE_CURSOR);
67 private static final double scale0 = 0;
68 private static final int scale50 = 50;
69 private static final long serialVersionUID = 3115716478135484000L;
70 private static final Cursor UPDN_CURSOR = new Cursor(Cursor.N_RESIZE_CURSOR);
71
72
73
74
75
76
77
78
79
80
81 static PPath node(final Shape sh, final Stroke st, final Paint sp,
82 final double minScale) {
83 final PPath s = new PPath(sh, st) {
84 private static final long serialVersionUID = 5255259239579383074L;
85
86 @Override
87 public void paint(final PPaintContext aPaintContext) {
88 if (minScale >= 0) {
89 if (aPaintContext.getScale() < minScale)
90 return;
91 } else if (aPaintContext.getScale() > -minScale)
92 return;
93 super.paint(aPaintContext);
94 }
95 };
96
97 s.setStrokePaint(sp);
98 s.setPickable(false);
99 return s;
100 }
101
102 private ChangeManager changer = null;
103 private Memento first = null;
104 private final PNode handle;
105 private Memento last = null;
106 private BroomPromptModel model;
107 private final PNode pie;
108 private final PPath slider;
109 private final float stickLength;
110
111 public BroomPromptSimple() {
112 final boolean stickUp = false;
113 final boolean bothSides = true;
114 final int pieAngle = 150;
115 final Color sp = Color.BLACK;
116 final Color bgc = new Color(1, 1, 1, 0.5f);
117 final Stroke fine = new BasicStroke(0.01f, BasicStroke.CAP_BUTT,
118 BasicStroke.JOIN_MITER);
119 final Stroke bold = new BasicStroke(0.03f, BasicStroke.CAP_ROUND,
120 BasicStroke.JOIN_MITER);
121
122 final float halo = RockProps.DEFAULT.getRadius();
123 final float outer = 0.8f * RockProps.DEFAULT.getRadius();
124 stickLength = (stickUp ? 1 : -1) * 5 * outer;
125 final float inner = 0.5F * outer;
126 setPickable(false);
127 final BroomPromptSimple self = this;
128 handle = new PNode() {
129 private static final long serialVersionUID = -7641452321842902940L;
130
131
132
133
134
135
136
137
138
139 @Override
140 public boolean fullPick(final PPickPath pickPath) {
141 if (super.fullPick(pickPath)) {
142 PNode picked = pickPath.getPickedNode();
143
144
145
146 while (picked != self) {
147 pickPath.popTransform(picked
148 .getTransformReference(false));
149 pickPath.popNode(picked);
150 picked = pickPath.getPickedNode();
151 }
152 return true;
153 }
154 return false;
155 }
156 };
157 {
158 final PNode bg = node(new Arc2D.Float(-halo, -halo, 2 * halo,
159 2 * halo, 0, 360, Arc2D.OPEN), null, null, scale0);
160 bg.setPaint(bgc);
161 bg.setPickable(true);
162 handle.addChild(bg);
163 }
164 {
165 final int off = 90;
166 final int pieOff = 180;
167 final int arrowLengthDegrees = 7;
168
169 pie = node(new Arc2D.Float(-outer, -outer, 2 * outer, 2 * outer,
170 off - pieOff, pieAngle, Arc2D.PIE), null, null, scale0);
171 handle.addChild(pie);
172
173 handle.addChild(node(new Arc2D.Float(-inner, -inner, 2 * inner,
174 2 * inner, off, pieOff + pieAngle, Arc2D.OPEN), fine, sp,
175 scale50));
176
177 handle.addChild(node(new Arc2D.Float(-outer, -outer, 2 * outer,
178 2 * outer, off, pieOff + pieAngle
179 - (14 + arrowLengthDegrees), Arc2D.OPEN), fine, sp,
180 scale50));
181 handle.addChild(node(new Arc2D.Float(-outer, -outer, 2 * outer,
182 2 * outer, off, pieOff + pieAngle, Arc2D.OPEN), fine, sp,
183 -scale50));
184 final double ar = Math.PI * (off + pieAngle) / 180.0;
185
186
187 handle.addChild(node(new Line2D.Double(0, 0, -outer * Math.cos(ar),
188 outer * Math.sin(ar)), bold, sp, scale0));
189
190
191 final float f = outer / 10;
192 final PPath s = node(IceShapes.createArrowHead(f, 3 * f, 0.5f * f),
193 null, null, scale50);
194 s.setPaint(sp);
195 final double a = Math.PI * (off + pieAngle - arrowLengthDegrees)
196 / 180.0;
197 s.translate(-outer * Math.cos(a), outer * Math.sin(a));
198 s.rotate(Math.PI * (90 - (off + pieAngle) + 8 + arrowLengthDegrees)
199 / 180.0);
200 handle.addChild(s);
201
202 this.addChild(handle);
203 }
204 {
205 handle.addChild(node(new Line2D.Float(0, -Math.signum(stickLength)
206 * halo, 0, stickLength), fine, sp, scale0));
207
208 handle.addChild(node(new Line2D.Float(-halo, 0, halo, 0), fine, sp,
209 scale0));
210 }
211 {
212 slider = new PPath(IceShapes.createSlider(0.4f * outer, bothSides),
213 fine);
214 slider.setStrokePaint(sp);
215 slider.setPickable(true);
216 this.addChild(slider);
217 }
218
219 addInputEventListener(new PDragEventHandler() {
220
221
222 @Override
223 public void mouseClicked(final PInputEvent arg0) {
224 super.mouseClicked(arg0);
225 if (arg0.getClickCount() > 1) {
226 arg0.setHandled(true);
227 first = new HandleMemento(getModel(), getModel()
228 .getOutTurn());
229 last = new HandleMemento(getModel(), !getModel()
230 .getOutTurn());
231 ChangeManager.getTrivial(changer).undoable(first, last);
232 first = last = null;
233 }
234 }
235
236
237 @Override
238 public void mouseDragged(final PInputEvent arg0) {
239 arg0.setHandled(true);
240 getModel().setValueIsAdjusting(true);
241 if (false) {
242 final Point2D p = arg0.getPositionRelativeTo(self
243 .getParent());
244 getModel().setBroom(p);
245 } else
246 view2model(new XYMemento(getModel(), arg0
247 .getPositionRelativeTo(self.getParent())));
248 }
249
250 @Override
251 public void mouseEntered(final PInputEvent arg0) {
252 super.mouseEntered(arg0);
253 arg0.pushCursor(MOVE_CURSOR);
254 }
255
256 @Override
257 public void mouseExited(final PInputEvent arg0) {
258 super.mouseExited(arg0);
259 arg0.popCursor();
260 }
261
262 @Override
263 public void mousePressed(final PInputEvent arg0) {
264 arg0.setHandled(true);
265 first = new XYMemento(getModel(), getModel().getBroom());
266 }
267
268 @Override
269 public void mouseReleased(final PInputEvent pinputevent) {
270 getModel().setValueIsAdjusting(false);
271 if (first != null && last != null && first != last)
272 ChangeManager.getTrivial(changer).undoable(first, last);
273 first = last = null;
274 }
275 });
276 slider.addInputEventListener(new PDragEventHandler() {
277 @Override
278 protected void endDrag(final PInputEvent pinputevent) {
279 log.debug("speed");
280 }
281
282
283 @Override
284 public void mouseDragged(final PInputEvent arg0) {
285 arg0.setHandled(true);
286 final Point2D p = arg0.getPositionRelativeTo(self);
287 final BoundedRangeModel r = self.getModel()
288 .getSplitTimeMillis();
289 if (r == null)
290 return;
291 r.setValueIsAdjusting(true);
292 view2model(new SplitMemento(getModel(), ratio2value(p.getY()
293 / stickLength, r)));
294 }
295
296 @Override
297 public void mouseEntered(final PInputEvent arg0) {
298 super.mouseEntered(arg0);
299 arg0.pushCursor(UPDN_CURSOR);
300 }
301
302 @Override
303 public void mouseExited(final PInputEvent arg0) {
304 super.mouseExited(arg0);
305 arg0.popCursor();
306 }
307
308 @Override
309 public void mousePressed(final PInputEvent arg0) {
310 arg0.setHandled(true);
311 first = new SplitMemento(getModel(), getModel()
312 .getSplitTimeMillis().getValue());
313 }
314
315 @Override
316 public void mouseReleased(final PInputEvent pinputevent) {
317 log.debug("speed");
318 final BoundedRangeModel r = self.getModel()
319 .getSplitTimeMillis();
320 if (r == null)
321 return;
322 r.setValueIsAdjusting(false);
323 if (first != null && last != null && first != last)
324 ChangeManager.getTrivial(changer).undoable(first, last);
325 first = last = null;
326 }
327 });
328 }
329
330 private void adjustSlider(final BoundedRangeModel r) {
331
332 slider.setPaint(IceShapes.sliderColor(r));
333 slider.getTransformReference(true).setToTranslation(0,
334 stickLength * IceShapes.value2ratio(r));
335 slider.invalidateFullBounds();
336 slider.invalidatePaint();
337
338 }
339
340 public ChangeManager getChanger() {
341 return changer;
342 }
343
344 public BroomPromptModel getModel() {
345 return model;
346 }
347
348 public void propertyChange(final PropertyChangeEvent evt) {
349 log.debug(evt.getPropertyName());
350 if ("broom".equals(evt.getPropertyName()))
351 setBroom((Point2D) evt.getNewValue());
352 else if ("idx16".equals(evt.getPropertyName()))
353 setIdx16((Integer) evt.getNewValue());
354 else if ("outTurn".equals(evt.getPropertyName()))
355 setOutTurn((Boolean) evt.getNewValue());
356 else if ("splitTimeMillis".equals(evt.getPropertyName())) {
357 final BoundedRangeModel os = (BoundedRangeModel) evt.getOldValue();
358 if (os != null)
359 os.removeChangeListener(this);
360 setSlider((BoundedRangeModel) evt.getNewValue());
361 }
362 }
363
364 private int ratio2value(final double ra, final BoundedRangeModel r) {
365 return r.getMaximum() + (int) ((r.getMinimum() - r.getMaximum()) * ra);
366 }
367
368
369 private void setBroom(final Point2D b) {
370 if (b == null)
371 return;
372 final AffineTransform t = getTransformReference(true);
373 t.setToIdentity();
374 t.translate(b.getX(), b.getY());
375 MathVec.rotate(t, b.getX(), b.getY() - IceSize.FAR_HACK_2_TEE);
376 MathVec.rotate(t, 0, 1);
377 invalidateFullBounds();
378 invalidatePaint();
379 }
380
381 public void setChanger(final ChangeManager changer) {
382 final ChangeManager old = this.changer;
383 if (old == changer)
384 return;
385 this.changer = changer;
386
387 }
388
389
390 private void setIdx16(final int i) {
391 if (i < 0 || i >= RockSet.ROCKS_PER_SET)
392 pie.setPaint(null);
393 else
394 pie.setPaint(RockSet.isDark(i) ? dark : light);
395 pie.invalidatePaint();
396 }
397
398 public void setModel(final BroomPromptModel model) {
399 if (this.model == model)
400 return;
401 if (this.model != null) {
402 this.model.removePropertyChangeListener(this);
403 if (this.model.getSplitTimeMillis() != null)
404 this.model.getSplitTimeMillis().removeChangeListener(this);
405 }
406 this.model = model;
407 setVisible(this.model != null && model.getBroom() != null);
408 if (this.model != null) {
409 setBroom(this.model.getBroom());
410 setIdx16(this.model.getIdx16());
411 setOutTurn(this.model.getOutTurn());
412 setSlider(this.model.getSplitTimeMillis());
413 this.model.addPropertyChangeListener(this);
414 }
415 invalidatePaint();
416 }
417
418 private void setOutTurn(final boolean ot) {
419 handle.getTransformReference(true).setToScale(ot ? -1 : 1, 1);
420 handle.invalidatePaint();
421 }
422
423 private void setSlider(final BoundedRangeModel s) {
424 slider.setVisible(s != null);
425 if (s == null)
426 return;
427 s.addChangeListener(this);
428 adjustSlider(s);
429 }
430
431 public void stateChanged(final ChangeEvent e) {
432
433 if (e.getSource() instanceof BoundedRangeModel)
434 adjustSlider((BoundedRangeModel) e.getSource());
435 }
436
437 private void view2model(final Memento<?> m) {
438 ChangeManager.getTrivial(changer).temporary(last = m);
439 }
440 }