/*
* Copyright 2015 Eckhart Arnold (eckhart_arnold@hotmail.com).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.eckhartarnold.client;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
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.AbsolutePanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Widget;
/**
* Simple touch screen controls for the image panel.
*
* Allows the slideshow to be controlled by touching (or clicking) on certain
* areas of the screen:
* - a touch on the left edge stops the slideshow and shows the previous image
* - a touch on the right edge stops the lisdeshow and moves on to the next
* image
* - a touch in the center starts or stops the slideshow
* - a touch on the upper edge of the screen returns to the gallery or the
* first picture depending on the kind of presentation (gallery presentation
* or slideshow presentation) that has been configured.
*
* @author eckhart
*/
public class TouchControls implements AttachmentListener, SlideshowControl,
TouchStartHandler, MouseDownHandler { // , MouseMoveHandler, MouseUpHandler, ClickHandler {
// private class FadeOut extends Fade {
// FadeOut(Widget widget) {
// super(widget, 1.0, 0.0, FADE_STEPS);;
// }
//
// @Override
// protected void onComplete() {
// super.onComplete();
// }
// }
private class FadeHomeButton extends Fade {
private ClickEvent event;
FadeHomeButton(Widget widget, ClickEvent event) {
super(widget);
}
@Override
protected void onComplete() {
super.onComplete();
// panel.remove(widget);
if (homeButtonHandler != null) {
homeButtonHandler.onClick(event);
}
}
}
protected static final double FADE_STEPS = 0.10;
private static final int FIRST = 0, BACK = 0, BACK_DOWN = 1, NEXT = 2,
NEXT_DOWN = 3, HOME = 4, HOME_DOWN = 5, PLAY = 6, PAUSE = 7, LAST = 7;
private int buttonDown = -1;
private Fade fader;
private ClickHandler homeButtonHandler = null;
private ImagePanel imagePanel;
private Image[] symbol = new Image[8];
private Slideshow slideshow;
private boolean touched = false;
public TouchControls(Slideshow slideshow) {
this.slideshow = slideshow;
imagePanel = slideshow.getImagePanel();
imagePanel.addMouseDownHandler(this);
imagePanel.addTouchStartHandler(this);
symbol[BACK] = new Image("icons/back.svg");
symbol[BACK_DOWN] = new Image("icons/back.svg");
symbol[NEXT] = new Image("icons/next.svg");
symbol[NEXT_DOWN] = new Image("icons/next.svg");
symbol[HOME] = new Image("icons/gallery.svg");
symbol[HOME_DOWN] = new Image("icons/gallery.svg");
symbol[PLAY] = new Image("icons/play.svg");
symbol[PAUSE] = new Image("icons/pause.svg");
for (int i = FIRST; i <= LAST; i++) {
if (i == BACK_DOWN || i == NEXT_DOWN || i == HOME_DOWN) {
symbol[i].addStyleName("touchDown");
} else {
symbol[i].addStyleName("touch");
}
Fade.setOpacity(symbol[i], 0.0);
}
imagePanel.addAttachmentListener(this);
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google.gwt.event.dom.client.MouseDownEvent)
*/
@Override
public void onMouseDown(MouseDownEvent event) {
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
if (touched) {
touched = false;
} else {
buttonDown = buttonTouched(event.getX(), event.getY());
touch(event.getX(), event.getY());
}
}
// int button = buttonTouched(event.getX(), event.getY());
// buttonDown = button;
// Rectangle r = buttonBoundary(button);
// if (button >= FIRST && button <= LAST) {
// if (button == BACK || button == NEXT || button == HOME) {
// button++;
// } else if (button == PLAY) {
// if (slideshow.isRunning()) {
// button = PAUSE;
// }
// }
// showWidget(symbol[button], r.x, r.y, r.w, r.h);
// hideAllOtherWidgets(symbol[button]);
// fader = new Fade(symbol[button], 0.0, 1.0, FADE_STEPS);
// fader.run(100);
// }
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.SlideshowControl#setHomeButtonListener(com.google.gwt.event.dom.client.ClickHandler)
*/
@Override
public void setHomeButtonListener(ClickHandler handler) {
homeButtonHandler = handler;
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.AttachmentListener#onLoad(com.google.gwt.user.client.ui.Widget)
*/
@Override
public void onLoad(Widget sender) {
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.AttachmentListener#onUnload(com.google.gwt.user.client.ui.Widget)
*/
@Override
public void onUnload(Widget sender) {
hideAllOtherWidgets(null);
}
@Override
public void onTouchStart(TouchStartEvent event) {
JsArray<Touch> touches = event.getTouches();
// Debugger.print("TouchControls.onTouchStart() touches.length = " + touches.length());
if (touches.length() > 0) {
// Debugger.print("TouchControls.onTouchStart() x = " + touches.get(0).getClientX() + " y = " + touches.get(0).getClientY());
int x = touches.get(0).getClientX();
int y = touches.get(0).getClientY();
buttonDown = buttonTouched(x, y);
touched = true;
touch(x, y);
}
}
/**
* Returns the screen boundary for the visual feedback of a particular touch
* button.
*
* @param button the button for which the boundary rectangle shall be
* returned
* @return the boundary rectangle for the given button.
*/
protected Rectangle buttonBoundary(int button) {
int w = imagePanel.getOffsetWidth();
int h = Toolbox.getOffsetHeight(this.imagePanel);
if (button == BACK || button == BACK_DOWN) {
return new Rectangle(0, h/8, w/5, h*6/8);
} else if (button == NEXT || button == NEXT_DOWN) {
return new Rectangle(w*4/5, h/8, w/5, h*6/8);
} else if (button == HOME || button == HOME_DOWN) {
return new Rectangle(w/4, 0, w/2, h/4);
} else if (button == PLAY || button == PAUSE) {
return new Rectangle(w/4, h/4, w/2, h/2);
} else {
return new Rectangle(0, 0, 0, 0);
}
}
/**
* Determines which touch area, if any, has been hit by a touch or click
* on the screen.
*
* @param x the x coordinate of the click event.
* @param y the y coordinate of the click event.
* @return BACK, NEXT, HOME, PLAY if any of the respective areas has been
* hit or -1 if no area has been hit.
*/
protected int buttonTouched(int x, int y) {
int w = imagePanel.getOffsetWidth();
int h = Toolbox.getOffsetHeight(this.imagePanel);
if (y < h * 7 / 8) {
if (x < w / 4) {
return BACK;
} else if (x > w * 3 / 4) {
return NEXT;
} else if (y < h / 4) {
return HOME;
} else {
return PLAY;
}
}
return -1;
}
/**
* Reaction for a touch event on the panel.
*
* @param x x-position of the event
* @param y y-position of the event
*/
protected void touch(int x, int y) {
int button = buttonTouched(x, y);
if (buttonDown == -1 || button != buttonDown) {
hideAllOtherWidgets(null);
buttonDown = -1;
return;
}
Rectangle r = buttonBoundary(button);
if (button == BACK) {
visualFeedBack(symbol[BACK], r.x, r.y, r.w, r.h);
slideshow.stop();
slideshow.back();
} else if (button == NEXT) {
visualFeedBack(symbol[NEXT], r.x, r.y, r.w, r.h);
slideshow.stop();
slideshow.next();
} else if (button == HOME) {
showWidget(symbol[HOME], r.x, r.y, r.w, r.h);
hideAllOtherWidgets(symbol[HOME]);
// homeButtonHandler.onClick(null);
fader = new FadeHomeButton(symbol[HOME], null); // TODO: using null here is a hack!!! Need to refactor home button listener logic.
fader.run(200);
} else if (button == PLAY){
if (slideshow.isRunning()) {
visualFeedBack(symbol[PAUSE],r.x, r.y, r.w, r.h);
slideshow.stop();
} else {
visualFeedBack(symbol[PLAY], r.x, r.y, r.w, r.h);
slideshow.next();
slideshow.start();
}
} else {
hideAllOtherWidgets(null);
}
buttonDown = -1;
}
private void hideAllOtherWidgets(Image except) {
AbsolutePanel panel = imagePanel.getPanel();
for (int i = FIRST; i <= LAST; i++) {
if (symbol[i] != except && panel.getWidgetIndex(symbol[i]) >= 0) {
Fade.setOpacity(symbol[i], 0.0);
panel.remove(symbol[i]);
}
}
}
private void showWidget(Image img, int x, int y, int w, int h) {
int ww = w, hh = h, dx = 0, dy = 0;
if (w > h / 2) {
ww = h / 2;
dx = (w - ww) / 2;
} else {
hh = w * 2;
dy = (h - hh) / 2;
}
AbsolutePanel panel = imagePanel.getPanel();
panel.add(img);
img.setPixelSize(ww, hh);
panel.setWidgetPosition(img, x + dx, y + dy);
}
private void visualFeedBack(Image img, int x, int y, int w, int h) {
showWidget(img, x, y, w, h);
hideAllOtherWidgets(img);
fader = new Fade(img, 1.0, 0.0, FADE_STEPS);
fader.run(500);
}
}