1
2
3
4
5
6
7
8 package com.extjs.gxt.ui.client.fx;
9
10 import com.extjs.gxt.ui.client.Style;
11 import com.extjs.gxt.ui.client.core.El;
12 import com.extjs.gxt.ui.client.core.XDOM;
13 import com.extjs.gxt.ui.client.event.BaseObservable;
14 import com.extjs.gxt.ui.client.event.ComponentEvent;
15 import com.extjs.gxt.ui.client.event.DragEvent;
16 import com.extjs.gxt.ui.client.event.DragListener;
17 import com.extjs.gxt.ui.client.event.Events;
18 import com.extjs.gxt.ui.client.event.Listener;
19 import com.extjs.gxt.ui.client.event.PreviewEvent;
20 import com.extjs.gxt.ui.client.util.BaseEventPreview;
21 import com.extjs.gxt.ui.client.util.Rectangle;
22 import com.extjs.gxt.ui.client.widget.Component;
23 import com.extjs.gxt.ui.client.widget.Shim;
24 import com.google.gwt.event.dom.client.KeyCodes;
25 import com.google.gwt.user.client.DOM;
26 import com.google.gwt.user.client.Element;
27 import com.google.gwt.user.client.Event;
28 import com.google.gwt.user.client.Window;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public class Draggable extends BaseObservable {
78
79 protected int conX, conY, conWidth, conHeight;
80 protected int dragStartX, dragStartY;
81 protected int lastX, lastY;
82 protected Rectangle startBounds;
83 protected El proxyEl;
84
85
86 private boolean updateZIndex = true;
87 private boolean sizeProxyToSource = true;
88 private boolean constrainHorizontal;
89 private boolean moveAfterProxyDrag = true;
90 private boolean constrainVertical;
91 private boolean constrainClient = true;
92 private boolean useProxy = true;
93 private int xLeft = Style.DEFAULT, xRight = Style.DEFAULT;
94 private int xTop = Style.DEFAULT, xBottom = Style.DEFAULT;
95 private String proxyStyle = "x-drag-proxy";
96 private Component container;
97 private Component dragWidget;
98 private Component handle;
99 private boolean dragging;
100 private boolean enabled = true;
101 private int clientWidth, clientHeight;
102 private BaseEventPreview preview;
103 private DragEvent dragEvent;
104 private int startDragDistance = 2;
105 private Listener<ComponentEvent> listener;
106
107
108
109
110
111
112 public Draggable(Component dragComponent) {
113 this(dragComponent, dragComponent);
114 }
115
116
117
118
119
120
121
122 public Draggable(final Component dragComponent, final Component handle) {
123 listener = new Listener<ComponentEvent>() {
124 public void handleEvent(ComponentEvent ce) {
125 onMouseDown(ce);
126 }
127 };
128 this.dragWidget = dragComponent;
129 this.handle = handle;
130
131 handle.addListener(Events.OnMouseDown, listener);
132
133 preview = new BaseEventPreview() {
134
135 @Override
136 public boolean onPreview(PreviewEvent event) {
137 event.preventDefault();
138 switch (event.getEventTypeInt()) {
139 case Event.ONKEYDOWN:
140 if (dragging && event.getKeyCode() == KeyCodes.KEY_ESCAPE) {
141 cancelDrag();
142 }
143 break;
144 case Event.ONMOUSEMOVE:
145 onMouseMove(event.getEvent());
146 break;
147 case Event.ONMOUSEUP:
148 stopDrag(event.getEvent());
149 break;
150 }
151 return true;
152 }
153
154 };
155 preview.setAutoHide(false);
156
157 handle.sinkEvents(Event.ONMOUSEDOWN);
158 }
159
160
161
162
163
164
165 public void addDragListener(DragListener listener) {
166 addListener(Events.DragStart, listener);
167 addListener(Events.DragMove, listener);
168 addListener(Events.DragCancel, listener);
169 addListener(Events.DragEnd, listener);
170 }
171
172
173
174
175 public void cancelDrag() {
176 preview.remove();
177 if (dragging) {
178 dragging = false;
179 if (isUseProxy()) {
180 proxyEl.disableTextSelection(false);
181 proxyEl.setVisibility(false);
182 proxyEl.remove();
183 } else {
184 dragWidget.el().setPagePosition(startBounds.x, startBounds.y);
185 }
186
187 fireEvent(Events.DragCancel, new DragEvent(this));
188 afterDrag();
189 }
190 }
191
192
193
194
195
196
197 public Component getContainer() {
198 return container;
199 }
200
201
202
203
204
205
206 public Component getDragHandle() {
207 return handle;
208 }
209
210
211
212
213
214
215 public Component getDragWidget() {
216 return dragWidget;
217 }
218
219
220
221
222
223
224 public String getProxyStyle() {
225 return proxyStyle;
226 }
227
228
229
230
231
232
233 public int getStartDragDistance() {
234 return startDragDistance;
235 }
236
237
238
239
240
241
242 public boolean isConstrainClient() {
243 return constrainClient;
244 }
245
246
247
248
249
250
251 public boolean isConstrainHorizontal() {
252 return constrainHorizontal;
253 }
254
255
256
257
258
259
260 public boolean isConstrainVertical() {
261 return constrainVertical;
262 }
263
264
265
266
267
268
269 public boolean isDragging() {
270 return dragging;
271 }
272
273
274
275
276
277
278 public boolean isEnabled() {
279 return enabled;
280 }
281
282
283
284
285
286
287 public boolean isMoveAfterProxyDrag() {
288 return moveAfterProxyDrag;
289 }
290
291
292
293
294
295
296 public boolean isSizeProxyToSource() {
297 return sizeProxyToSource;
298 }
299
300
301
302
303
304
305 public boolean isUpdateZIndex() {
306 return updateZIndex;
307 }
308
309
310
311
312
313
314 public boolean isUseProxy() {
315 return useProxy;
316 }
317
318
319
320
321 public void release() {
322 cancelDrag();
323 handle.removeListener(Events.OnMouseDown, listener);
324 }
325
326
327
328
329
330
331 public void removeDragListener(DragListener listener) {
332 if (hasListeners()) {
333 removeListener(Events.DragStart, listener);
334 removeListener(Events.DragMove, listener);
335 removeListener(Events.DragCancel, listener);
336 removeListener(Events.DragEnd, listener);
337 }
338 }
339
340
341
342
343
344
345 public void setConstrainClient(boolean constrainClient) {
346 this.constrainClient = constrainClient;
347 }
348
349
350
351
352
353
354 public void setConstrainHorizontal(boolean constrainHorizontal) {
355 this.constrainHorizontal = constrainHorizontal;
356 }
357
358
359
360
361
362
363 public void setConstrainVertical(boolean constrainVertical) {
364 this.constrainVertical = constrainVertical;
365 }
366
367
368
369
370
371
372 public void setContainer(Component container) {
373 this.container = container;
374 }
375
376
377
378
379
380
381
382 public void setEnabled(boolean enabled) {
383 this.enabled = enabled;
384 }
385
386
387
388
389
390
391 public void setMoveAfterProxyDrag(boolean moveAfterProxyDrag) {
392 this.moveAfterProxyDrag = moveAfterProxyDrag;
393 }
394
395
396
397
398
399
400 public void setProxy(El element) {
401 proxyEl = element;
402 }
403
404
405
406
407
408
409 public void setProxyStyle(String proxyStyle) {
410 this.proxyStyle = proxyStyle;
411 }
412
413
414
415
416
417
418
419 public void setSizeProxyToSource(boolean sizeProxyToSource) {
420 this.sizeProxyToSource = sizeProxyToSource;
421 }
422
423
424
425
426
427
428
429 public void setStartDragDistance(int startDragDistance) {
430 this.startDragDistance = startDragDistance;
431 }
432
433
434
435
436
437
438
439
440 public void setUpdateZIndex(boolean updateZIndex) {
441 this.updateZIndex = updateZIndex;
442 }
443
444
445
446
447
448
449 public void setUseProxy(boolean useProxy) {
450 this.useProxy = useProxy;
451 }
452
453
454
455
456
457
458
459 public void setXConstraint(int left, int right) {
460 xLeft = left;
461 xRight = right;
462 }
463
464
465
466
467
468
469
470 public void setYConstraint(int top, int bottom) {
471 xTop = top;
472 xBottom = bottom;
473 }
474
475 protected void afterDrag() {
476 XDOM.getBodyEl().removeStyleName("x-unselectable");
477 XDOM.getBodyEl().removeStyleName("x-dd-cursor");
478 Shim.get().uncover();
479 }
480
481 protected El createProxy() {
482 proxyEl = new El(DOM.createDiv());
483 proxyEl.setVisibility(false);
484 proxyEl.dom.setClassName(getProxyStyle());
485 proxyEl.disableTextSelection(true);
486 return proxyEl;
487 }
488
489 protected void onMouseDown(ComponentEvent ce) {
490 if (!enabled || ce.getEvent().getButton() != Event.BUTTON_LEFT) {
491 return;
492 }
493 Element target = ce.getTarget();
494 String s = DOM.getElementProperty(target, "className");
495 if (s != null && s.indexOf("x-nodrag") != -1) {
496 return;
497 }
498
499
500 if ((!"input".equalsIgnoreCase(ce.getTarget().getTagName()) && !"textarea".equalsIgnoreCase(ce.getTarget().getTagName()))
501 || ce.getTarget().getPropertyBoolean("disabled")) {
502 ce.preventDefault();
503 }
504
505 startBounds = dragWidget.el().getBounds();
506
507 dragStartX = ce.getClientX();
508 dragStartY = ce.getClientY();
509
510 preview.add();
511
512 clientWidth = Window.getClientWidth() + XDOM.getBodyScrollLeft();
513 clientHeight = Window.getClientHeight() + XDOM.getBodyScrollTop();
514
515 if (container != null) {
516 conX = container.getAbsoluteLeft();
517 conY = container.getAbsoluteTop();
518 conWidth = container.getOffsetWidth();
519 conHeight = container.getOffsetHeight();
520 }
521
522 if (startDragDistance == 0) {
523 startDrag(ce.getEvent());
524 }
525
526 }
527
528 protected void onMouseMove(Event event) {
529 Element elem = event.getEventTarget().cast();
530
531
532 if (hasAttribute(elem, "class")) {
533
534
535 String cls = El.getClassName(((Element) event.getEventTarget().cast()));
536
537
538 if (cls != null && cls.contains("x-insert")) {
539 return;
540 }
541 }
542
543 int x = DOM.eventGetClientX(event);
544 int y = DOM.eventGetClientY(event);
545
546 if (!dragging && (Math.abs(dragStartX - x) > startDragDistance || Math.abs(dragStartY - y) > startDragDistance)) {
547 startDrag(event);
548 }
549
550 if (dragging) {
551 int left = constrainHorizontal ? startBounds.x : startBounds.x + (x - dragStartX);
552 int top = constrainVertical ? startBounds.y : startBounds.y + (y - dragStartY);
553
554 if (constrainClient) {
555 if (!constrainHorizontal) {
556 int width = startBounds.width;
557 left = Math.max(left, 0);
558 left = Math.max(0, Math.min(clientWidth - width, left));
559 }
560 if (!constrainVertical) {
561 top = Math.max(top, 0);
562 int height = startBounds.height;
563 if (Math.min(clientHeight - height, top) > 0) {
564 top = Math.max(2, Math.min(clientHeight - height, top));
565 }
566 }
567 }
568
569 if (container != null) {
570 int width = startBounds.width;
571 int height = startBounds.height;
572 if (!constrainHorizontal) {
573 left = Math.max(left, conX);
574 left = Math.min(conX + conWidth - width, left);
575 }
576 if (!constrainVertical) {
577 top = Math.min(conY + conHeight - height, top);
578 top = Math.max(top, conY);
579 }
580 }
581 if (!constrainHorizontal) {
582 if (xLeft != Style.DEFAULT) {
583 left = Math.max(startBounds.x - xLeft, left);
584 }
585 if (xRight != Style.DEFAULT) {
586 left = Math.min(startBounds.x + xRight, left);
587 }
588 }
589
590 if (!constrainVertical) {
591 if (xTop != Style.DEFAULT) {
592 top = Math.max(startBounds.y - xTop, top);
593 }
594 if (xBottom != Style.DEFAULT) {
595 top = Math.min(startBounds.y + xBottom, top);
596 }
597 }
598
599 lastX = left;
600 lastY = top;
601
602 dragEvent.setSource(this);
603 dragEvent.setComponent(dragWidget);
604 dragEvent.setEvent(event);
605 dragEvent.setCancelled(false);
606 dragEvent.setX(lastX);
607 dragEvent.setY(lastY);
608 fireEvent(Events.DragMove, dragEvent);
609
610 if (dragEvent.isCancelled()) {
611 cancelDrag();
612 return;
613 }
614
615 int tl = dragEvent.getX() != lastX ? dragEvent.getX() : lastX;
616 int tt = dragEvent.getY() != lastY ? dragEvent.getY() : lastY;
617 if (useProxy) {
618 proxyEl.setPagePosition(tl, tt);
619 } else {
620 dragWidget.el().setPagePosition(tl, tt);
621 }
622 }
623
624 }
625
626 protected void startDrag(Event event) {
627 DragEvent de = new DragEvent(this);
628 de.setComponent(dragWidget);
629 de.setEvent(event);
630 de.setX(startBounds.x);
631 de.setY(startBounds.y);
632
633 if (fireEvent(Events.DragStart, de)) {
634 dragging = true;
635 XDOM.getBodyEl().addStyleName("x-unselectable");
636 XDOM.getBodyEl().addStyleName("x-dd-cursor");
637 dragWidget.el().makePositionable();
638
639 event.preventDefault();
640
641 Shim.get().cover(true);
642
643 lastX = startBounds.x;
644 lastY = startBounds.y;
645
646 if (dragEvent == null) {
647 dragEvent = new DragEvent(this);
648 }
649
650 if (useProxy) {
651 if (proxyEl == null) {
652 createProxy();
653 }
654 if (container == null) {
655 XDOM.getBody().appendChild(proxyEl.dom);
656 } else {
657 container.el().appendChild(proxyEl.dom);
658 }
659 proxyEl.setVisibility(true);
660 proxyEl.setZIndex(XDOM.getTopZIndex());
661 proxyEl.makePositionable(true);
662
663 if (sizeProxyToSource) {
664 proxyEl.setBounds(startBounds);
665 } else {
666 proxyEl.setXY(startBounds.x, startBounds.y);
667 }
668
669
670 if (de.getHeight() > 0 && de.getWidth() > 0) {
671 proxyEl.setSize(de.getWidth(), de.getHeight(), true);
672 } else if (de.getHeight() > 0) {
673 proxyEl.setHeight(de.getHeight(), true);
674 } else if (de.getWidth() > 0) {
675 proxyEl.setWidth(de.getWidth(), true);
676 }
677 } else if (updateZIndex) {
678 dragWidget.setZIndex(XDOM.getTopZIndex());
679 }
680 } else {
681 cancelDrag();
682 }
683 }
684
685 protected void stopDrag(Event event) {
686 preview.remove();
687 if (dragging) {
688 dragging = false;
689 if (isUseProxy()) {
690 if (isMoveAfterProxyDrag()) {
691 Rectangle rect = proxyEl.getBounds();
692 dragWidget.el().setPagePosition(rect.x, rect.y);
693 }
694 proxyEl.setVisibility(false);
695 proxyEl.disableTextSelection(false);
696 proxyEl.remove();
697 }
698 DragEvent de = new DragEvent(this);
699 de.setComponent(dragWidget);
700 de.setEvent(event);
701 de.setX(lastX);
702 de.setY(lastY);
703 fireEvent(Events.DragEnd, de);
704 afterDrag();
705 }
706 }
707
708 private native boolean hasAttribute(Element elem, String name)
709
710 ;
711
712 }