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    }