Skip to content

Commit 945d0e0

Browse files
committed
Add default implementation of select and drag listener into core library.
1 parent 29d100d commit 945d0e0

3 files changed

Lines changed: 268 additions & 3 deletions

File tree

worldwind/src/main/java/gov/nasa/worldwind/BasicWorldWindowController.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package gov.nasa.worldwind;
77

8+
import android.view.GestureDetector;
89
import android.view.MotionEvent;
910

1011
import java.util.Arrays;
@@ -18,6 +19,8 @@
1819
import gov.nasa.worldwind.gesture.PanRecognizer;
1920
import gov.nasa.worldwind.gesture.PinchRecognizer;
2021
import gov.nasa.worldwind.gesture.RotationRecognizer;
22+
import gov.nasa.worldwind.gesture.SelectDragCallback;
23+
import gov.nasa.worldwind.gesture.SelectDragListener;
2124
import gov.nasa.worldwind.util.WWMath;
2225

2326
public class BasicWorldWindowController implements WorldWindowController, GestureListener {
@@ -51,6 +54,10 @@ public class BasicWorldWindowController implements WorldWindowController, Gestur
5154
protected List<GestureRecognizer> allRecognizers = Arrays.asList(
5255
this.panRecognizer, this.pinchRecognizer, this.rotationRecognizer, this.tiltRecognizer, this.mouseTiltRecognizer);
5356

57+
protected final SelectDragListener selectDragListener;
58+
59+
protected GestureDetector selectDragDetector;
60+
5461
public BasicWorldWindowController(WorldWindow wwd) {
5562
this.wwd = wwd;
5663

@@ -70,6 +77,14 @@ public BasicWorldWindowController(WorldWindow wwd) {
7077
((RotationRecognizer) this.rotationRecognizer).setInterpretAngle(20f);
7178
((PanRecognizer) this.tiltRecognizer).setInterpretDistance(wwd.getContext().getResources().getDimension(R.dimen.tilt_interpret_distance));
7279
((MousePanRecognizer) this.mouseTiltRecognizer).setInterpretDistance(wwd.getContext().getResources().getDimension(R.dimen.tilt_interpret_distance));
80+
81+
// Initialize basic select and drag listener
82+
this.selectDragListener = new SelectDragListener(wwd);
83+
this.selectDragDetector = new GestureDetector(wwd.getContext(), selectDragListener);
84+
}
85+
86+
public void setSelectDragCallback(SelectDragCallback callback) {
87+
selectDragListener.setCallback(callback);
7388
}
7489

7590
public void resetOrientation(boolean headingOnly) {
@@ -111,12 +126,28 @@ public WorldWindow getWorldWindow() {
111126
public boolean onTouchEvent(MotionEvent event) {
112127
boolean handled = false;
113128

114-
for (int idx = 0, len = this.allRecognizers.size(); idx < len; idx++) {
129+
// Skip select and drag processing if callback is not assigned
130+
if (selectDragListener.getCallback() != null) {
131+
// Allow select and drag detector to intercept event. It sets the state flags which will
132+
// either preempt or allow the event to be subsequently processed by the globe's navigation event handlers.
133+
handled = selectDragDetector.onTouchEvent(event);
134+
135+
// Is a dragging operation started or in progress? Any ACTION_UP event cancels a drag operation.
136+
if (selectDragListener.isDragging() && event.getAction() == MotionEvent.ACTION_UP) {
137+
selectDragListener.cancelDragging();
138+
}
139+
140+
// Preempt the globe's pan navigation recognizer if we're dragging
141+
panRecognizer.setEnabled(!selectDragListener.isDragging());
142+
}
143+
144+
// Pass on the event on to the default globe navigation handlers
145+
if (!handled) for (int idx = 0, len = this.allRecognizers.size(); idx < len; idx++) {
115146
handled |= this.allRecognizers.get(idx).onTouchEvent(event); // use or-assignment to indicate if any recognizer handled the event
116147
}
117148

118149
// Handle dependent gestures lock
119-
if(handled) {
150+
if (handled) {
120151
tiltRecognizer.setEnabled(!isInProcess(rotationRecognizer) || !rotationRecognizer.isEnabled());
121152
rotationRecognizer.setEnabled(!isInProcess(tiltRecognizer) || !tiltRecognizer.isEnabled());
122153
}
@@ -284,7 +315,7 @@ protected void gestureDidEnd() {
284315
}
285316
}
286317

287-
private boolean isInProcess(GestureRecognizer recognizer) {
318+
protected boolean isInProcess(GestureRecognizer recognizer) {
288319
return recognizer.getState() == WorldWind.BEGAN || recognizer.getState() == WorldWind.CHANGED;
289320
}
290321

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package gov.nasa.worldwind.gesture;
2+
3+
import gov.nasa.worldwind.geom.Position;
4+
import gov.nasa.worldwind.render.Renderable;
5+
6+
/**
7+
* Interface for processing user input to interact with renderables.
8+
*/
9+
public interface SelectDragCallback {
10+
/**
11+
* Terrain position was picked.
12+
*
13+
* @param position picked terrain position
14+
*/
15+
void onTerrainPicked(Position position);
16+
17+
/**
18+
* Terrain context at some position was requested.
19+
*
20+
* @param position picked terrain position
21+
*/
22+
void onTerrainContext(Position position);
23+
24+
/**
25+
* Check if renderable is pick-able.
26+
*
27+
* @param renderable some renderable intended to be picked
28+
* @return renderable is pick-able
29+
*/
30+
boolean canPickRenderable(Renderable renderable);
31+
32+
/**
33+
* Some renderable was picked.
34+
*
35+
* @param renderable picked renderable
36+
* @param position picked terrain or renderable center position
37+
*/
38+
void onRenderablePicked(Renderable renderable, Position position);
39+
40+
/**
41+
* Some renderables context was requested.
42+
*
43+
* @param renderable picked renderable
44+
* @param position picked terrain or renderable center position
45+
*/
46+
void onRenderableContext(Renderable renderable, Position position);
47+
48+
/**
49+
* Check if picked renderable is movable.
50+
*
51+
* @param renderable picked renderable
52+
* @return picked renderable is movable
53+
*/
54+
boolean canMoveRenderable(Renderable renderable);
55+
56+
/**
57+
* Renderable was moved from ane position to another.
58+
*
59+
* @param renderable picked renderable which is moving
60+
* @param fromPosition previous position
61+
* @param toPosition current position
62+
*/
63+
void onRenderableMoved(Renderable renderable, Position fromPosition, Position toPosition);
64+
65+
/**
66+
* Renderable movement was finished
67+
*
68+
* @param renderable renderable which was moved
69+
* @param position last position during movement
70+
*/
71+
void onRenderableMovingFinished(Renderable renderable, Position position);
72+
73+
/**
74+
* Renderable was double-tapped or double-clicked
75+
*
76+
* @param renderable renderable which was double-tapped or double-clicked
77+
* @param position picked terrain or renderable center position
78+
*/
79+
void onRenderableDoubleTap(Renderable renderable, Position position);
80+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package gov.nasa.worldwind.gesture;
2+
3+
import android.view.GestureDetector.SimpleOnGestureListener;
4+
import android.view.MotionEvent;
5+
import android.view.ViewConfiguration;
6+
7+
import gov.nasa.worldwind.PickedObject;
8+
import gov.nasa.worldwind.WorldWindow;
9+
import gov.nasa.worldwind.geom.Position;
10+
import gov.nasa.worldwind.render.Renderable;
11+
12+
public class SelectDragListener extends SimpleOnGestureListener {
13+
14+
private final WorldWindow wwd;
15+
private final int slope;
16+
private Position pickedPosition;
17+
private Renderable pickedRenderable;
18+
private boolean isDraggingArmed;
19+
private boolean isDragging;
20+
21+
private SelectDragCallback callback;
22+
23+
public SelectDragListener(WorldWindow wwd) {
24+
this.wwd = wwd;
25+
this.slope = ViewConfiguration.get(wwd.getContext()).getScaledTouchSlop();
26+
}
27+
28+
public boolean isDragging() {
29+
return isDragging;
30+
}
31+
32+
public void setCallback(SelectDragCallback callback) {
33+
this.callback = callback;
34+
}
35+
36+
public SelectDragCallback getCallback() {
37+
return callback;
38+
}
39+
40+
@Override
41+
public boolean onDown(MotionEvent event) {
42+
pick(event);
43+
return false;
44+
}
45+
46+
@Override
47+
public boolean onSingleTapUp(MotionEvent event) {
48+
if (pickedPosition != null && callback != null) {
49+
if (pickedRenderable != null && callback.canPickRenderable(pickedRenderable))
50+
callback.onRenderablePicked(pickedRenderable, pickedPosition);
51+
else callback.onTerrainPicked(pickedPosition);
52+
wwd.requestRedraw();
53+
}
54+
return false;
55+
}
56+
57+
@Override
58+
public boolean onScroll(MotionEvent downEvent, MotionEvent moveEvent, float distanceX, float distanceY) {
59+
Position fromPosition = pickedPosition;
60+
if (isDraggingArmed && fromPosition != null && pickedRenderable != null && callback != null) {
61+
// Signal that dragging is in progress
62+
isDragging = true;
63+
64+
// Backup original altitude
65+
double altitude = fromPosition.altitude;
66+
// First we compute the screen coordinates of the position's "ground" point. We'll apply the
67+
// screen X and Y drag distances to this point, from which we'll compute a new position,
68+
// wherein we restore the original position's altitude.
69+
PickedObject terrainPickedObject = wwd.pick(moveEvent.getX(), moveEvent.getY()).terrainPickedObject();
70+
if (terrainPickedObject != null && terrainPickedObject.getTerrainPosition() != null) {
71+
Position toPosition = terrainPickedObject.getTerrainPosition();
72+
// Restore original altitude
73+
toPosition.altitude = altitude;
74+
// Callback event
75+
callback.onRenderableMoved(pickedRenderable, fromPosition, toPosition);
76+
// Remember new position
77+
pickedPosition = toPosition;
78+
// Reflect the change in position on the globe.
79+
wwd.requestRedraw();
80+
} else {
81+
// Probably clipped by near/far clipping plane or off the globe. The position was not updated. Stop the drag.
82+
isDraggingArmed = false;
83+
}
84+
return true; // We consumed this event, even if dragging has been stopped.
85+
}
86+
return false;
87+
}
88+
89+
@Override
90+
public boolean onDoubleTap(MotionEvent event) {
91+
if (pickedRenderable != null && pickedPosition != null && callback != null) {
92+
callback.onRenderableDoubleTap(pickedRenderable, pickedPosition);
93+
wwd.requestRedraw();
94+
return true;
95+
}
96+
return false;
97+
}
98+
99+
@Override
100+
public void onLongPress(MotionEvent event) {
101+
showContext();
102+
pick(event); // Select possible drag point
103+
}
104+
105+
@Override
106+
public boolean onContextClick(MotionEvent event) {
107+
showContext();
108+
pick(event); // Select possible drag point
109+
return true;
110+
}
111+
112+
public void cancelDragging() {
113+
isDragging = false;
114+
isDraggingArmed = false;
115+
// Callback event
116+
if (pickedRenderable != null && pickedPosition != null && callback != null) {
117+
callback.onRenderableMovingFinished(pickedRenderable, pickedPosition);
118+
wwd.requestRedraw();
119+
}
120+
}
121+
122+
private void showContext() {
123+
if (pickedPosition != null && callback != null) {
124+
if (pickedRenderable != null) callback.onRenderableContext(pickedRenderable, pickedPosition);
125+
else callback.onTerrainContext(pickedPosition);
126+
wwd.requestRedraw();
127+
}
128+
}
129+
130+
/**
131+
* Performs a pick at the tap location and conditionally arms the dragging flag, so that dragging can occur if
132+
* the next event is an onScroll event.
133+
*/
134+
private void pick(MotionEvent event) {
135+
// Perform the pick at the screen x, y
136+
var pickList = wwd.pick(event.getX(), event.getY());
137+
138+
// Store picked position
139+
pickedPosition = pickList.terrainPickedObject() != null ? pickList.terrainPickedObject().getTerrainPosition() : null;
140+
141+
// Pick objects inside touch slope if current pick list has no renderables
142+
if (!pickList.hasNonTerrainObjects()) {
143+
pickList = wwd.pickShapesInRect(event.getX() - slope / 2f, event.getY() - slope / 2f, slope, slope);
144+
}
145+
146+
// Examine the picked objects for Renderables
147+
Object userObject = pickList.topPickedObject() != null ? pickList.topPickedObject().getUserObject() : null;
148+
pickedRenderable = userObject instanceof Renderable ? (Renderable) userObject : null;
149+
150+
// Determine whether the dragging flag should be "armed".
151+
isDraggingArmed = (userObject instanceof Renderable) && callback != null && callback.canMoveRenderable((Renderable) userObject);
152+
}
153+
154+
}

0 commit comments

Comments
 (0)