Commit 461f0b7b authored by Nico Mack's avatar Nico Mack

Major overhaul of touch mechanism.

Extension of touch mechanism by introducing distinct tap event.
parent 0a1f88a2
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
*/ */
package lu.list.itis.dkd.tui.widget.animation; package lu.list.itis.dkd.tui.widget.animation;
import java.util.List; import java.util.Collection;
/** /**
* @author mack * @author mack
...@@ -37,7 +37,7 @@ public interface Animated { ...@@ -37,7 +37,7 @@ public interface Animated {
/** /**
* @return * @return
*/ */
public List<AnimationProperty<?>> getAnimationProperties(); public Collection<AnimationProperty<?>> getAnimationProperties();
/** /**
* *
......
...@@ -16,12 +16,11 @@ ...@@ -16,12 +16,11 @@
*/ */
package lu.list.itis.dkd.tui.widget.animation; package lu.list.itis.dkd.tui.widget.animation;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
// *************************************************************************** // ***************************************************************************
// * Class Definition and Members * // * Class Definition and Members *
...@@ -34,7 +33,7 @@ import java.util.List; ...@@ -34,7 +33,7 @@ import java.util.List;
*/ */
public class AnimationEventSource { public class AnimationEventSource {
private ArrayList<AnimationListener> listeners; private ArrayList<AnimationListener> listeners;
private Multimap<Integer, AnimationListener> keyframes; private Map<Integer, List<AnimationListener>> keyframes;
// *************************************************************************** // ***************************************************************************
// * Constants * // * Constants *
...@@ -51,7 +50,7 @@ public class AnimationEventSource { ...@@ -51,7 +50,7 @@ public class AnimationEventSource {
*/ */
public AnimationEventSource() { public AnimationEventSource() {
listeners = new ArrayList<>(); listeners = new ArrayList<>();
keyframes = TreeMultimap.create(); keyframes = new HashMap<>();
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -81,7 +80,10 @@ public class AnimationEventSource { ...@@ -81,7 +80,10 @@ public class AnimationEventSource {
*/ */
public void addAnimationListenerAtKeyFrame(AnimationListener listener, int keyFrame) { public void addAnimationListenerAtKeyFrame(AnimationListener listener, int keyFrame) {
listeners.add(listener); listeners.add(listener);
keyframes.put(keyFrame, listener); if (!keyframes.containsKey(listener)) {
keyframes.put(keyFrame, new ArrayList<>());
}
keyframes.get(keyFrame).add(listener);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -90,7 +92,9 @@ public class AnimationEventSource { ...@@ -90,7 +92,9 @@ public class AnimationEventSource {
* @param listener * @param listener
*/ */
public void addAnimationListener(AnimationListener listener) { public void addAnimationListener(AnimationListener listener) {
listeners.add(listener); if (!listeners.contains(listener)) {
listeners.add(listener);
}
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
......
...@@ -25,7 +25,7 @@ package lu.list.itis.dkd.tui.widget.animation; ...@@ -25,7 +25,7 @@ package lu.list.itis.dkd.tui.widget.animation;
// * Interface Definition and Members * // * Interface Definition and Members *
// *************************************************************************** // ***************************************************************************
public interface AnimationListener extends Comparable<Object> { public interface AnimationListener {
/** /**
* @param event * @param event
......
...@@ -103,6 +103,24 @@ public class AnimationProperty<T> implements TimelineCallback { ...@@ -103,6 +103,24 @@ public class AnimationProperty<T> implements TimelineCallback {
// * Class Body * // * Class Body *
// *************************************************************************** // ***************************************************************************
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/**
* @param listener
*/
// ---------------------------------------------------------------------------
public void addAnimationListener(AnimationListener listener) {
listeners.addAnimationListener(listener);
}
// ---------------------------------------------------------------------------
/**
* @param listener
*/
// ---------------------------------------------------------------------------
public void removeAnimationListener(AnimationListener listener) {
listeners.removeAnimationListener(listener);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
...@@ -220,10 +238,10 @@ public class AnimationProperty<T> implements TimelineCallback { ...@@ -220,10 +238,10 @@ public class AnimationProperty<T> implements TimelineCallback {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
* Allows controlling looping behavior. When reversing is enabled, (<code>true</code>), * Allows controlling looping behavior. When reversing is enabled, (<code>true</code>), animation
* animation plays back and forth whenever the end is reached. Specify <code>false</code> to * plays back and forth whenever the end is reached. Specify <code>false</code> to disable
* disable reversing. It should be noted that reversing requires the looping property to be set * reversing. It should be noted that reversing requires the looping property to be set in order to
* in order to have any effect * have any effect
* *
* @param reversing * @param reversing
* <code>true</code> to enable reversing, <code>false</code> to disable * <code>true</code> to enable reversing, <code>false</code> to disable
...@@ -318,11 +336,13 @@ public class AnimationProperty<T> implements TimelineCallback { ...@@ -318,11 +336,13 @@ public class AnimationProperty<T> implements TimelineCallback {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
* starts the animation of the property represented by this instance * starts the animation of the property represented by this instance
*
* @param backwards
*/ */
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@SuppressWarnings("incomplete-switch") @SuppressWarnings("incomplete-switch")
public void start() { public void start(boolean backwards) {
if (timeline != null) { if (timeline != null) {
...@@ -338,6 +358,8 @@ public class AnimationProperty<T> implements TimelineCallback { ...@@ -338,6 +358,8 @@ public class AnimationProperty<T> implements TimelineCallback {
if (looping) { if (looping) {
timeline.playLoop((reversing ? RepeatBehavior.REVERSE : RepeatBehavior.LOOP)); timeline.playLoop((reversing ? RepeatBehavior.REVERSE : RepeatBehavior.LOOP));
} else if (backwards) {
timeline.playReverse();
} else { } else {
timeline.play(); timeline.play();
} }
...@@ -387,6 +409,7 @@ public class AnimationProperty<T> implements TimelineCallback { ...@@ -387,6 +409,7 @@ public class AnimationProperty<T> implements TimelineCallback {
direction = Direction.NONE; direction = Direction.NONE;
keyFrameIterator = null; keyFrameIterator = null;
nextKeyFrame = null; nextKeyFrame = null;
this.listeners.notifyAnimationListener(new AnimationEvent(this, AnimationEvent.AnimationState.DONE));
break; break;
// $CASES-OMITTED$ // $CASES-OMITTED$
default: default:
......
...@@ -31,9 +31,8 @@ import java.beans.Introspector; ...@@ -31,9 +31,8 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
...@@ -47,7 +46,7 @@ import java.util.Map; ...@@ -47,7 +46,7 @@ import java.util.Map;
public abstract class AnimatedCorona extends Corona implements Animated { public abstract class AnimatedCorona extends Corona implements Animated {
protected List<AnimationProperty<?>> animationProperties; protected Map<String, AnimationProperty<?>> animationProperties;
protected Map<String, Method> animationSetters; protected Map<String, Method> animationSetters;
private static final Logger LOGGER = LoggerFactory.getLogger(AnimatedCorona.class.getSimpleName()); private static final Logger LOGGER = LoggerFactory.getLogger(AnimatedCorona.class.getSimpleName());
...@@ -81,7 +80,7 @@ public abstract class AnimatedCorona extends Corona implements Animated { ...@@ -81,7 +80,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
public AnimatedCorona(AnimatedCorona original) { public AnimatedCorona(AnimatedCorona original) {
super(original); super(original);
animationProperties = new ArrayList<>(original.animationProperties); animationProperties = new HashMap<>(original.animationProperties);
this.validateAnimationProperties(); this.validateAnimationProperties();
} }
...@@ -95,7 +94,7 @@ public abstract class AnimatedCorona extends Corona implements Animated { ...@@ -95,7 +94,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
private void validateAnimationProperties() { private void validateAnimationProperties() {
animationSetters = getAnimationSetters(this.getClass()); animationSetters = getAnimationSetters(this.getClass());
for (AnimationProperty<?> property : animationProperties) { for (AnimationProperty<?> property : animationProperties.values()) {
if (!animationSetters.containsKey(property.getProperty())) { if (!animationSetters.containsKey(property.getProperty())) {
LOGGER.error("Corona {} does not support animated Property {}!", this.getClass().getName(), property.getProperty()); //$NON-NLS-1$ LOGGER.error("Corona {} does not support animated Property {}!", this.getClass().getName(), property.getProperty()); //$NON-NLS-1$
} }
...@@ -153,8 +152,19 @@ public abstract class AnimatedCorona extends Corona implements Animated { ...@@ -153,8 +152,19 @@ public abstract class AnimatedCorona extends Corona implements Animated {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public List<AnimationProperty<?>> getAnimationProperties() { public Collection<AnimationProperty<?>> getAnimationProperties() {
return animationProperties; return animationProperties.values();
}
// ---------------------------------------------------------------------------
/**
* @param identifier
* @return
*/
// ---------------------------------------------------------------------------
public AnimationProperty<?> getAnimatedProperty(String identifier) {
return animationProperties.get(identifier);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -168,9 +178,9 @@ public abstract class AnimatedCorona extends Corona implements Animated { ...@@ -168,9 +178,9 @@ public abstract class AnimatedCorona extends Corona implements Animated {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void start() { public void start() {
for (AnimationProperty<?> property : animationProperties) { for (AnimationProperty<?> property : animationProperties.values()) {
property.setAnimatedObject(this); property.setAnimatedObject(this);
property.start(); property.start(false);
} }
} }
...@@ -179,7 +189,7 @@ public abstract class AnimatedCorona extends Corona implements Animated { ...@@ -179,7 +189,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void stop() { public void stop() {
for (AnimationProperty<?> property : animationProperties) { for (AnimationProperty<?> property : animationProperties.values()) {
property.stop(); property.stop();
} }
this.resetAnimatedProperties(); this.resetAnimatedProperties();
......
...@@ -32,7 +32,7 @@ import java.awt.Graphics2D; ...@@ -32,7 +32,7 @@ import java.awt.Graphics2D;
import java.awt.Shape; import java.awt.Shape;
import java.awt.Stroke; import java.awt.Stroke;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.util.List; import java.util.Collection;
/** /**
* @author Nico Mack [nico.mack@list.lu] * @author Nico Mack [nico.mack@list.lu]
...@@ -114,7 +114,7 @@ public class AnimatedShapeCorona extends AnimatedCorona { ...@@ -114,7 +114,7 @@ public class AnimatedShapeCorona extends AnimatedCorona {
@Override @Override
public void resetAnimatedProperties() { public void resetAnimatedProperties() {
List<AnimationProperty<?>> properties = this.getAnimationProperties(); Collection<AnimationProperty<?>> properties = this.getAnimationProperties();
for (AnimationProperty<?> property : properties) { for (AnimationProperty<?> property : properties) {
if (PROPERTY_OPACITY.equals(property.getProperty())) { if (PROPERTY_OPACITY.equals(property.getProperty())) {
......
...@@ -66,10 +66,10 @@ public class HtmlBox extends SelectableCorona implements InformationReceiver<Str ...@@ -66,10 +66,10 @@ public class HtmlBox extends SelectableCorona implements InformationReceiver<Str
protected int strokeWidth; protected int strokeWidth;
protected int insetBorder; protected int insetBorder;
protected List<String> styleRules; protected List<String> styleRules;
protected BufferedImage rendered;
private Stroke borderStroke; private Stroke borderStroke;
private Rectangle2D shapeBounds; private Rectangle2D shapeBounds;
private BufferedImage rendered;
private Point renderedCentre; private Point renderedCentre;
private JEditorPane editor; private JEditorPane editor;
......
...@@ -50,8 +50,8 @@ import lu.list.itis.dkd.tui.widget.corona.AnimatedCorona; ...@@ -50,8 +50,8 @@ import lu.list.itis.dkd.tui.widget.corona.AnimatedCorona;
import org.jdom2.Element; import org.jdom2.Element;
import java.util.ArrayList; import java.util.HashMap;
import java.util.List; import java.util.Map;
/** /**
* @author mack * @author mack
...@@ -61,7 +61,7 @@ import java.util.List; ...@@ -61,7 +61,7 @@ import java.util.List;
*/ */
public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuilder<B>> extends CoronaBuilder<B> { public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuilder<B>> extends CoronaBuilder<B> {
/** Time the fading corona takes to appear, i.e. going from transparent to opaque */ /** Time the fading corona takes to appear, i.e. going from transparent to opaque */
public List<AnimationProperty<?>> animationProperties = new ArrayList<>(); public Map<String, AnimationProperty<?>> animationProperties = new HashMap<>();
// *************************************************************************** // ***************************************************************************
// * Constants * // * Constants *
...@@ -105,7 +105,7 @@ public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuil ...@@ -105,7 +105,7 @@ public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuil
if (propertiesNode != null) { if (propertiesNode != null) {
for (Element propertyNode : propertiesNode.getChildren(Externalization.ANIMATED_PROPERTY_ELEMENT)) { for (Element propertyNode : propertiesNode.getChildren(Externalization.ANIMATED_PROPERTY_ELEMENT)) {
AnimationProperty<?> property = buildProperty(propertyNode, context, callback); AnimationProperty<?> property = buildProperty(propertyNode, context, callback);
animationProperties.add(property); animationProperties.put(property.getProperty(), property);
} }
} }
} }
...@@ -143,7 +143,7 @@ public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuil ...@@ -143,7 +143,7 @@ public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuil
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public B withAnimationProperty(AnimationProperty<?> property) { public B withAnimationProperty(AnimationProperty<?> property) {
this.animationProperties.add(property); this.animationProperties.put(property.getProperty(), property);
return (B) this; return (B) this;
} }
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.widget.touch;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
@SuppressWarnings({"javadoc", "squid:S1118"})
public abstract class FiniteStateMachine {
public static final int RELEASED_STATE = 0;
public static final int TAPPED_STATE = 1;
public static final int TOUCHED_STATE = 2;
public static final int DRAGGED_STATE = 3;
public static final int LATCHED_STATE = 4;
public static final int TOUCHED_EVENT = 0;
public static final int DRAGGED_EVENT = 1;
public static final int RELEASED_EVENT = 2;
public static final int EXPIRED_EVENT = 3;
public static final int IDLE_ACTION = 0;
public static final int TAP_ACTION = 1;
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.widget.touch;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
public final class Latching extends FiniteStateMachine {
@SuppressWarnings("javadoc")
public static final int[][] TRANSITIONS =
{
/* TOUCHED DRAGGED RELEASED EXPIRED */
/* RELEASED_STATE */ {TAPPED_STATE, RELEASED_STATE, RELEASED_STATE, RELEASED_STATE},
/* TAPPED_STATE */ {TAPPED_STATE, DRAGGED_STATE, LATCHED_STATE, TOUCHED_STATE},
/* TOUCHED_STATE */ {TOUCHED_STATE, DRAGGED_STATE, LATCHED_STATE, TOUCHED_STATE},
/* DRAGGED_STATE */ {DRAGGED_STATE, DRAGGED_STATE, RELEASED_STATE, DRAGGED_STATE},
/* LATCHED_STATE */ {LATCHED_STATE, DRAGGED_STATE, RELEASED_STATE, RELEASED_STATE}
};
@SuppressWarnings("javadoc")
public static final int[][] ACTIONS =
{
/* TOUCHED DRAGGED RELEASED EXPIRED */
/* RELEASED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION},
/* TAPPED_STATE */ {IDLE_ACTION, IDLE_ACTION, TAP_ACTION, IDLE_ACTION},
/* TOUCHED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION},
/* DRAGGED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION},
/* LATCHED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION}
};
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.widget.touch;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
public final class NonLatching extends FiniteStateMachine {
@SuppressWarnings({"javadoc", "squid:S2386"})
public static final int[][] TRANSITIONS =
{
/* TOUCHED DRAGGED RELEASED EXPIRED */
/* RELEASED_STATE */ {TAPPED_STATE, RELEASED_STATE, RELEASED_STATE, RELEASED_STATE},
/* TAPPED_STATE */ {TAPPED_STATE, DRAGGED_STATE, RELEASED_STATE, TOUCHED_STATE},
/* TOUCHED_STATE */ {TOUCHED_STATE, DRAGGED_STATE, RELEASED_STATE, TOUCHED_STATE},
/* DRAGGED_STATE */ {DRAGGED_STATE, DRAGGED_STATE, RELEASED_STATE, DRAGGED_STATE}
};
@SuppressWarnings({"javadoc", "squid:S2386"})
public static final int[][] ACTIONS =
{
/* TOUCHED DRAGGED RELEASED EXPIRED */
/* RELEASED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION},
/* TAPPED_STATE */ {IDLE_ACTION, IDLE_ACTION, TAP_ACTION, IDLE_ACTION},
/* TOUCHED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION},
/* DRAGGED_STATE */ {IDLE_ACTION, IDLE_ACTION, IDLE_ACTION, IDLE_ACTION}
};
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.