//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.util;

import playn.core.Mouse;

/**
* Dispatches user input from {@link Mouse}.
*/
public class MouseInput extends Input<Mouse.Listener>
{
    /**
     * Configures a reaction to be notified of mouse activity. On mouse activity, reactions will be
     * scanned from most-recently-registered to least-recently-registered and hit-tested. Thus more
     * recently registered reactions that overlap previously registered reactions will take
     * precedence. TODO: use layer depth information to hit test based on depth.
     *
     * <p> After a mouse down, subsequent move and up events will be dispatched to the reaction that
     * successfully hit-tested the mouse start. If no mouse down reaction is active, movement is
     * dispatched via the same hit-testing mechanism. Mouse wheel scrolls are dispatched the the
     * active down reaction, or the most recent movement hit if there is no active down reaction.
     * </p>
     *
     * @return a handle that can be used to clear this registration.
     */
    public Registration register (Region region, Mouse.Listener listener) {
        return _reactor.register(region, listener);
    }

    /** Receives input from the PlayN Mouse service. */
    protected class MouseReactor extends Reactor<Mouse.Listener>
        implements Mouse.Listener {
        @Override public void onMouseDown (Mouse.ButtonEvent event) {
            _active = hitTest(event);
            if (_active != null) {
                _active.onMouseDown(event);
            }
        }
        @Override public void onMouseMove (Mouse.MotionEvent event) {
            if (_active != null) {
                _active.onMouseMove(event);
            } else {
                _lastMoved = hitTest(event);
                if (_lastMoved != null) {
                    _lastMoved.onMouseMove(event);
                }
            }
        }
        @Override public void onMouseUp (Mouse.ButtonEvent event) {
            if (_active != null) {
                _active.onMouseUp(event);
                _active = null;
            }
        }
        @Override public void onMouseWheelScroll (Mouse.WheelEvent event) {
            if (_active != null) {
                _active.onMouseWheelScroll(event);
            } else if (_lastMoved != null) {
                _lastMoved.onMouseWheelScroll(event);
            }
        }

        protected Mouse.Listener _active, _lastMoved;
    };

    protected final MouseReactor _reactor = new MouseReactor();
    public final Mouse.Listener mlistener = _reactor;
}

@@ -749,50 +749,221 @@
 %3Cp%3E 
-After a mouse down, subsequent move and up
+Mouse motion events are dispatched to the region over which the mouse is hovering, if%0A     * any (with overlapping regions resolved as described above). After a mouse down, subsequent%0A     * movement, up and wheel
  eve
@@ -1005,23 +1005,16 @@
 ion that
-%0A     *
  success
@@ -1018,16 +1018,23 @@
 essfully
+%0A     *
  hit-tes
@@ -1059,129 +1059,75 @@
 t. I
-f no mouse down reaction is active, movement is%0A     * dispatched via the same hit-testing mechanism. Mouse wheel scrolls
+n the absence of an active down reaction, mouse wheel events%0A     *
  are
@@ -1143,119 +1143,62 @@
 ed t
-he
+o
  the
-%0A     * active down react
+ reg
 ion
-,
  o
-r the most recent movement hit if there is no active down reaction.%0A     *
+ver which the mouse is hovering, if any.
  %3C/p
@@ -1538,24 +1538,16 @@
 istener%3E
-%0A       
  impleme
@@ -1650,22 +1650,22 @@
        _
-active
+target
  = hitTe
@@ -1684,38 +1684,38 @@
            if (_
-active
+target
  != null) %7B%0A    
@@ -1719,38 +1719,68 @@
                _
-active
+down = true;%0A                _target
 .onMouseDown(eve
@@ -1890,39 +1890,30 @@
         if (
-_active != null
+!_down
 ) %7B%0A        
@@ -1925,26 +1925,24 @@
    _
-active.onMouseMove
+target = hitTest
 (eve
@@ -1963,65 +1963,9 @@
    %7D
- else %7B%0A                _lastMoved = hitTest(event);%0A    
+%0A
     
@@ -1973,33 +1973,30 @@
        if (_
-lastMoved
+target
  != null) %7B%0A
@@ -2007,38 +2007,31 @@
             
-  
-  _lastMoved
+_target
 .onMouseMove
@@ -2043,26 +2043,8 @@
 t);%0A
-                %7D%0A
     
@@ -2144,38 +2144,28 @@
        if (_
-active != null
+down
 ) %7B%0A        
@@ -2177,78 +2177,172 @@
    _
-active.onMouseUp(event);%0A                _active = null;%0A            %7D
+down = false;%0A                Mouse.Listener oldHover = _target;%0A                // now that the mouse is released, we may be hovering over a new region; rechecking
 %0A   
@@ -2342,34 +2342,32 @@
 ing%0A        
-%7D%0A
         
 @Override pu
@@ -2358,142 +2358,381 @@
     
-@Override public void onM
+// hover here ensures that subsequent m
 ouse
-W
+ w
 heel
-Scroll (Mouse.WheelEvent event) %7B%0A            if (_active != null) %7B%0A                _acti
+ events will be correctly%0A                // dispatched even if the mouse is not moved%0A                _target = hitTest(event);%0A                // notify onMouseUp last so that our internal invariants are not broken if the%0A                // listener decides to throw an unchecked exception%0A                oldHo
 ve
+r
 .onMouse
 Whee
@@ -2727,35 +2727,126 @@
 .onMouse
-WheelScroll(
+Up(event);%0A            %7D%0A        %7D%0A        @Override public void onMouseWheelScroll (Mouse.WheelEvent 
 event)
-;
+ %7B
 %0A       
@@ -2854,29 +2854,19 @@
     
-%7D else if (_lastMoved
+if (_target
  != 
@@ -2890,25 +2890,22 @@
        _
-lastMoved
+target
 .onMouse
@@ -2987,26 +2987,47 @@
 er _
-active, _lastMoved
+target;%0A        protected boolean _down
 ;%0A  

Clarified the comments and code. I'm being OCD, but I did fix a bug.