Skip to content

Commit

Permalink
feat: add experimental support for touch events in editor (#206)
Browse files Browse the repository at this point in the history
targos authored May 17, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent d7399aa commit bc41dcc
Showing 6 changed files with 258 additions and 63 deletions.
4 changes: 2 additions & 2 deletions examples/Editor.html
Original file line number Diff line number Diff line change
@@ -34,11 +34,11 @@
*/
-->

<html>
<html style="overscroll-behavior: none">
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
<meta content="utf-8" http-equiv="encoding" />
<script src="../dist/openchemlib-full.js"></script>
<script src="../dist/openchemlib-full.pretty.js"></script>

<style>
body,
35 changes: 35 additions & 0 deletions src/com/actelion/research/gwt/gui/editor/ACTTouchEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.actelion.research.gwt.gui.editor;

import com.actelion.research.share.gui.editor.io.IMouseEvent;
import com.google.gwt.event.dom.client.TouchEvent;

public class ACTTouchEvent<T extends TouchEvent> implements IMouseEvent {
T _evt;
MousePoint _mousePoint;

public ACTTouchEvent(T evt, MousePoint mousePoint) {
_evt = evt;
_mousePoint = mousePoint;
}

public double getX() {
return _mousePoint.getX();
}

public double getY() {
return _mousePoint.getY();
}

public boolean isShiftDown() {
return _evt.isShiftKeyDown();
}

public boolean isControlDown() {
return _evt.isControlKeyDown();
}

@Override
public boolean isAltDown() {
return _evt.isAltKeyDown();
}
}
28 changes: 22 additions & 6 deletions src/com/actelion/research/gwt/gui/editor/DrawArea.java
Original file line number Diff line number Diff line change
@@ -241,22 +241,38 @@ public void setOnMouseDragged(MouseMoveHandler handler) {
canvas.addMouseMoveHandler(handler);
}

public void setOnMouseMoved(MouseMoveHandler handler) {
canvas.addMouseMoveHandler(handler);
}

public void setOnMouseOut(MouseOutHandler h) {
canvas.addMouseOutHandler(h);
}

public void setOnMousePressed(MouseDownHandler h) {
public void setOnMouseDown(MouseDownHandler h) {
canvas.addMouseDownHandler(h);
}

public void setOnMouseReleased(MouseUpHandler handler) {
public void setOnTouchStart(TouchStartHandler h) {
canvas.addTouchStartHandler(h);
}

public void setOnMouseMove(MouseMoveHandler handler) {
canvas.addMouseMoveHandler(handler);
}

public void setOnTouchMove(TouchMoveHandler h) {
canvas.addTouchMoveHandler(h);
}

public void setOnMouseUp(MouseUpHandler handler) {
canvas.addMouseUpHandler(handler);
}

public void setOnTouchEnd(TouchEndHandler handler) {
canvas.addTouchEndHandler(handler);
}

public void setOnTouchCancel(TouchCancelHandler handler) {
canvas.addTouchCancelHandler(handler);
}

protected boolean isMarkush() {
int mode = model.getMode();
return (mode & Model.MODE_MARKUSH_STRUCTURE) != 0;
35 changes: 35 additions & 0 deletions src/com/actelion/research/gwt/gui/editor/FakeMouseEvent.java
Original file line number Diff line number Diff line change
@@ -33,7 +33,11 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
package com.actelion.research.gwt.gui.editor;

import com.actelion.research.share.gui.editor.io.IMouseEvent;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.dom.client.TouchEvent;

public class FakeMouseEvent implements IMouseEvent {
private int x = 0;
@@ -42,6 +46,18 @@ public class FakeMouseEvent implements IMouseEvent {
private boolean ctrl = false;
private boolean alt = false;

static MousePoint getPointFromTouchEvent(TouchEvent evt) {
JsArray<Touch> touches = evt.getTouches();
Touch touch = touches.get(0);
if (touch == null) {
return null;
}
Element target = evt.getRelativeElement();
int x = touch.getRelativeX(target);
int y = touch.getRelativeY(target);
return new MousePoint(x, y);
}

public FakeMouseEvent(MouseEvent evt) {
x = evt.getX();
y = evt.getY();
@@ -50,6 +66,25 @@ public FakeMouseEvent(MouseEvent evt) {
alt = evt.isAltKeyDown();
}

public FakeMouseEvent(TouchEvent evt) {
MousePoint point = getPointFromTouchEvent(evt);
if (point != null) {
x = point.getX();
y = point.getY();
}
shift = evt.isShiftKeyDown();
ctrl = evt.isControlKeyDown();
alt = evt.isAltKeyDown();
}

public FakeMouseEvent(TouchEvent evt, MousePoint mousePoint) {
x = mousePoint.getX();
y = mousePoint.getY();
shift = evt.isShiftKeyDown();
ctrl = evt.isControlKeyDown();
alt = evt.isAltKeyDown();
}

public double getX() {
return x;
}
19 changes: 19 additions & 0 deletions src/com/actelion/research/gwt/gui/editor/MousePoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.actelion.research.gwt.gui.editor;

public class MousePoint {
private int x = 0;
private int y = 0;

public MousePoint(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return this.x;
}

public int getY() {
return this.y;
}
}
200 changes: 145 additions & 55 deletions src/com/actelion/research/gwt/gui/editor/StructureEditor.java
Original file line number Diff line number Diff line change
@@ -53,7 +53,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
import com.google.gwt.event.logical.shared.ResizeHandler;
import jsinterop.annotations.*;
import com.actelion.research.gwt.minimal.JSMolecule;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

@@ -66,7 +65,7 @@ public class StructureEditor implements IChangeListener {
static int TOOLBARWIDTH = 45;

private boolean drag = false;
private Point2D mousePoint = null;
private MousePoint mousePoint = null;
private Model model;
private ToolBar<Element> toolBar;
private DrawArea drawPane;
@@ -384,36 +383,61 @@ public void onMouseMove(MouseMoveEvent event) {

}
});
drawPane.setOnMouseMoved(new MouseMoveHandler() {
drawPane.setOnMouseOut(new MouseOutHandler() {
@Override
public void onMouseOut(MouseOutEvent event) {
mousePoint = null;
}
});
drawPane.setOnMouseDown(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
onMousePressed(event);
}
});
drawPane.setOnTouchStart(new TouchStartHandler() {
@Override
public void onTouchStart(TouchStartEvent event) {
onTouchStarted(event);
}
});
drawPane.setOnMouseMove(new MouseMoveHandler() {
@Override
public void onMouseMove(MouseMoveEvent event) {
boolean moved = mousePoint == null ? false : true;
if (!drag && moved) {
onMouseMoved(event);
}
mousePoint = new Point2D.Double(event.getX(), event.getY());
mousePoint = new MousePoint(event.getX(), event.getY());
}
});
drawPane.setOnMouseOut(new MouseOutHandler() {
drawPane.setOnTouchMove(new TouchMoveHandler() {
@Override
public void onMouseOut(MouseOutEvent event) {
mousePoint = null;
public void onTouchMove(TouchMoveEvent event) {
if (drag) {
onTouchMoved(event);
}
}
});
drawPane.setOnMousePressed(new MouseDownHandler() {
drawPane.setOnTouchCancel(new TouchCancelHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {

drag = true;
onMousePressed(event);
public void onTouchCancel(TouchCancelEvent event) {
onTouchCancelled(event);
}
});
drawPane.setOnMouseReleased(new MouseUpHandler() {
drawPane.setOnMouseUp(new MouseUpHandler() {
@Override
public void onMouseUp(MouseUpEvent event) {
drag = false;
onMouseReleased(event);
mousePoint = null;
}
});
drawPane.setOnTouchEnd(new TouchEndHandler() {
@Override
public void onTouchEnd(TouchEndEvent event) {
// Simulate a previous mouse move event so action that depend on the currently hovered element can work properly.
// Touch screens only emit move events for some hardware like the Apple Pencil Pro.
onMouseMovedFake(event);
onTouchEnded(event);
}
});
drawPane.setOnKeyPressed(new ACTKeyEventHandler() {
@@ -425,7 +449,7 @@ public void onKey(IKeyEvent event) {

/*
* drawPane.setOnKeyReleased(new ACTKeyEventHandler() {
*
*
* @Override public void onKey(IKeyEvent event) { onKeyPressed(event); } });
*/

@@ -445,32 +469,6 @@ private void onKeyPressed(IKeyEvent keyEvent) {
private void handleKeyEvent(IKeyEvent keyEvent) {
}

private void onMouseMoved(MouseEvent evt) {
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
if (a.onMouseMove(new ACTMouseEvent(evt), false)) {
drawPane.draw(a);
drawPane.requestFocus();
}
}
}
}

private void onMouseDragged(MouseEvent evt) {
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
FakeMouseEvent thisEvt = new FakeMouseEvent(evt);
if (mousePressEvt == null || !isSmallMovement(thisEvt, mousePressEvt)) {
if (a.onMouseMove(new ACTMouseEvent(evt), true)) {
drawPane.draw(a);
}
}
}
}
}

public boolean onPasteString(String s) {
try {
StereoMolecule mol = new StereoMolecule();
@@ -517,7 +515,7 @@ public static native void addPasteHandler(StructureEditor self, String text)
var blob = items[i].getAsFile();
var URLObj = window.URL || window.webkitURL;
var source = URLObj.createObjectURL(blob);
var pastedImage = new Image();
pastedImage.onload = function () {
if(self.@com.actelion.research.gwt.gui.editor.StructureEditor::onPasteImage(Ljava/lang/Object;)(pastedImage)) {
@@ -531,13 +529,13 @@ public static native void addPasteHandler(StructureEditor self, String text)
done = true;
}
});
}
}
e.preventDefault();
}
}
}, false); //official paste handler
}-*/;

@@ -553,7 +551,89 @@ private void onMouseClicked(MouseEvent evt, boolean dbl) {

}

private void onMousePressed(MouseEvent evt) {
drag = true;
mousePressEvt = new FakeMouseEvent(evt);
if (evt.getNativeButton() == NativeEvent.BUTTON_RIGHT) {
rightClick = true;
}
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
a.onMouseDown(new ACTMouseEvent(evt));
setCursor(a.getCursor());
}
}
}

private void onTouchStarted(TouchEvent evt) {
evt.preventDefault();
mousePoint = FakeMouseEvent.getPointFromTouchEvent(evt);
drag = true;
mousePressEvt = new FakeMouseEvent(evt);
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
a.onMouseDown(new ACTTouchEvent(evt, mousePoint));
setCursor(a.getCursor());
}
}

private void onMouseMoved(MouseEvent evt) {
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
if (a.onMouseMove(new ACTMouseEvent(evt), false)) {
drawPane.draw(a);
drawPane.requestFocus();
}
}
}
}

private void onMouseMovedFake(TouchEvent evt) {
Action a = toolBar.getCurrentAction();
if (mousePoint != null && a != null && !a.isCommand()) {
if (a.onMouseMove(new ACTTouchEvent(evt, mousePoint), false)) {
drawPane.draw(a);
}
}
}

private void onMouseDragged(MouseEvent evt) {
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
FakeMouseEvent thisEvt = new FakeMouseEvent(evt);
if (mousePressEvt == null || !isSmallMovement(thisEvt, mousePressEvt)) {
if (a.onMouseMove(new ACTMouseEvent(evt), true)) {
drawPane.draw(a);
}
}
}
}
}

