Skip to content

Commit ff73120

Browse files
author
jmhofer
committed
Added a helper for computing relative mouse motion.
1 parent e92bafa commit ff73120

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.awt.Component;
2121
import java.awt.Dimension;
22+
import java.awt.Point;
2223
import java.awt.event.ActionEvent;
2324
import java.awt.event.ComponentEvent;
2425
import java.awt.event.KeyEvent;
@@ -110,6 +111,16 @@ public static Observable<MouseEvent> fromMouseMotionEvents(Component component)
110111
return MouseEventSource.fromMouseMotionEventsOf(component);
111112
}
112113

114+
/**
115+
* Creates an observable corresponding to relative mouse motion.
116+
* @param component
117+
* The component to register the observable for.
118+
* @return A point whose x and y coordinate represent the relative horizontal and vertical mouse motion.
119+
*/
120+
public static Observable<Point> fromRelativeMouseMotion(Component component) {
121+
return MouseEventSource.fromRelativeMouseMotion(component);
122+
}
123+
113124
/**
114125
* Creates an observable corresponding to raw component events.
115126
*

rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/MouseEventSource.java

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,28 @@
1515
*/
1616
package rx.swing.sources;
1717

18+
import static org.mockito.Mockito.*;
19+
1820
import java.awt.Component;
21+
import java.awt.Point;
1922
import java.awt.event.MouseEvent;
2023
import java.awt.event.MouseListener;
2124
import java.awt.event.MouseMotionListener;
2225

26+
import javax.swing.JPanel;
27+
28+
import org.junit.Test;
29+
import org.mockito.InOrder;
30+
import org.mockito.Matchers;
31+
2332
import rx.Observable;
2433
import rx.Observer;
2534
import rx.Subscription;
2635
import rx.subscriptions.Subscriptions;
2736
import rx.util.functions.Action0;
37+
import rx.util.functions.Action1;
2838
import rx.util.functions.Func1;
39+
import rx.util.functions.Func2;
2940

3041
public enum MouseEventSource { ; // no instances
3142

@@ -103,4 +114,86 @@ public void call() {
103114
}
104115
});
105116
}
117+
118+
/**
119+
* @see rx.observables.SwingObservable#fromRelativeMouseMotion
120+
*/
121+
public static Observable<Point> fromRelativeMouseMotion(final Component component) {
122+
class OldAndRelative {
123+
public final Point old;
124+
public final Point relative;
125+
126+
private OldAndRelative(Point old, Point relative) {
127+
this.old = old;
128+
this.relative = relative;
129+
}
130+
}
131+
132+
class Relativize implements Func2<OldAndRelative, MouseEvent, OldAndRelative> {
133+
@Override
134+
public OldAndRelative call(OldAndRelative last, MouseEvent event) {
135+
Point current = new Point(event.getX(), event.getY());
136+
Point relative = new Point(current.x - last.old.x, current.y - last.old.y);
137+
return new OldAndRelative(current, relative);
138+
}
139+
}
140+
141+
class OnlyRelative implements Func1<OldAndRelative, Point> {
142+
@Override
143+
public Point call(OldAndRelative oar) {
144+
return oar.relative;
145+
}
146+
}
147+
148+
return fromMouseMotionEventsOf(component)
149+
.scan(new OldAndRelative(new Point(0, 0), new Point(0, 0)), new Relativize())
150+
.map(new OnlyRelative())
151+
.skip(2); // skip the useless initial value and the invalid first computation
152+
}
153+
154+
public static class UnitTest {
155+
private Component comp = new JPanel();
156+
157+
@Test
158+
public void testRelativeMouseMotion() {
159+
@SuppressWarnings("unchecked")
160+
Action1<Point> action = mock(Action1.class);
161+
@SuppressWarnings("unchecked")
162+
Action1<Exception> error = mock(Action1.class);
163+
Action0 complete = mock(Action0.class);
164+
165+
Subscription sub = fromRelativeMouseMotion(comp).subscribe(action, error, complete);
166+
167+
InOrder inOrder = inOrder(action);
168+
169+
verify(action, never()).call(Matchers.<Point>any());
170+
verify(error, never()).call(Matchers.<Exception>any());
171+
verify(complete, never()).call();
172+
173+
fireMouseEvent(mouseEvent(0, 0));
174+
verify(action, never()).call(Matchers.<Point>any());
175+
176+
fireMouseEvent(mouseEvent(10, -5));
177+
inOrder.verify(action, times(1)).call(new Point(10, -5));
178+
179+
fireMouseEvent(mouseEvent(6, 10));
180+
inOrder.verify(action, times(1)).call(new Point(-4, 15));
181+
182+
sub.unsubscribe();
183+
fireMouseEvent(mouseEvent(0, 0));
184+
inOrder.verify(action, never()).call(Matchers.<Point>any());
185+
verify(error, never()).call(Matchers.<Exception>any());
186+
verify(complete, never()).call();
187+
}
188+
189+
private MouseEvent mouseEvent(int x, int y) {
190+
return new MouseEvent(comp, MouseEvent.MOUSE_MOVED, 1L, 0, x, y, 0, false);
191+
}
192+
193+
private void fireMouseEvent(MouseEvent event) {
194+
for (MouseMotionListener listener: comp.getMouseMotionListeners()) {
195+
listener.mouseMoved(event);
196+
}
197+
}
198+
}
106199
}

0 commit comments

Comments
 (0)