Commit 25444cce authored by Evan W. Patton's avatar Evan W. Patton Committed by Jeffrey Schiller

Implement touch support for designer drag-and-drop (#1047)

Author: Evan W. Patton <ewpatton@mit.edu>

Make sure that touches select the components
Implement drag-and-drop to reorder components

Closes #1020

Change-Id: If33b569dbf76d08df411185e0efac546df253409
parent 647312c7
...@@ -39,11 +39,23 @@ import com.google.appinventor.shared.simple.ComponentDatabaseInterface; ...@@ -39,11 +39,23 @@ import com.google.appinventor.shared.simple.ComponentDatabaseInterface;
import com.google.appinventor.shared.storage.StorageUtil; import com.google.appinventor.shared.storage.StorageUtil;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasAllTouchHandlers;
import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.TouchCancelHandler;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.dom.client.TouchCancelEvent;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.DeferredCommand;
...@@ -83,7 +95,7 @@ import java.util.Map; ...@@ -83,7 +95,7 @@ import java.util.Map;
* @author lizlooney@google.com (Liz Looney) * @author lizlooney@google.com (Liz Looney)
*/ */
public abstract class MockComponent extends Composite implements PropertyChangeListener, public abstract class MockComponent extends Composite implements PropertyChangeListener,
SourcesMouseEvents, DragSource { SourcesMouseEvents, DragSource, HasAllTouchHandlers {
// Common property names (not all components support all properties). // Common property names (not all components support all properties).
public static final String PROPERTY_NAME_NAME = "Name"; public static final String PROPERTY_NAME_NAME = "Name";
public static final String PROPERTY_NAME_UUID = "Uuid"; public static final String PROPERTY_NAME_UUID = "Uuid";
...@@ -302,6 +314,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -302,6 +314,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
private MockContainer container; private MockContainer container;
private MouseListenerCollection mouseListeners = new MouseListenerCollection(); private MouseListenerCollection mouseListeners = new MouseListenerCollection();
private HandlerManager handlers;
/** /**
* Creates a new instance of the component. * Creates a new instance of the component.
...@@ -312,6 +325,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -312,6 +325,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
this.editor = editor; this.editor = editor;
this.type = type; this.type = type;
this.iconImage = iconImage; this.iconImage = iconImage;
this.handlers = new HandlerManager(this);
COMPONENT_DATABASE = SimpleComponentDatabase.getInstance(editor.getProjectId()); COMPONENT_DATABASE = SimpleComponentDatabase.getInstance(editor.getProjectId());
componentDefinition = COMPONENT_DATABASE.getComponentDefinition(type); componentDefinition = COMPONENT_DATABASE.getComponentDefinition(type);
...@@ -374,6 +388,10 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -374,6 +388,10 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
if (!isForm()) { if (!isForm()) {
dragSourceSupport = new DragSourceSupport(this); dragSourceSupport = new DragSourceSupport(this);
addMouseListener(dragSourceSupport); addMouseListener(dragSourceSupport);
addTouchStartHandler(dragSourceSupport);
addTouchMoveHandler(dragSourceSupport);
addTouchEndHandler(dragSourceSupport);
addTouchCancelHandler(dragSourceSupport);
} }
} }
...@@ -390,7 +408,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -390,7 +408,7 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
initWidget(widget); initWidget(widget);
// Capture mouse and click events in onBrowserEvent(Event) // Capture mouse and click events in onBrowserEvent(Event)
sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK); sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.TOUCHEVENTS);
// Add the special name property and set the tooltip // Add the special name property and set the tooltip
String name = componentName(); String name = componentName();
...@@ -823,6 +841,17 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -823,6 +841,17 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
public void onBrowserEvent(Event event) { public void onBrowserEvent(Event event) {
if (!shouldCancel(event)) return; if (!shouldCancel(event)) return;
switch (event.getTypeInt()) { switch (event.getTypeInt()) {
case Event.ONTOUCHSTART:
case Event.ONTOUCHEND:
if (isForm()) {
select();
}
case Event.ONTOUCHMOVE:
case Event.ONTOUCHCANCEL:
cancelBrowserEvent(event);
DomEvent.fireNativeEvent(event, handlers);
break;
case Event.ONMOUSEDOWN: case Event.ONMOUSEDOWN:
case Event.ONMOUSEUP: case Event.ONMOUSEUP:
case Event.ONMOUSEMOVE: case Event.ONMOUSEMOVE:
...@@ -870,6 +899,26 @@ public abstract class MockComponent extends Composite implements PropertyChangeL ...@@ -870,6 +899,26 @@ public abstract class MockComponent extends Composite implements PropertyChangeL
mouseListeners.remove(listener); mouseListeners.remove(listener);
} }
@Override
public final HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
return handlers.addHandler(TouchStartEvent.getType(), handler);
}
@Override
public final HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
return handlers.addHandler(TouchMoveEvent.getType(), handler);
}
@Override
public final HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
return handlers.addHandler(TouchEndEvent.getType(), handler);
}
@Override
public final HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
return handlers.addHandler(TouchCancelEvent.getType(), handler);
}
// DragSource implementation // DragSource implementation
@Override @Override
......
...@@ -14,6 +14,8 @@ import com.google.appinventor.client.widgets.dnd.DragSourceSupport; ...@@ -14,6 +14,8 @@ import com.google.appinventor.client.widgets.dnd.DragSourceSupport;
import com.google.appinventor.client.widgets.dnd.DropTarget; import com.google.appinventor.client.widgets.dnd.DropTarget;
import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Label;
...@@ -108,6 +110,12 @@ public class SimplePaletteItem extends DragSourcePanel { ...@@ -108,6 +110,12 @@ public class SimplePaletteItem extends DragSourcePanel {
select(getWidget()); select(getWidget());
} }
}); });
addTouchStartHandler(new TouchStartHandler() {
@Override
public void onTouchStart(TouchStartEvent event) {
select(getWidget());
}
});
} }
/** /**
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2017 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -31,5 +31,9 @@ public abstract class DragSourcePanel extends FocusPanel implements DragSource { ...@@ -31,5 +31,9 @@ public abstract class DragSourcePanel extends FocusPanel implements DragSource {
// Listen for drag gestures on self // Listen for drag gestures on self
dragSourceSupport = new DragSourceSupport(this); dragSourceSupport = new DragSourceSupport(this);
addMouseListener(dragSourceSupport); addMouseListener(dragSourceSupport);
addTouchStartHandler(dragSourceSupport);
addTouchMoveHandler(dragSourceSupport);
addTouchEndHandler(dragSourceSupport);
addTouchCancelHandler(dragSourceSupport);
} }
} }
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2017 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.widgets.dnd; package com.google.appinventor.client.widgets.dnd;
import com.google.appinventor.client.editor.simple.components.MockComponent;
import com.google.appinventor.client.output.OdeLog; import com.google.appinventor.client.output.OdeLog;
import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
...@@ -15,13 +16,22 @@ import com.google.gwt.user.client.ui.MouseListener; ...@@ -15,13 +16,22 @@ import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchCancelHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchCancelEvent;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.dom.client.Touch;
/** /**
* Provides support for dragging from a {@link DragSource} * Provides support for dragging from a {@link DragSource}
* (typically a widget) to a {@link DropTarget}. * (typically a widget) to a {@link DropTarget}.
* *
*/ */
public final class DragSourceSupport implements MouseListener { public final class DragSourceSupport implements MouseListener, TouchStartHandler, TouchMoveHandler, TouchCancelHandler, TouchEndHandler {
/** /**
* Interface to functionality provided by the {@link DOM} class. * Interface to functionality provided by the {@link DOM} class.
* Used as a testing seam. * Used as a testing seam.
...@@ -373,6 +383,52 @@ public final class DragSourceSupport implements MouseListener { ...@@ -373,6 +383,52 @@ public final class DragSourceSupport implements MouseListener {
return dragWidgetPopup.getWidget(); return dragWidgetPopup.getWidget();
} }
// Touch Handler Implementation
/**
* Call the equivalent mouse event handler for each touch event
*/
@Override
public void onTouchStart(TouchStartEvent event) {
event.preventDefault();
Widget src = (Widget) event.getSource();
Touch touch = event.getTargetTouches().get(0);
com.google.gwt.dom.client.Element target = com.google.gwt.dom.client.Element.as(touch.getTarget());
int x = touch.getRelativeX(target);
int y = touch.getRelativeY(target);
onMouseDown(src, x, y);
}
@Override
public void onTouchMove(TouchMoveEvent event) {
Widget src = (Widget) event.getSource();
Touch touch = event.getTargetTouches().get(0);
com.google.gwt.dom.client.Element target = com.google.gwt.dom.client.Element.as(touch.getTarget());
int x = touch.getRelativeX(target);
int y = touch.getRelativeY(target);
onMouseMove(src, x, y);
}
@Override
public void onTouchEnd(TouchEndEvent event) {
final Widget src = (Widget) event.getSource();
if (src instanceof MockComponent) { // We only select on CLICK, which isn't generated on mobile
DeferredCommand.addCommand(new Command() {
@Override
public void execute() {
((MockComponent) src).select();
}
});
}
onMouseUp(src, dragX, dragY);
}
@Override
public void onTouchCancel(TouchCancelEvent event) {
Widget src = (Widget) event.getSource();
onMouseLeave(src);
}
// Drag handling // Drag handling
private void onDragStart(Widget sender, int x, int y) { private void onDragStart(Widget sender, int x, int y) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment