001 /*
002 * Copyright 2006 Mat Gessel <mat.gessel@gmail.com>
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package asquare.gwt.tk.client.ui.behavior;
017
018 import asquare.gwt.tk.client.util.DomUtil;
019
020 import com.google.gwt.user.client.DOM;
021 import com.google.gwt.user.client.Event;
022 import com.google.gwt.user.client.ui.Widget;
023
024 /**
025 * A controller which interprets drag events and delegates the mouse drag
026 * operation to a delegate.
027 *
028 * @see asquare.gwt.tk.client.ui.behavior.DragGesture
029 */
030 public class DragController extends ControllerAdaptor
031 {
032 private final DragGesture m_dragGesture;
033 private final int m_threshold;
034
035 private boolean m_mouseDown = false;
036 private boolean m_dragging = false;
037 private int m_downX, m_downY;
038
039 /**
040 * Creates a new DragController which delegates to the specified
041 * DragGesture.
042 *
043 * @param gesture a delegate object
044 */
045 public DragController(DragGesture gesture)
046 {
047 this(gesture, 0);
048 }
049
050 /**
051 * Creates a new DragController which delegates to the specified
052 * DragGesture. The DragGesture is not activated until the mouse movement
053 * equals the specified distance; this prevents accidental movement.
054 *
055 * @param distance the distance in screen pixels to move before taking an
056 * action, or <code>0</code>
057 * @param gesture a delegate object
058 */
059 public DragController(DragGesture gesture, int distance)
060 {
061 super(Event.ONMOUSEDOWN | Event.ONMOUSEMOVE | Event.ONMOUSEUP, DragController.class);
062 m_dragGesture = gesture;
063 m_threshold = distance;
064 }
065
066 /*
067 * (non-Javadoc)
068 * @see asquare.gwt.tk.client.ui.behavior.EventDelegateAdaptor#doBrowserEvent(com.google.gwt.user.client.ui.Widget, com.google.gwt.user.client.Event)
069 */
070 public void onBrowserEvent(Widget widget, Event event)
071 {
072 // translate the coordinates into the source widget's coordinate space
073 // see MouseListenerCollection.fireMouseEvent()
074 int sourceX = DomUtil.eventGetAbsoluteX(event) - DOM.getAbsoluteLeft(widget.getElement());
075 int sourceY = DomUtil.eventGetAbsoluteY(event) - DOM.getAbsoluteTop(widget.getElement());
076
077 switch(DOM.eventGetType(event))
078 {
079 case Event.ONMOUSEDOWN:
080 onMouseDown(widget, sourceX, sourceY);
081 break;
082
083 case Event.ONMOUSEMOVE:
084 onMouseMove(widget, sourceX, sourceY);
085 break;
086
087 case Event.ONMOUSEUP:
088 onMouseUp(widget, sourceX, sourceY);
089 break;
090 }
091 }
092
093 private boolean equalsThreshold(int x, int y)
094 {
095 return Math.abs(x - m_downX) >= m_threshold || Math.abs(y - m_downY) >= m_threshold;
096 }
097
098 private void doStartDrag(Widget sender, int x, int y)
099 {
100 m_dragging = true;
101 m_dragGesture.start(x, y);
102 }
103
104 public void onMouseDown(Widget sender, int x, int y)
105 {
106 // Debug.println("DragController.onMouseDown(x=" + x + ",y=" + y + ")");
107 DOM.setCapture(sender.getElement());
108 m_downX = x;
109 m_downY = y;
110 m_mouseDown = true;
111 if (equalsThreshold(x, y))
112 {
113 doStartDrag(sender, x, y);
114 }
115 }
116
117 public void onMouseMove(Widget sender, int x, int y)
118 {
119 // Debug.println("DragController.onMouseMove(x=" + x + ",y=" + y + ")");
120 if (m_mouseDown)
121 {
122 if (! m_dragging && equalsThreshold(x, y))
123 {
124 doStartDrag(sender, m_downX, m_downY);
125 }
126 if (m_dragging)
127 {
128 m_dragGesture.step(x, y);
129 }
130 }
131 }
132
133 public void onMouseUp(Widget sender, int x, int y)
134 {
135 // Debug.println("DragController.onMouseUp(x=" + x + ",y=" + y + ")");
136
137 // it is possible to get a mouse up without a mouse down
138 if (m_mouseDown)
139 {
140 m_dragGesture.step(x, y);
141 m_dragGesture.finish(x, y);
142 DOM.releaseCapture(sender.getElement());
143 m_dragging = false;
144 m_mouseDown = false;
145 }
146 }
147 }