Skip to content

Commit

Permalink
Adding support for horizontal scrolling (touch pad and touch screen)
Browse files Browse the repository at this point in the history
Also, adding support for devices which report fractional scrolling
amounts. E.g. a mouse with a continuous mouse wheel, or a Mac touch
pad. This is currently only supported in lwjgl3. It can probably be
added to android and maybe to gwt.

InputProcessor scrolled method now receives scroll amount for X and
Y. Changed type to float to support devices which report fractional
scroll amounts. Updated InputEvent in scene2d accordingly: added
scrollAmountX, scrollAmountY attributes and corresponding setters and
getters.

Input event queue can receive float scrolling values. Since the queue
stores the events with integers. Scrolling values are stored in fixed
precision format, with 8 bits for the fraction.

Updated backends accordingly: lwjgl, lwjgl3, android and gwt.
  • Loading branch information
Julien Pauty committed Apr 15, 2020
1 parent b87a828 commit 390ec12
Show file tree
Hide file tree
Showing 18 changed files with 58 additions and 60 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -59,6 +59,8 @@
- API Addition: Added Group#removeActorAt(int,boolean) to avoid looking up the actor index. Subclasses intending to take action when an actor is removed may need to override this new method.
- API Change: If Group#addActorAfter is called with an afterActor not in the group, the actor is added as the last child (not the first).

[1.9.10]
- API Change: InputProcessor scrolled method now receives scroll amount for X and Y. Changed type to float to support devices which report fractional scroll amounts. Updated InputEvent in scene2d accordingly: added scrollAmountX, scrollAmountY attributes and corresponding setters and getters.
[1.9.9]
- API Addition: Add support for stripping whitespace in PixmapPacker
- API Addition: Add support for 9 patch packing in PixmapPacker
Expand Down
Expand Up @@ -76,7 +76,8 @@ static class TouchEvent {
int type;
int x;
int y;
int scrollAmount;
int scrollAmountX;
int scrollAmountY;
int button;
int pointer;
}
Expand Down Expand Up @@ -412,7 +413,7 @@ void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(e.scrollAmountX, e.scrollAmountY);
}
usedTouchEvents.free(e);
}
Expand Down
Expand Up @@ -38,7 +38,8 @@ public boolean onGenericMotion (MotionEvent event, AndroidInput input) {
final int action = event.getAction() & MotionEvent.ACTION_MASK;

int x = 0, y = 0;
int scrollAmount = 0;
int scrollAmountX = 0;
int scrollAmountY = 0;

long timeStamp = System.nanoTime();
synchronized (input) {
Expand All @@ -47,15 +48,16 @@ public boolean onGenericMotion (MotionEvent event, AndroidInput input) {
x = (int)event.getX();
y = (int)event.getY();
if ((x != deltaX) || (y != deltaY)) { // Avoid garbage events
postTouchEvent(input, TouchEvent.TOUCH_MOVED, x, y, 0, timeStamp);
postTouchEvent(input, TouchEvent.TOUCH_MOVED, x, y, 0, 0, timeStamp);
deltaX = x;
deltaY = y;
}
break;

case MotionEvent.ACTION_SCROLL:
scrollAmount = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_VSCROLL));
postTouchEvent(input, TouchEvent.TOUCH_SCROLLED, 0, 0, scrollAmount, timeStamp);
scrollAmountY = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_VSCROLL));
scrollAmountX = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_HSCROLL));
postTouchEvent(input, TouchEvent.TOUCH_SCROLLED, 0, 0, scrollAmountX, scrollAmountY, timeStamp);

}
}
Expand All @@ -78,13 +80,14 @@ else if (action == MotionEvent.ACTION_SCROLL)
Gdx.app.log("AndroidMouseHandler", "action " + actionStr);
}

