Commit e7029606 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 @@
*/
package lu.list.itis.dkd.tui.widget.animation;
import java.util.List;
import java.util.Collection;
/**
* @author mack
......@@ -37,7 +37,7 @@ public interface Animated {
/**
* @return
*/
public List<AnimationProperty<?>> getAnimationProperties();
public Collection<AnimationProperty<?>> getAnimationProperties();
/**
*
......
......@@ -16,12 +16,11 @@
*/
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.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// ***************************************************************************
// * Class Definition and Members *
......@@ -34,7 +33,7 @@ import java.util.List;
*/
public class AnimationEventSource {
private ArrayList<AnimationListener> listeners;
private Multimap<Integer, AnimationListener> keyframes;
private Map<Integer, List<AnimationListener>> keyframes;
// ***************************************************************************
// * Constants *
......@@ -51,7 +50,7 @@ public class AnimationEventSource {
*/
public AnimationEventSource() {
listeners = new ArrayList<>();
keyframes = TreeMultimap.create();
keyframes = new HashMap<>();
}
// ---------------------------------------------------------------------------
......@@ -81,7 +80,10 @@ public class AnimationEventSource {
*/
public void addAnimationListenerAtKeyFrame(AnimationListener listener, int keyFrame) {
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 {
* @param 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;
// * Interface Definition and Members *
// ***************************************************************************
public interface AnimationListener extends Comparable<Object> {
public interface AnimationListener {
/**
* @param event
......
......@@ -103,6 +103,24 @@ public class AnimationProperty<T> implements TimelineCallback {
// * 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 {
// ---------------------------------------------------------------------------
/**
* Allows controlling looping behavior. When reversing is enabled, (<code>true</code>),
* animation plays back and forth whenever the end is reached. Specify <code>false</code> to
* disable reversing. It should be noted that reversing requires the looping property to be set
* in order to have any effect
* Allows controlling looping behavior. When reversing is enabled, (<code>true</code>), animation
* plays back and forth whenever the end is reached. Specify <code>false</code> to disable
* reversing. It should be noted that reversing requires the looping property to be set in order to
* have any effect
*
* @param reversing
* <code>true</code> to enable reversing, <code>false</code> to disable
......@@ -318,11 +336,13 @@ public class AnimationProperty<T> implements TimelineCallback {
// ---------------------------------------------------------------------------
/**
* starts the animation of the property represented by this instance
*
* @param backwards
*/
// ---------------------------------------------------------------------------
@SuppressWarnings("incomplete-switch")
public void start() {
public void start(boolean backwards) {
if (timeline != null) {
......@@ -338,6 +358,8 @@ public class AnimationProperty<T> implements TimelineCallback {
if (looping) {
timeline.playLoop((reversing ? RepeatBehavior.REVERSE : RepeatBehavior.LOOP));
} else if (backwards) {
timeline.playReverse();
} else {
timeline.play();
}
......@@ -387,6 +409,7 @@ public class AnimationProperty<T> implements TimelineCallback {
direction = Direction.NONE;
keyFrameIterator = null;
nextKeyFrame = null;
this.listeners.notifyAnimationListener(new AnimationEvent(this, AnimationEvent.AnimationState.DONE));
break;
// $CASES-OMITTED$
default:
......
......@@ -31,9 +31,8 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
......@@ -47,7 +46,7 @@ import java.util.Map;
public abstract class AnimatedCorona extends Corona implements Animated {
protected List<AnimationProperty<?>> animationProperties;
protected Map<String, AnimationProperty<?>> animationProperties;
protected Map<String, Method> animationSetters;
private static final Logger LOGGER = LoggerFactory.getLogger(AnimatedCorona.class.getSimpleName());
......@@ -81,7 +80,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
public AnimatedCorona(AnimatedCorona original) {
super(original);
animationProperties = new ArrayList<>(original.animationProperties);
animationProperties = new HashMap<>(original.animationProperties);
this.validateAnimationProperties();
}
......@@ -95,7 +94,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
private void validateAnimationProperties() {
animationSetters = getAnimationSetters(this.getClass());
for (AnimationProperty<?> property : animationProperties) {
for (AnimationProperty<?> property : animationProperties.values()) {
if (!animationSetters.containsKey(property.getProperty())) {
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 {
/** {@inheritDoc} */
@Override
public List<AnimationProperty<?>> getAnimationProperties() {
return animationProperties;
public Collection<AnimationProperty<?>> getAnimationProperties() {
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 {
/** {@inheritDoc} */
@Override
public void start() {
for (AnimationProperty<?> property : animationProperties) {
for (AnimationProperty<?> property : animationProperties.values()) {
property.setAnimatedObject(this);
property.start();
property.start(false);
}
}
......@@ -179,7 +189,7 @@ public abstract class AnimatedCorona extends Corona implements Animated {
/** {@inheritDoc} */
@Override
public void stop() {
for (AnimationProperty<?> property : animationProperties) {
for (AnimationProperty<?> property : animationProperties.values()) {
property.stop();
}
this.resetAnimatedProperties();
......
......@@ -32,7 +32,7 @@ import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.util.List;
import java.util.Collection;
/**
* @author Nico Mack [nico.mack@list.lu]
......@@ -114,7 +114,7 @@ public class AnimatedShapeCorona extends AnimatedCorona {
@Override
public void resetAnimatedProperties() {
List<AnimationProperty<?>> properties = this.getAnimationProperties();
Collection<AnimationProperty<?>> properties = this.getAnimationProperties();
for (AnimationProperty<?> property : properties) {
if (PROPERTY_OPACITY.equals(property.getProperty())) {
......
......@@ -66,10 +66,10 @@ public class HtmlBox extends SelectableCorona implements InformationReceiver<Str
protected int strokeWidth;
protected int insetBorder;
protected List<String> styleRules;
protected BufferedImage rendered;
private Stroke borderStroke;
private Rectangle2D shapeBounds;
private BufferedImage rendered;
private Point renderedCentre;
private JEditorPane editor;
......
......@@ -50,8 +50,8 @@ import lu.list.itis.dkd.tui.widget.corona.AnimatedCorona;
import org.jdom2.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
/**
* @author mack
......@@ -61,7 +61,7 @@ import java.util.List;
*/
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 */
public List<AnimationProperty<?>> animationProperties = new ArrayList<>();
public Map<String, AnimationProperty<?>> animationProperties = new HashMap<>();
// ***************************************************************************
// * Constants *
......@@ -105,7 +105,7 @@ public abstract class BaseAnimatedCoronaBuilder<B extends BaseAnimatedCoronaBuil
if (propertiesNode != null) {
for (Element propertyNode : propertiesNode.getChildren(Externalization.ANIMATED_PROPERTY_ELEMENT)) {
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
*/
@SuppressWarnings("unchecked")
public B withAnimationProperty(AnimationProperty<?> property) {
this.animationProperties.add(property);
this.animationProperties.put(property.getProperty(), property);
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.
*
* 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;
import lu.list.itis.dkd.tui.utility.Point;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class TapEvent {
private int touchId;
private Point position;
private long timestamp;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param touchId
* @param position
*/
// ---------------------------------------------------------------------------
public TapEvent(int touchId, Point position) {
this.touchId = touchId;
this.position = position;
this.timestamp = System.currentTimeMillis();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Simple getter method for touchId.
*
* @return The value of touchId.
*/
// ---------------------------------------------------------------------------
public int getTouchId() {
return touchId;
}
// ---------------------------------------------------------------------------
/**
* Simple setter method for touchId.
*
* @param touchId
* The value to set touchId to.
*/
// ---------------------------------------------------------------------------
public void setTouchId(int touchId) {
this.touchId = touchId;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for position.
*
* @return The value of position.
*/
// ---------------------------------------------------------------------------
public Point getPosition() {
return position;
}
// ---------------------------------------------------------------------------
/**
* Simple setter method for position.
*
* @param position
* The value to set position to.
*/
// ---------------------------------------------------------------------------
public void setPosition(Point position) {
this.position = position;
}
// ---------------------------------------------------------------------------
/**
* @return
*/
// ---------------------------------------------------------------------------
public long getTimestamp() {
return this.timestamp;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* 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 interface TapListener {
/**
* @param event
*/
public void tapped(TapEvent event);
}
/**
* 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;
import lu.list.itis.dkd.tui.utility.Point;
import javax.swing.Timer;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Touch {
private Integer id;
private Integer state;
private Timer tapTimer;
private Point position;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param id
* @param initialState
*/
// ---------------------------------------------------------------------------
public Touch(Integer id, int initialState) {
this.id = id;
this.state = initialState;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Simple getter method for id.
*
* @return The value of id.
*/
// ---------------------------------------------------------------------------
public Integer getId() {
return id;
}
// ---------------------------------------------------------------------------
/**
* Simple setter method for id.
*
* @param id
* The value to set id to.
*/
// ---------------------------------------------------------------------------
public void setId(Integer id) {
this.id = id;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for state.
*
* @return The value of state.
*/
// ---------------------------------------------------------------------------
public Integer getState() {
return state;
}
// ---------------------------------------------------------------------------
/**
* Simple setter method for state.
*
* @param state
* The value to set state to.