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

Add touch handling for component helper widgets (#1251)

Implementation of the drag and drop support for the designer did not
handle touch events on the help and remove extension buttons in the
palette. This commit adds the corresponding implementations to improve
touch support.

Change-Id: I7a877683da6421c67104f4fb704e7c35fd90f578
parent 2db96fcc
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2018 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.editor.simple.palette;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.Image;
/**
* AbstractPaletteItemWidget provides a common superclass for buttons presented in the
* {@link SimplePaletteItem} for a component.
*/
public abstract class AbstractPaletteItemWidget extends Image {
protected final SimpleComponentDescriptor scd;
AbstractPaletteItemWidget(SimpleComponentDescriptor scd, ImageResource image) {
this.scd = scd;
AbstractImagePrototype.create(image).applyTo(this);
this.addStyleName("ode-SimplePaletteItem-button");
addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
handleClick();
}
});
addTouchStartHandler(new TouchStartHandler() {
@Override
public void onTouchStart(TouchStartEvent touchStartEvent) {
// Otherwise captured by SimplePaletteItem
touchStartEvent.stopPropagation();
}
});
addTouchEndHandler(new TouchEndHandler() {
@Override
public void onTouchEnd(TouchEndEvent touchEndEvent) {
handleClick();
}
});
}
/**
* Handles when the user clicks (or taps) on the button.
*/
protected abstract void handleClick();
}
// -*- 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-2018 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.editor.simple.palette; package com.google.appinventor.client.editor.simple.palette;
import com.google.appinventor.client.Images;
import com.google.appinventor.client.Ode;
import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.client.ComponentsTranslation; import com.google.appinventor.client.ComponentsTranslation;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.utils.PZAwarePositionCallback; import com.google.appinventor.client.utils.PZAwarePositionCallback;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.resources.client.ImageResource; import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupListener;
import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import static com.google.appinventor.client.Ode.MESSAGES;
/** /**
* Defines a widget that has the appearance of a question mark and * Defines a widget that has the appearance of a question mark and
* creates a popup with information about a component when it is clicked on. * creates a popup with information about a component when it is clicked on.
* *
*/ */
public final class ComponentHelpWidget extends Image { public final class ComponentHelpWidget extends AbstractPaletteItemWidget {
private static ImageResource imageResource = null; private static final ImageResource imageResource = Ode.getImageBundle().help();
// Keep track of the last time (in milliseconds) of the last closure // Keep track of the last time (in milliseconds) of the last closure
// so we don't reopen a popup too soon after closing it. Specifically, // so we don't reopen a popup too soon after closing it. Specifically,
...@@ -41,8 +37,7 @@ public final class ComponentHelpWidget extends Image { ...@@ -41,8 +37,7 @@ public final class ComponentHelpWidget extends Image {
private class ComponentHelpPopup extends PopupPanel { private class ComponentHelpPopup extends PopupPanel {
private ComponentHelpPopup(final SimpleComponentDescriptor scd, private ComponentHelpPopup() {
final Widget sender) {
// Create popup panel. // Create popup panel.
super(true); super(true);
setStyleName("ode-ComponentHelpPopup"); setStyleName("ode-ComponentHelpPopup");
...@@ -108,16 +103,16 @@ public final class ComponentHelpWidget extends Image { ...@@ -108,16 +103,16 @@ public final class ComponentHelpWidget extends Image {
// When the panel is closed, save the time in milliseconds. // When the panel is closed, save the time in milliseconds.
// This will help us avoid immediately reopening it if the user // This will help us avoid immediately reopening it if the user
// closed it by clicking on the question-mark icon. // closed it by clicking on the question-mark icon.
addPopupListener(new PopupListener() { addCloseHandler(new CloseHandler<PopupPanel>() {
@Override @Override
public void onPopupClosed(PopupPanel sender, boolean autoClosed) { public void onClose(CloseEvent<PopupPanel> event) {
lastClosureTime = System.currentTimeMillis(); lastClosureTime = System.currentTimeMillis();
} }
}); });
// Use a Pinch Zoom aware PopupPanel.PositionCallback to handle positioning to // Use a Pinch Zoom aware PopupPanel.PositionCallback to handle positioning to
// avoid the Google Chrome Pinch Zoom bug. // avoid the Google Chrome Pinch Zoom bug.
setPopupPositionAndShow(new PZAwarePositionCallback(sender.getElement()) { setPopupPositionAndShow(new PZAwarePositionCallback(ComponentHelpWidget.this.getElement()) {
@Override @Override
public void setPosition(int offsetWidth, int offsetHeight) { public void setPosition(int offsetWidth, int offsetHeight) {
// Position the upper-left of the panel just to the right of the // Position the upper-left of the panel just to the right of the
...@@ -130,8 +125,8 @@ public final class ComponentHelpWidget extends Image { ...@@ -130,8 +125,8 @@ public final class ComponentHelpWidget extends Image {
Math.max(0, Window.getClientHeight() Math.max(0, Window.getClientHeight()
- offsetHeight + Y_OFFSET))); - offsetHeight + Y_OFFSET)));
} else { } else {
setPopupPosition(sender.getAbsoluteLeft() + X_OFFSET, setPopupPosition(ComponentHelpWidget.this.getAbsoluteLeft() + X_OFFSET,
Math.min(sender.getAbsoluteTop() + Y_OFFSET, Math.min(ComponentHelpWidget.this.getAbsoluteTop() + Y_OFFSET,
Math.max(0, Window.getClientHeight() Math.max(0, Window.getClientHeight()
- offsetHeight + Y_OFFSET))); - offsetHeight + Y_OFFSET)));
} }
...@@ -141,22 +136,16 @@ public final class ComponentHelpWidget extends Image { ...@@ -141,22 +136,16 @@ public final class ComponentHelpWidget extends Image {
} }
public ComponentHelpWidget(final SimpleComponentDescriptor scd) { public ComponentHelpWidget(final SimpleComponentDescriptor scd) {
if (imageResource == null) { super(scd, imageResource);
Images images = Ode.getImageBundle();
imageResource = images.help();
} }
AbstractImagePrototype.create(imageResource).applyTo(this);
addClickListener(new ClickListener() {
@Override @Override
public void onClick(Widget sender) { protected void handleClick() {
final long MINIMUM_MS_BETWEEN_SHOWS = 250; // .25 seconds final long MINIMUM_MS_BETWEEN_SHOWS = 250; // .25 seconds
if (System.currentTimeMillis() - lastClosureTime >= if (System.currentTimeMillis() - lastClosureTime >=
MINIMUM_MS_BETWEEN_SHOWS) { MINIMUM_MS_BETWEEN_SHOWS) {
new ComponentHelpPopup(scd, sender); new ComponentHelpPopup();
}
}
} }
);
} }
} }
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015-2016 MIT, All rights reserved // Copyright 2015-2018 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.editor.simple.palette; package com.google.appinventor.client.editor.simple.palette;
import com.google.appinventor.client.Images;
import com.google.appinventor.client.Ode; import com.google.appinventor.client.Ode;
import com.google.appinventor.client.editor.simple.SimpleComponentDatabase; import com.google.appinventor.client.editor.simple.SimpleComponentDatabase;
import com.google.appinventor.client.editor.youngandroid.YaBlocksEditor;
import com.google.appinventor.client.editor.youngandroid.YaProjectEditor; import com.google.appinventor.client.editor.youngandroid.YaProjectEditor;
import com.google.gwt.resources.client.ImageResource; import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Widget;
import static com.google.appinventor.client.Ode.MESSAGES; import static com.google.appinventor.client.Ode.MESSAGES;
...@@ -23,24 +17,17 @@ import static com.google.appinventor.client.Ode.MESSAGES; ...@@ -23,24 +17,17 @@ import static com.google.appinventor.client.Ode.MESSAGES;
* Defines a widget that has the appearance of a red close button. * Defines a widget that has the appearance of a red close button.
* The Widget is clicked to delete the associated component * The Widget is clicked to delete the associated component
*/ */
public class ComponentRemoveWidget extends Image { public class ComponentRemoveWidget extends AbstractPaletteItemWidget {
private static ImageResource imageResource = null; private static final ImageResource imageResource = Ode.getImageBundle().deleteComponent();
private static Ode ode = Ode.getInstance(); private static final Ode ode = Ode.getInstance();
private final SimpleComponentDescriptor scd;
public ComponentRemoveWidget(SimpleComponentDescriptor simpleComponentDescriptor) { public ComponentRemoveWidget(SimpleComponentDescriptor simpleComponentDescriptor) {
if (imageResource == null) { super(simpleComponentDescriptor, imageResource);
Images images = Ode.getImageBundle();
imageResource = images.deleteComponent();
} }
this.scd = simpleComponentDescriptor;
AbstractImagePrototype.create(imageResource).applyTo(this);
addClickListener(new ClickListener() {
@Override @Override
public void onClick(Widget widget) { protected void handleClick() {
if (Window.confirm(MESSAGES.reallyRemoveComponent())) { if (Window.confirm(MESSAGES.reallyRemoveComponent())) {
long projectId = ode.getCurrentYoungAndroidProjectId(); long projectId = ode.getCurrentYoungAndroidProjectId();
YaProjectEditor projectEditor = (YaProjectEditor) ode.getEditorManager().getOpenProjectEditor(projectId); YaProjectEditor projectEditor = (YaProjectEditor) ode.getEditorManager().getOpenProjectEditor(projectId);
...@@ -49,6 +36,4 @@ public class ComponentRemoveWidget extends Image { ...@@ -49,6 +36,4 @@ public class ComponentRemoveWidget extends Image {
componentDatabase.removeComponent(scd.getName()); componentDatabase.removeComponent(scd.getName());
} }
} }
});
}
} }
...@@ -69,13 +69,11 @@ public class SimplePaletteItem extends DragSourcePanel { ...@@ -69,13 +69,11 @@ public class SimplePaletteItem extends DragSourcePanel {
HorizontalPanel optPanel = new HorizontalPanel(); HorizontalPanel optPanel = new HorizontalPanel();
ComponentHelpWidget helpImage = new ComponentHelpWidget(scd); ComponentHelpWidget helpImage = new ComponentHelpWidget(scd);
helpImage.addStyleName("ode-SimplePalleteItem-button");
optPanel.add(helpImage); optPanel.add(helpImage);
optPanel.setCellHorizontalAlignment(helpImage, HorizontalPanel.ALIGN_LEFT); optPanel.setCellHorizontalAlignment(helpImage, HorizontalPanel.ALIGN_LEFT);
if (scd.getExternal()) { if (scd.getExternal()) {
ComponentRemoveWidget deleteImage = new ComponentRemoveWidget(scd); ComponentRemoveWidget deleteImage = new ComponentRemoveWidget(scd);
deleteImage.addStyleName("ode-SimplePalleteItem-button");
optPanel.add(deleteImage); optPanel.add(deleteImage);
optPanel.setCellHorizontalAlignment(deleteImage, HorizontalPanel.ALIGN_RIGHT); optPanel.setCellHorizontalAlignment(deleteImage, HorizontalPanel.ALIGN_RIGHT);
} }
......
...@@ -825,7 +825,7 @@ select { ...@@ -825,7 +825,7 @@ select {
color: #555; color: #555;
} }
.ode-SimplePalleteItem-button { .ode-SimplePaletteItem-button {
padding: 2px; padding: 2px;
} }
......
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