private void postTouchEvent (AndroidInput input, int type, int x, int y, int scrollAmount, long timeStamp) {
private void postTouchEvent (AndroidInput input, int type, int x, int y, int scrollAmountX, int scrollAmountY, long timeStamp) {
TouchEvent event = input.usedTouchEvents.obtain();
event.timeStamp = timeStamp;
event.x = x;
event.y = y;
event.type = type;
event.scrollAmount = scrollAmount;
event.scrollAmountX = scrollAmountX;
event.scrollAmountY = scrollAmountY;
input.touchEvents.add(event);
}

Expand Down
Expand Up @@ -383,7 +383,7 @@ void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(0, e.scrollAmount);
break;
}
usedTouchEvents.free(e);
Expand Down
Expand Up @@ -366,7 +366,7 @@ void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(0,e.scrollAmount);
}
usedTouchEvents.free(e);
}
Expand Down
Expand Up @@ -93,25 +93,7 @@ public void invoke(long window, int codepoint) {
@Override
public void invoke(long window, double scrollX, double scrollY) {
Lwjgl3Input.this.window.getGraphics().requestRendering();
if (scrollYRemainder > 0 && scrollY < 0 || scrollYRemainder < 0 && scrollY > 0 ||
TimeUtils.nanoTime() - lastScrollEventTime > pauseTime ) {
// fire a scroll event immediately:
// - if the scroll direction changes;
// - if the user did not move the wheel for more than 250ms
scrollYRemainder = 0;
int scrollAmount = (int)-Math.signum(scrollY);
eventQueue.scrolled(scrollAmount);
lastScrollEventTime = TimeUtils.nanoTime();
}
else {
scrollYRemainder += scrollY;
while (Math.abs(scrollYRemainder) >= 1) {
int scrollAmount = (int)-Math.signum(scrollY);
eventQueue.scrolled(scrollAmount);
lastScrollEventTime = TimeUtils.nanoTime();
scrollYRemainder += scrollAmount;
}
}
eventQueue.scrolled(-(float)scrollX, -(float)scrollY);
}
};

