Commit 5a556945 authored by Nico Mack's avatar Nico Mack

Cleanup of code. Implemented cloning of widgets, required by feature

allowing mutliple widgets with identical IDs.
parent 5e2bc616
......@@ -171,6 +171,7 @@ STYLESHEET_NODE=styleSheet
STYLERULE_NODE=rule
PATH_NODE=path
PAGE_NODE=page
MEDIA_NODE=media
LOCATION_NODE=location
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, 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.content;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.widget.ZoomWidget;
/**
* Interface imposing functionality in order to be used with the {@link ZoomWidget}.
*
* @author Eric Tobias [eric.tobias@list.lu]
* @since 1.0
* @version 2.3.0
*/
@NonNullByDefault
public interface Zoomable {
/**
* Method used to specify the initial position of the zoom.
*
* @param position
*/
public void centre(Point position);
/**
* Method used to request all zooms be translate to the specified position.
*
* @param position
* The position to centre on.
*/
public void translate(Point position);
/**
* Method used to zoom by a factor given as parameter The direction of the zoom depends whether
* the parameter is positive or negative.
*
* @param position
* Zoom factor contained in a {@link Point}.
*/
public void zoom(@Nullable Point position);
/**
* Method called by the manager handling the {@link Zoomable} instance when the state changed to
* where it is no longer considered zooming. This method provides the opportunity to run code
* only executable when the zooming stopped.
*/
public void stoppedZooming();
/**
* Method called by the manager handling the {@link Zoomable} instance when the state changed to
* where it is no longer considered moving. This method provides the opportunity to run code
* only executable when the moving stopped.
*/
public void stoppedMoving();
}
\ No newline at end of file
......@@ -215,6 +215,7 @@ public class Externalization extends NLS {
public static String POINTING_OFFSET_NODE;
public static String PATH_NODE;
public static String PAGE_NODE;
public static String MEDIA_NODE;
public static String LOCATION_NODE;
......
......@@ -441,22 +441,6 @@ public class Point extends Float implements KdComparator<Point> {
return clone();
}
// switch (state.getClass().getSimpleName()) {
// case "TableCoordinates": //$NON-NLS-1$
// point.toTableCoordinates();
// break;
// case "ScreenCoordinates": //$NON-NLS-1$
// point.toScreenCoordinates();
// break;
// case "CameraCoordinates": //$NON-NLS-1$
// point.toCameraCoordinates();
// break;
// default:
// logger.error("This should never happen! State: {}!", state.toString()); //$NON-NLS-1$
// break;
// }
point.getState().toCoordinates(point, this.state.getClass());
Point clone = clone();
......
......@@ -36,36 +36,53 @@ import java.util.ArrayList;
* @since 1.0
* @version 2.3.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
@NonNullByDefault
public class ContentWidget extends BaseWidget {
/** List of {@link ContentEventListener} instances listening to updates to content. */
protected ArrayList<ContentEventListener> listeners = new ArrayList<>();
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Constructor making use of the super constructor to initialise all fields.
*
* @param builder
* The builder instance defining all parameters.
*/
// ---------------------------------------------------------------------------
public ContentWidget(BaseContentBuilder<?> builder) {
super(builder);
listeners = builder.listeners;
}
// ---------------------------------------------------------------------------
/**
* Method invoked when the tangible is detected on the table surface for the first time. The
* {@link BaseWidget} instance is set to be active.
* Copy constructor to clone widget.
*
* @param tangibleObject
* The {@link TangibleObject} that triggered the drop action.
* @param original
* specifies the original widget to create an exact copy from.
*/
@Override
public void actionDrop(TangibleObject tangibleObject) {
super.actionDrop(tangibleObject);
notify(this, tangibleObject.getObjectId(), ContentEventType.DROP);
}
// ---------------------------------------------------------------------------
public ContentWidget(ContentWidget original) {
super(original);
listeners = new ArrayList<>(original.listeners);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitive(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Method used to notify all listeners to a specific event.
*
......@@ -76,26 +93,35 @@ public class ContentWidget extends BaseWidget {
* @param type
* The type of the triggered event.
*/
// ---------------------------------------------------------------------------
private void notify(ContentWidget widget, int handleID, ContentEventType type) {
for (ContentEventListener listener : listeners) {
listener.contentUpdated(new ContentEvent(widget, handleID, type));
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Method invoked when the tangible is removed from the table surface. The {@link BaseWidget}
* instance will be set to no longer be active.
* Method invoked when the tangible is detected on the table surface for the first time. The
* {@link BaseWidget} instance is set to be active.
*
* @param tangibleObject
* The {@link TangibleObject} that was triggering the lift action.
* The {@link TangibleObject} that triggered the drop action.
*/
// ---------------------------------------------------------------------------
@Override
public void actionLift(TangibleObject tangibleObject) {
super.actionLift(tangibleObject);
notify(this, tangibleObject.getObjectId(), ContentEventType.LIFT);
public void actionDrop(TangibleObject tangibleObject) {
super.actionDrop(tangibleObject);
notify(this, tangibleObject.getObjectId(), ContentEventType.DROP);
}
// ---------------------------------------------------------------------------
/**
* Method invoked when a handle associated with the widget was moved. This default
* implementation will set the base and angle fields to the corresponding values and update the
......@@ -104,13 +130,31 @@ public class ContentWidget extends BaseWidget {
* @param tangibleObject
* The {@link TangibleObject} that was triggering the move.
*/
// ---------------------------------------------------------------------------
@Override
public void actionMove(TangibleObject tangibleObject) {
super.actionMove(tangibleObject);
notify(this, tangibleObject.getObjectId(), ContentEventType.MANIPULATION);
}
// ---------------------------------------------------------------------------
/**
* Method invoked when the tangible is removed from the table surface. The {@link BaseWidget}
* instance will be set to no longer be active.
*
* @param tangibleObject
* The {@link TangibleObject} that was triggering the lift action.
*/
// ---------------------------------------------------------------------------
@Override
public void actionLift(TangibleObject tangibleObject) {
super.actionLift(tangibleObject);
notify(this, tangibleObject.getObjectId(), ContentEventType.LIFT);
}
// ---------------------------------------------------------------------------
/**
* Method used to determine which segment the rotation of a handle is in given the number of
* segments to cover by one rotation.
......@@ -120,13 +164,25 @@ public class ContentWidget extends BaseWidget {
* @param handleID
* The ID of the handle to check the rotation for.
* @return The segment the rotation is currently in given:<br>
* <code>rotation / (PI / totalSegments)</code>.
* <code>rotation / (2*PI / totalSegments)</code>.
*/
public int getSegment(int totalSegments, int handleID) {
// float rotation = Math.abs(positions.get(handleID).getAngle());
float rotation = Math.abs(getPosition(handleID).getAngle());
float segmentSize = (float) (2 * Math.PI / totalSegments);
// ---------------------------------------------------------------------------
// public int getSegment(int totalSegments, int handleID) {
// Preconditions.checkArgument(totalSegments > 0, "Number of segments MUST be greater than 0!");
// //$NON-NLS-1$
//
// double rotation = Math.abs(getPosition(handleID).getAngle() % TWO_PI);
// double segmentSize = (float) (TWO_PI / totalSegments);
//
// return (int) Math.floor(rotation / segmentSize);
// }
// ---------------------------------------------------------------------------
return (int) Math.floor(rotation / segmentSize);
@Override
public ContentWidget clone() {
return new ContentWidget(this);
}
}
\ No newline at end of file
......@@ -35,27 +35,60 @@ import org.slf4j.LoggerFactory;
/**
* Widget used to display information in a box next to the summit of a, usually, triangular shape.
*
* @author Nico Mack [nico.mack@list.lu]
* @author Eric Tobias [eric.tobias@list.lu]
* @since 1.0
* @version 2.3.0
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
@NonNullByDefault
public class InfoWidget extends TetherableWidget implements TetherListener {
private static Logger LOGGER = LoggerFactory.getLogger(InfoWidget.class.getSimpleName());
private static final Logger LOGGER = LoggerFactory.getLogger(InfoWidget.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Constructor setting all fields by calling the super constructor.
*
* @param builder
* The builder instance defining all parameters.
*/
// ---------------------------------------------------------------------------
public InfoWidget(BaseInfoBuilder<InfoWidgetBuilder> builder) {
super(builder);
this.addTetherListener(this);
}
// ---------------------------------------------------------------------------
/**
* Copy constructor to clone widget.
*
* @param original
* specifies the original widget to create an exact copy from.
*/
// ---------------------------------------------------------------------------
public InfoWidget(InfoWidget original) {
super(original);
this.addTetherListener(this);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public void tetherChanged(TetherEvent event) {
switch (event.getState()) {
......@@ -90,6 +123,12 @@ public class InfoWidget extends TetherableWidget implements TetherListener {
break;
}
}// TODO Auto-generated method stub
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
......@@ -6,6 +6,10 @@ import lu.list.itis.dkd.tui.utility.PolarCoordinateHelper;
import lu.list.itis.dkd.tui.widget.builder.BasePointingWidgetBuilder;
/**
* Widget used to point at something on the table. Pointing implies that one particular point of the
* widgets' shape is considered as a pointer. The PointingWidget class implements functionality to
* find the position of this pointing location.
*
* @author nmack
* @date 14 Jul 2017
*
......@@ -35,12 +39,29 @@ public abstract class PointingWidget extends StatefulWidget {
*
* @param builder
*/
// ---------------------------------------------------------------------------
public PointingWidget(BasePointingWidgetBuilder<?> builder) {
super(builder);
pointingOffset = builder.pointingOffset;
}
// ---------------------------------------------------------------------------
/**
* Copy constructor to clone widget.
*
* @param original
* specifies the original widget to create an exact copy from.
*/
// ---------------------------------------------------------------------------
public PointingWidget(PointingWidget original) {
super(original);
pointingOffset = original.pointingOffset;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
......@@ -76,8 +97,6 @@ public abstract class PointingWidget extends StatefulWidget {
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
......
......@@ -30,23 +30,34 @@ import lu.list.itis.dkd.tui.widget.state.StateManager;
import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
* A widget implementation which adds a {@link NuiState} to the widget keeping track of state
* transitions and the actual state.
*
* @author Nico Mack [nico.mack@list.lu]
* @author Eric Tobias [eric.tobias@list.lu]
* @since 1.0
* @version 2.3.0
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
@NonNullByDefault
public class StatefulWidget extends BaseWidget {
/** The coalesced NuiState instances per handle. */
protected ConcurrentHashMap<Integer, StateManager> states;
/** Fields to track changes in position and rotation. */
protected Point rotationDelta, movementDelta;
// protected Point rotationDelta, movementDelta;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Constructor setting all fields as by the values specified by the builder.
*
......@@ -57,10 +68,36 @@ public class StatefulWidget extends BaseWidget {
super(builder);
Preconditions.checkState(builder.states != null);
states = builder.states;
rotationDelta = new Point(0, 0, 0);
movementDelta = new Point(0, 0, 0);
// rotationDelta = new Point(0, 0, 0);
// movementDelta = new Point(0, 0, 0);
}
// ---------------------------------------------------------------------------
/**
* Copy constructor to clone widget.
*
* @param original
* specifies the original widget to create an exact copy from.
*/
// ---------------------------------------------------------------------------
public StatefulWidget(StatefulWidget original) {
super(original);
states = new ConcurrentHashMap<>();
for (Entry<Integer, StateManager> entry : original.states.entrySet()) {
boolean isPersistent = entry.getValue().isPersistent();
states.putIfAbsent(entry.getKey(), new StateManager(isPersistent));
}
// rotationDelta = new Point(0, 0, 0);
// movementDelta = new Point(0, 0, 0);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Allows checking wether this stateful widget is persistent or not. Persistent widgets remain
* logically active even though they are physically removed (lifted) from the table
......@@ -69,12 +106,14 @@ public class StatefulWidget extends BaseWidget {
* specifies the object to check the persistence state of
* @return <code>true</code> if specified object is persistent, <code>false</code> if not.
*/
// ---------------------------------------------------------------------------
public boolean isPersistent(Integer objectId) {
StateManager manager = states.get(objectId);
return manager.isPersistent();
}
// ---------------------------------------------------------------------------
/**
* Method invoked when a handle associated with the widget was moved. The method issues a call
* to the super method before handling state updates.
......@@ -83,6 +122,8 @@ public class StatefulWidget extends BaseWidget {
* The {@link TangibleObject} that was triggering the move.
* @see BaseWidget#actionMove(TangibleObject)
*/
// ---------------------------------------------------------------------------
@Override
public void actionMove(TangibleObject tangibleObject) {
StateManager manager = states.get(tangibleObject.getObjectId());
......@@ -93,6 +134,7 @@ public class StatefulWidget extends BaseWidget {
manager.rotate(position).move(position);
}
// ---------------------------------------------------------------------------
/**
* Method invoked when the tangible is detected on the table surface for the first time. The
* method issues a call to the super method before handling state updates.
......@@ -101,12 +143,15 @@ public class StatefulWidget extends BaseWidget {
* The {@link TangibleObject} that was triggering the drop action.
* @see BaseWidget#actionDrop(TangibleObject)
*/
// ---------------------------------------------------------------------------
@Override
public void actionDrop(TangibleObject tangibleObject) {
super.actionDrop(tangibleObject);
states.get(tangibleObject.getObjectId()).drop(new Point(tangibleObject.getX(), tangibleObject.getY(), tangibleObject.getAngle()));
}
// ---------------------------------------------------------------------------
/**
* Method invoked when the cursor is removed from the table surface. The method issues a call to
* the super method before handling state updates.
......@@ -115,19 +160,39 @@ public class StatefulWidget extends BaseWidget {
* The {@link TangibleObject} that was triggering the drop action.
* @see BaseWidget#actionLift(TangibleObject)
*/
// ---------------------------------------------------------------------------
@Override
public void actionLift(TangibleObject tangibleObject) {
states.get(tangibleObject.getObjectId()).lift(new Point(tangibleObject.getX(), tangibleObject.getY(), tangibleObject.getAngle()));
super.actionLift(tangibleObject);
}
// ---------------------------------------------------------------------------
/**
* Method for retrieving all {@link StateManager} instances attached to handles.
*
* @return A collection of {@link StateManager} instances.
*/
// ---------------------------------------------------------------------------
public Collection<StateManager> getManagers() {
Preconditions.checkState(states.values() != null);
return states.values();
}
// ---------------------------------------------------------------------------
@Override
public StatefulWidget clone() {
return new StatefulWidget(this);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, 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;
import lu.list.itis.dkd.tui.adapter.TangibleObject;
......@@ -11,18 +32,16 @@ import lu.list.itis.dkd.tui.widget.tether.Tetherable;
import lu.list.itis.dkd.tui.widget.tether.listener.TetherListener;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.List;
import TUIO.TuioObject;
/**
* @author nmack
* @date 12 May 2015
*
* <br>
* $Log: TetherableWidget.java,v $
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
......@@ -50,20 +69,42 @@ public abstract class TetherableWidget extends PointingWidget implements Tethera
*
* @param builder
*/
// ---------------------------------------------------------------------------
public TetherableWidget(BaseTetherableBuilder<?> builder) {
super(builder);
this.tetherManager = new TetherManager(this, builder.exclusive);
this.tetherManager.setProviders(builder.providers);
this.tetherManager.setReceivers(builder.receivers);
// this.handleID = builder.handleID;
this.tetherOrigin = builder.tetherOrigin;
this.tetheringDistance = builder.tetheringDistance;
this.draggable = builder.draggable;
this.rotatesWithTether = builder.rotatesWithTether;
}
// ---------------------------------------------------------------------------
/**
* Copy constructor to clone widget.
*
* @param original
* specifies the original widget to create an exact copy from.
*/
// ---------------------------------------------------------------------------
public TetherableWidget(TetherableWidget original) {
super(original);
this.tetherManager = new TetherManager(this, original.tetherManager.isExclusive());
this.tetherManager.setProviders(new ArrayList<>(original.tetherManager.getProviders()));
this.tetherManager.setReceivers(new ArrayList<>(original.tetherManager.getReceivers()));
this.tetherManager.setPotentialTethers(original.tetherManager.getPotentialTethers());
this.tetherOrigin = original.tetherOrigin;
this.tetheringDistance = original.tetheringDistance;
this.draggable = original.draggable;
this.rotatesWithTether = original.rotatesWithTether;
}
// ---------------------------------------------------------------------------