1
6 import java.awt.geom.*;
7 import java.awt.Graphics2D;
8 import javax.swing.*;
9 import java.util.*;
10
11 public abstract class Sub extends Symbol implements DragableSymbol,Aligner {
12
13 private static final long serialVersionUID = Version.getSUID();
14
15 static double MINR = 2;
16
17 public ViewTransform relativepos = null;
18 public PointSym anchorpoint = new PointSym();
19
20 public SavableRectangle2D box;
21
22 transient public ViewTransform pos = null;
23 transient public Point2D[] corners;
24
25 public double handley = 0;
26 public double handlex = 0;
27
28 transient Point2D origin = new Point2D.Double();
29
30 transient boolean brandnew = true;
31
32 public boolean editaspect = false;
33
34 public boolean editrotation = true;
35 public boolean editscale = true;
36 public boolean showcorners = true;
37
38
39 public boolean sizewidth = true;
40
41 public double subaspect = 1;
42 public Size size = Size.none;
43
44 transient boolean located = false;
45
46 public void copy(Sub that) {
47 handley = that.handley;
48 handlex = that.handlex;
49
50 editaspect = that.editaspect;
51 editrotation = that.editrotation;
52 editscale = that.editscale;
53 showcorners = that.showcorners;
54 sizewidth = that.sizewidth;
55
56 subaspect = that.subaspect;
57 size = that.size;
58 }
59
60 public Sub(){
61 anchorpoint.getAlignTransform().addAlignmentListener(this);
62 }
63
64 public Sub(Point2D where,View view,Object arg) {
65 anchorpoint.getAlignTransform().addAlignmentListener(this);
66 if (arg instanceof Rectangle2D) {
67 located=false;
68 box = new SavableRectangle2D((Rectangle2D)arg);
69 }
70 }
71
72
73
74
75
76 public void alignmentChanged(){
77 located = false;
78 }
79
80
81
82 transient JRadioButton widthf=null;
83 transient JRadioButton heightf=null;
84 transient JComboBox sizefield=null;
85
86 transient JComboBox editmodef = null;
87
88 transient JRadioButton topf=null;
89 transient JRadioButton botf=null;
90 transient JRadioButton leftf=null;
91 transient JRadioButton rightf=null;
92
93
96 protected Vector getEditModes() {
97 Vector res = new Vector();
98 res.add("Translate");
99 res.add("Rotate");
100
101 res.add("Scale");
102 res.add("Scale & Rotate");
103
104 return(res);
105 }
106
107 public int getLevel() {return(super.getLevel()+1);}
108
109 public void getPropertyEdit(Object[] edits,int slot,Set sub,Symbol parent) {
110 located=false;
111 locate();
112 JPanel res = new JPanel();
113 edits[slot] = res;
114 ((java.awt.Component)edits[slot]).setName("Group");
115 res.setLayout(new BoxLayout(res,BoxLayout.Y_AXIS));
116
117 JPanel row = new JPanel();
118 row.setLayout(new BoxLayout(row,BoxLayout.X_AXIS));
119
120 Object[] editmodes = getEditModes().toArray();
121 editmodef = new JComboBox(editmodes);
122 for (int i=0;i<editmodes.length;i++)
123 if ((editscale || ((String)editmodes[i]).indexOf("Scale")<0) &&
124 (editrotation || ((String)editmodes[i]).indexOf("Rotate")<0) &&
125 (editaspect || ((String)editmodes[i]).indexOf("Aspect")<0))
126 editmodef.setSelectedIndex(i);
127
128 JPanel modebox = new JPanel();
129 modebox.add(new JLabel("Edit Mode"));
130 modebox.add(editmodef);
131 row.add(modebox);
132
133
134
135
136
137 res.add(row);
138
139
140
141 res.add(anchorpoint.pointPropertyEdit());
142
143 row = new JPanel();
144 row.setLayout(new BoxLayout(row,BoxLayout.X_AXIS));
145 row.add(new JLabel("Handle:"));
146 JPanel col = new JPanel();
147 col.setLayout(new java.awt.GridLayout(1,6));
148 ButtonGroup group = new ButtonGroup();
149
150 topf = new JRadioButton("Top",handley==1);
151 group.add(topf);
152 col.add(topf);
153 JRadioButton midf = new JRadioButton("Mid",handley==0);
154 group.add(midf);
155 col.add(midf);
156 botf = new JRadioButton("Bottom",handley==-11);
157 group.add(botf);
158 col.add(botf);
159
160 group = new ButtonGroup();
161 leftf = new JRadioButton("Left",handlex==-1);
162 group.add(leftf);
163 col.add(leftf);
164 midf = new JRadioButton("Mid",handlex==0);
165 group.add(midf);
166 col.add(midf);
167 rightf = new JRadioButton("Right",handlex==1);
168 group.add(rightf);
169 col.add(rightf);
170
171 row.add(col);
172 res.add(row);
173
174 row = new JPanel();
175 row.setLayout(new BoxLayout(row,BoxLayout.X_AXIS));
176 widthf = new JRadioButton("Width",sizewidth);
177 heightf = new JRadioButton("Height",!sizewidth);
178
179 row.add(widthf);
180 row.add(heightf);
181
182 group = new ButtonGroup();
183 group.add(widthf);
184 group.add(heightf);
185
186 row.add(new JLabel("Size "));
187 sizefield = new JComboBox(Size.getAll(Size.class));
188 sizefield.setSelectedItem(size);
189 row.add(sizefield);
190
191 res.add(row);
192
193 super.getPropertyEdit(edits,slot-1,sub,parent);
194 }
195
196 public void acceptPropertyEdit() {
197 if (widthf!=null) {
198 String editmode = (String)editmodef.getSelectedItem();
199 editscale = editmode.indexOf("Scale")>=0;
200 editrotation = editmode.indexOf("Rotate")>=0;
201 editaspect = editmode.indexOf("Aspect")>=0;
202
203
204
205
206 if (topf.isSelected()) handley = 1;
207 else if (botf.isSelected()) handley = -1;
208 else handley = 0;
209
210 if (leftf.isSelected()) handlex = -1;
211 else if (rightf.isSelected()) handlex = 1;
212 else handlex = 0;
213
214 sizewidth = widthf.isSelected();
215 size = (Size)sizefield.getSelectedItem();
216 if (size!=null && !size.equals(Size.none)) editscale = false;
217 anchorpoint.acceptPropertyEdit();
218
219 clear();
220 }
221 super.acceptPropertyEdit();
222 located = false;
223 reshape();
224
225 }
226
227 void clear() {
228 editmodef = null;
229 sizefield = null;
230
231
232 widthf = null;
233 heightf = null;
234 topf = null;
235 botf = null;
236 leftf = null;
237 rightf = null;
238
239 }
240
241 public void abandonPropertyEdit() {
242 clear();
243 anchorpoint.abandonPropertyEdit();
244 super.abandonPropertyEdit();
245 }
246
247 void init(Point2D where,View view) {
248 anchorpoint.position.setLocation(where);
249 located=false;
250
251 locate();
252 }
253
254 public ViewTransform getAlignTransform() {
255 locate();
256 return(anchorpoint.position);
257 }
258
259
260
261 public void locate() {
262 if (located) return;
263 located = true;
264
265 if (box==null) {
266 box = new SavableRectangle2D(-0.5,-0.5,1,1);
267 reshape();
268 }
269
270 origin = new Point2D.Double(box.getX()+(handlex+1)*box.getWidth()/2,
271 box.getY()+(handley+1)*box.getHeight()/2);
272
273 if (pos==null) pos = new ViewTransform();
274
275 pos.setToTranslation(-origin.getX(),-origin.getY());
276
277 pos.preConcatenate(anchorpoint.position);
278
279
280
281 if (corners==null) {
282 corners = new Point2D.Double[4];
283 for (int i=0;i<4;i++) corners[i] = new Point2D.Double();
284 }
285
286 corners[0].setLocation(box.getMinX(),box.getMinY());
287 corners[1].setLocation(box.getMaxX(),box.getMinY());
288 corners[2].setLocation(box.getMaxX(),box.getMaxY());
289 corners[3].setLocation(box.getMinX(),box.getMaxY());
290
291 for (int i=0;i<4;i++) pos.transform(corners[i],corners[i]);
292
293
294 }
295
296
297
298
299
300
301
302 private void readObject(java.io.ObjectInputStream stream)
303 throws java.io.IOException,java.lang.ClassNotFoundException {
304 stream.defaultReadObject();
305 brandnew = false;
306
307 if (relativepos!=null) {
308 anchorpoint.position = relativepos;
309 relativepos = null;
310 }
311
312 if ((this instanceof Page) &&
313 ((Page)this).aspect != -1 &&
314 ((Page)this).aspect != 0) {
315 subaspect = ((Page)this).aspect;
316 ((Page)this).aspect = -1;
317 }
318
319 if (subaspect==0)
320 subaspect = 1.0;
321
322 if (size==null) size=Size.none;
323
324 located = false;
325 }
326
327 public Rectangle2D getBounds(AffineTransform trans) {
328 locate();
329
330 Point2D.Double corn = new Point2D.Double();
331 trans.transform(corners[0],corn);;
332 Point2D.Double min = (Point2D.Double)corn.clone();
333 Point2D.Double max = (Point2D.Double)corn.clone();
334
335 for (int i=1;i<4;i++) {
336 trans.transform(corners[i],corn);;
337 if (corn.x<min.x) min.x = corn.x;
338 if (corn.y<min.y) min.y = corn.y;
339 if (corn.x>max.x) max.x = corn.x;
340 if (corn.y>max.y) max.y = corn.y;
341 }
342 return(new Rectangle2D.Double(min.x,min.y,max.x-min.x,max.y-min.y));
343 }
344
345 public java.awt.Shape getShape(AffineTransform trans) {
346 locate();
347
348 return(trans.createTransformedShape(pos.createTransformedShape(box)));
349 }
350
351 transient double csize = 0;
352
353 public void checkSize(View view) {
354 if (size !=null && size!=Size.none) {
355 if (origin==null) locate();
356 csize = getScale(size,view);
357 if (csize!=0) anchorpoint.position.setScale(csize/view.scale,0,0);
358 located = false;
359 }
360 }
361
362 public void paint(View view) {
363 if (!view.visible.isMember(this)) return;
364
365 checkSize(view);
366 if (csize==0) return;
367
368 locate();
369 view.push(pos);
370
371
372
373
374
375
376
377
378
379 paintContents(view);
380 view.pop();
381 }
382
383 public double getScale(Size size,View view) {
384
385
386
387
388
389 return(size.getSize(view.mapscale)/(sizewidth?box.getWidth():box.getHeight()));
390 }
391
392 public abstract void paintContents(View view);
393
394 Point2D getPolar(Point2D p,View v) {
395 double r = anchorpoint.position.distance(p);
396
397 if (r==0) return(new Point2D.Double(MINR/v.scale,0));
398 else return(new Point2D.Double(r,-Math.atan2(p.getX()-anchorpoint.position.getTranslateX(),
399 p.getY()-anchorpoint.position.getTranslateY())));
400 }
401
402 public boolean selectProbe(Point2D pos,View view){
403
404 brandnew = false;
405 if (anchorpoint.selectProbe(pos,view)) return(true);
406 double BOXSIZE = Size.handle.getSize(view.mapscale);
407 for (int i=0;i<4;i++)
408 if (pos.distance(corners[i].getX(),corners[i].getY())<BOXSIZE/view.scale) return(true);
409
410 return(false);
411 }
412
413 transient boolean cornerdrag = false;
414 transient Point2D dragpos = null;
415
416 public void startDrag(int command,Point2D where,View view){
417
418 cornerdrag = false;
419 int i=4;
420
421 if (brandnew) {
422 checkSize(view);
423 showSelected(view);
424 where = corners[0];
425 }
426
427 if ((brandnew || !anchorpoint.selectProbe(where,view)) && (editrotation || editscale || editaspect))
428 for (i=0;i<4;i++)
429 if (where.distance(corners[i].getX(),corners[i].getY())<Size.handle.getSize(view.mapscale)/view.scale ||
430 brandnew) {
431 cornerdrag = true;
432 if (editaspect)
433 dragpos = new Point2D.Double(where.getX()-anchorpoint.position.getTranslateX(),
434 where.getY()-anchorpoint.position.getTranslateY());
435 else {
436 dragpos = getPolar(where,view);
437 }
438 break;
439 }
440 if (i==4) dragpos = where;
441 }
442
443 public void drag(int command,Point2D where,View view){
444
445 showSelected(view);
446 located = false;
447 if (cornerdrag) {
448 Point2D newpos = null;
449 if (editaspect) {
450 double c,s;
451 newpos = new Point2D.Double(where.getX()-anchorpoint.position.getTranslateX(),
452 where.getY()-anchorpoint.position.getTranslateY());
453 if (!sizewidth&& size!=null && !size.equals(Size.none)) {
454 c = -Math.cos(-anchorpoint.position.angle);
455 s = Math.sin(-anchorpoint.position.angle);
456 subaspect /= (c*newpos.getX()+s*newpos.getY())/(c*dragpos.getX()+s*dragpos.getY());
457 anchorpoint.position.setScale(anchorpoint.position.scale*(c*newpos.getX()+s*newpos.getY())/
458 (c*dragpos.getX()+s*dragpos.getY()),0,0);
459 }
460 else {
461 s = Math.cos(-anchorpoint.position.angle);
462 c = Math.sin(-anchorpoint.position.angle);
463 double fact;
464 if (editscale) {
465 fact = (-s*newpos.getX()+c*newpos.getY())/
466 (-s*dragpos.getX()+c*dragpos.getY());
467 anchorpoint.position.setScale(anchorpoint.position.scale*fact
468 ,0,0);
469 } else fact = 1.0;
470 subaspect *= (c*newpos.getX()+s*newpos.getY())/(c*dragpos.getX()+s*dragpos.getY())/fact;
471 }
472 reshape();
473 }
474 else {
475 newpos = getPolar(where,view);
476 if (editscale)
477 anchorpoint.position.setScale(anchorpoint.position.scale*newpos.getX()/dragpos.getX(),
478 0,0);
479 if (editrotation)
480 anchorpoint.position.setRotation(anchorpoint.position.angle+newpos.getY()-dragpos.getY(),
481 0,0);
482 }
483 dragpos=newpos;
484 } else {
485 anchorpoint.position.preConcatenate(new AffineTransform(1,0,0,1,
486 where.getX()-dragpos.getX(),
487 where.getY()-dragpos.getY()));
488 dragpos=where;
489 }
490 showSelected(view);
491 }
492
493 public void endDrag(int comand,Point2D pos,View view){
494 located=false;
495
496 anchorpoint.position.notifyChange();
497 }
498
499 public void showSelected(View view) {
500 int BOXSIZE = (int)Size.handle.getSize(view.mapscale);
501 Point2D tpos = new Point2D.Double();
502 Point2D cpos = new Point2D.Double();
503 Graphics2D g;
504 int arrows=0;
505 double c=0,s=0;
506 g = view.draw;
507 locate();
508 anchorpoint.position.transformOrigin(view.trans,cpos);
509
510 g.drawRect((int)(cpos.getX()-BOXSIZE),(int)(cpos.getY()-BOXSIZE),2*BOXSIZE,2*BOXSIZE);
511
512 for (int i=0;i<4;i++) {
513 arrows = 0;
514 view.trans.transform(corners[i],tpos);
515 g.drawRect((int)(tpos.getX()-BOXSIZE),(int)(tpos.getY()-BOXSIZE),2*BOXSIZE,2*BOXSIZE);
516 if (editaspect) {
517 arrows = (editscale?2:1);
518 if (!sizewidth&& size!=null && !size.equals(Size.none)) {
519 c = Math.cos(-view.angle-anchorpoint.position.angle);
520 s = Math.sin(-view.angle-anchorpoint.position.angle);
521 }
522 else {
523 s = -Math.cos(view.angle-anchorpoint.position.angle);
524 c = Math.sin(view.angle-anchorpoint.position.angle);
525 }
526 }
527 else if (editrotation) {
528 arrows = (editscale?2:1);
529 c = tpos.getY()-cpos.getY();
530 s = -(tpos.getX()-cpos.getX());
531 double fact = Math.sqrt(c*c+s*s);
532 c/=fact;
533 s/=fact;
534 }
535 else if (editscale) {
536 arrows = 1;
537 s = tpos.getY()-cpos.getY();
538 c = tpos.getX()-cpos.getX();
539 double fact = Math.sqrt(c*c+s*s);
540 c/=fact;
541 s/=fact;
542 }
543
544 if (arrows>0) {
545 g.drawLine((int)(tpos.getX()-BOXSIZE*c*2),(int)(tpos.getY()-BOXSIZE*s*2),
546 (int)(tpos.getX()+BOXSIZE*c*2),(int)(tpos.getY()+BOXSIZE*s*2));
547 }
548 if (arrows>1) {
549 g.drawLine((int)(tpos.getX()+BOXSIZE*s*2),(int)(tpos.getY()-BOXSIZE*c*2),
550 (int)(tpos.getX()-BOXSIZE*s*2),(int)(tpos.getY()+BOXSIZE*c*2));
551 }
552 }
553
554 }
555
556 public void reshape() {
557 double oldheight = box.getHeight();
558 box.height = subaspect*box.getWidth();
559 box.x = -box.getWidth()/2;
560 box.y = -box.getHeight()/2;
561 located = false;
562
563 }
564
565 public void showAlignee(View view) {
566 anchorpoint.showAlignee(view);
567 }
568
569 public Point2D showAligner(View view) {
570 return(anchorpoint.showAligner(view));
571 }
572 }
573