private void onTouchMoved(TouchEvent evt) {
evt.preventDefault();
mousePoint = FakeMouseEvent.getPointFromTouchEvent(evt);
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
FakeMouseEvent thisEvt = new FakeMouseEvent(evt);
if (mousePressEvt == null || !isSmallMovement(thisEvt, mousePressEvt)) {
if (a.onMouseMove(new ACTTouchEvent(evt, mousePoint), true)) {
drawPane.draw(a);
}
}
}
}

private void onTouchCancelled(TouchEvent evt) {
drag = false;
mousePressEvt = null;
}

private void onMouseReleased(MouseEvent evt) {
drag = false;
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
@@ -573,20 +653,30 @@ private void onMouseReleased(MouseEvent evt) {
setCursor(ICursor.DEFAULT);
rightClick = false;
mousePressEvt = null;
mousePoint = null;
}

private void onMousePressed(MouseEvent evt) {
mousePressEvt = new FakeMouseEvent(evt);
if (evt.getNativeButton() == NativeEvent.BUTTON_RIGHT) {
rightClick = true;
}
if (!rightClick) {
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
a.onMouseDown(new ACTMouseEvent(evt));
setCursor(a.getCursor());
private void onTouchEnded(TouchEvent evt) {
evt.preventDefault();
drag = false;
Action a = toolBar.getCurrentAction();
if (a != null && !a.isCommand()) {
FakeMouseEvent thisEvt = new FakeMouseEvent(evt, mousePoint);
FakeMouseEvent syntheticEvt = null;
if (mousePressEvt != null && isSmallMovement(thisEvt, mousePressEvt)) {
syntheticEvt = mousePressEvt;
} else {
syntheticEvt = thisEvt;
}
if (a.onMouseUp(syntheticEvt)) {
drawPane.draw();
model.changed();
}
}
setCursor(ICursor.DEFAULT);
rightClick = false;
mousePressEvt = null;
mousePoint = null;
}

private boolean isSmallMovement(FakeMouseEvent evt1, FakeMouseEvent evt2) {

0 comments on commit bc41dcc

Please sign in to comment.