Expand Down
Expand Up @@ -646,7 +646,7 @@ private void handleEvent (NativeEvent e) {
}
if (e.getType().equals(getMouseWheelEvent())) {
if (processor != null) {
processor.scrolled((int)getMouseWheelVelocity(e));
processor.scrolled(0,(int)getMouseWheelVelocity(e));
}
this.currentEventTimeStamp = TimeUtils.nanoTime();
e.preventDefault();
Expand Down
Expand Up @@ -599,7 +599,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion gdx/src/com/badlogic/gdx/InputAdapter.java
Expand Up @@ -50,7 +50,7 @@ public boolean mouseMoved (int screenX, int screenY) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}
}
9 changes: 5 additions & 4 deletions gdx/src/com/badlogic/gdx/InputEventQueue.java
Expand Up @@ -92,7 +92,7 @@ public void drain () {
localProcessor.mouseMoved(q[i++], q[i++]);
break;
case SCROLLED:
localProcessor.scrolled(q[i++]);
localProcessor.scrolled(q[i++] / 256f, q[i++] / 256f);
break;
default:
throw new RuntimeException();
Expand Down Expand Up @@ -133,7 +133,7 @@ private synchronized int next (int nextType, int i) {
i += 2;
break;
case SCROLLED:
i++;
i += 2;
break;
default:
throw new RuntimeException();
Expand Down Expand Up @@ -218,10 +218,11 @@ public synchronized boolean mouseMoved (int screenX, int screenY) {
return false;
}

public synchronized boolean scrolled (int amount) {
public synchronized boolean scrolled(float amountX, float amountY) {
queue.add(SCROLLED);
queueTime();
queue.add(amount);
queue.add((int)(amountX * 256));
queue.add((int)(amountY * 256));
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions gdx/src/com/badlogic/gdx/InputMultiplexer.java
Expand Up @@ -150,11 +150,11 @@ public boolean mouseMoved (int screenX, int screenY) {
return false;
}

public boolean scrolled (int amount) {
public boolean scrolled (float amountX,float amountY) {
Object[] items = processors.begin();
try {
for (int i = 0, n = processors.size; i < n; i++)
if (((InputProcessor)items[i]).scrolled(amount)) return true;
if (((InputProcessor)items[i]).scrolled(amountX, amountY)) return true;
} finally {
processors.end();
}
Expand Down
5 changes: 3 additions & 2 deletions gdx/src/com/badlogic/gdx/InputProcessor.java
Expand Up @@ -67,7 +67,8 @@ public interface InputProcessor {
public boolean mouseMoved (int screenX, int screenY);

/** Called when the mouse wheel was scrolled. Will not be called on iOS.
* @param amount the scroll amount, -1 or 1 depending on the direction the wheel was scrolled.
* @param amountX the horizontal scroll amount, negative or positive depending on the direction the wheel was scrolled.
* @param amountY the vertical scroll amount, negative or positive depending on the direction the wheel was scrolled.
* @return whether the input was processed. */
public boolean scrolled (int amount);
public boolean scrolled (float amountX, float amountY);
}
Expand Up @@ -203,8 +203,8 @@ public boolean touchDragged (int screenX, int screenY, int pointer) {
}

@Override
public boolean scrolled (int amount) {
return zoom(amount * scrollFactor * translateUnits);
public boolean scrolled (float amountX, float amountY) {
return zoom(amountY * scrollFactor * translateUnits);
}

public boolean zoom (float amount) {
Expand Down
2 changes: 1 addition & 1 deletion gdx/src/com/badlogic/gdx/input/RemoteSender.java
Expand Up @@ -198,7 +198,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}

Expand Down
22 changes: 15 additions & 7 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/InputEvent.java
Expand Up @@ -24,8 +24,8 @@
* @see InputListener */
public class InputEvent extends Event {
private Type type;
private float stageX, stageY;
private int pointer, button, keyCode, scrollAmount;
private float stageX, stageY, scrollAmountX, scrollAmountY;
private int pointer, button, keyCode;
private char character;
@Null private Actor relatedActor;

Expand Down Expand Up @@ -100,13 +100,21 @@ public void setCharacter (char character) {
this.character = character;
}

/** The amount the mouse was scrolled. Valid for: scrolled. */
public int getScrollAmount () {
return scrollAmount;
/** The amount the mouse was scrolled horizontally. Valid for: scrolled. */
public float getScrollAmountX () {
return scrollAmountX;
}
/** The amount the mouse was scrolled vertically. Valid for: scrolled. */
public float getScrollAmountY () {
return scrollAmountY;
}

public void setScrollAmountX (float scrollAmount) {
this.scrollAmountX = scrollAmount;
}

public void setScrollAmount (int scrollAmount) {
this.scrollAmount = scrollAmount;
public void setScrollAmountY (float scrollAmount) {
this.scrollAmountY = scrollAmount;
}

/** The actor related to the event. Valid for: enter and exit. For enter, this is the actor being exited, or null. For exit,
Expand Down
4 changes: 2 additions & 2 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/InputListener.java
Expand Up @@ -65,7 +65,7 @@ public boolean handle (Event e) {
case mouseMoved:
return mouseMoved(event, tmpCoords.x, tmpCoords.y);
case scrolled:
return scrolled(event, tmpCoords.x, tmpCoords.y, event.getScrollAmount());
return scrolled(event, tmpCoords.x, tmpCoords.y, event.getScrollAmountX(), event.getScrollAmountY());
case enter:
enter(event, tmpCoords.x, tmpCoords.y, event.getPointer(), event.getRelatedActor());
return false;
Expand Down Expand Up @@ -119,7 +119,7 @@ public void exit (InputEvent event, float x, float y, int pointer, @Null Actor t
}

/** Called when the mouse wheel has been scrolled. When true is returned, the event is {@link Event#handle() handled}. */
public boolean scrolled (InputEvent event, float x, float y, int amount) {
public boolean scrolled (InputEvent event, float x, float y, float amountX, float amountY) {
return false;
}

Expand Down
5 changes: 3 additions & 2 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/Stage.java
Expand Up @@ -387,15 +387,16 @@ public boolean mouseMoved (int screenX, int screenY) {

/** Applies a mouse scroll event to the stage and returns true if an actor in the scene {@link Event#handle() handled} the
* event. This event only occurs on the desktop. */
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
Actor target = scrollFocus == null ? root : scrollFocus;

screenToStageCoordinates(tempCoords.set(mouseScreenX, mouseScreenY));

InputEvent event = Pools.obtain(InputEvent.class);
event.setStage(this);
event.setType(InputEvent.Type.scrolled);
event.setScrollAmount(amount);
event.setScrollAmountX(amountX);
event.setScrollAmountY(amountY);
event.setStageX(tempCoords.x);
event.setStageY(tempCoords.y);
target.fire(event);
Expand Down
11 changes: 5 additions & 6 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/ui/ScrollPane.java
Expand Up @@ -214,13 +214,12 @@ public boolean handle (Event event) {
addListener(flickScrollListener);

addListener(new InputListener() {
public boolean scrolled (InputEvent event, float x, float y, int amount) {
public boolean scrolled (InputEvent event, float x, float y, float scrollAmountX, float scrollAmountY) {
setScrollbarsVisible(true);
if (scrollY)
setScrollY(amountY + getMouseWheelY() * amount);
else if (scrollX) //
setScrollX(amountX + getMouseWheelX() * amount);
else
if (scrollY || scrollX) {
setScrollY(amountY + getMouseWheelY() * scrollAmountY);
setScrollX(amountX + getMouseWheelX() * scrollAmountX);
} else
return false;
return true;
}
Expand Down

0 comments on commit 390ec12

Please sign in to comment.