[1098] | 1 | package org.apollo;
|
---|
| 2 |
|
---|
[1517] | 3 | import java.util.ArrayList;
|
---|
[1098] | 4 | import java.util.Collection;
|
---|
| 5 | import java.util.HashMap;
|
---|
| 6 | import java.util.LinkedHashSet;
|
---|
| 7 | import java.util.LinkedList;
|
---|
| 8 | import java.util.List;
|
---|
| 9 | import java.util.Map;
|
---|
| 10 |
|
---|
| 11 | import org.apollo.gio.gesture.data.TrackAdjustmentGestureData;
|
---|
| 12 | import org.apollo.util.Mutable;
|
---|
| 13 | import org.apollo.widgets.LinkedTrack;
|
---|
| 14 | import org.apollo.widgets.SampledTrack;
|
---|
| 15 | import org.apollo.widgets.TrackWidgetCommons;
|
---|
| 16 | import org.expeditee.core.Dimension;
|
---|
| 17 | import org.expeditee.core.Point;
|
---|
[1523] | 18 | import org.expeditee.core.bounds.AxisAlignedBoxBounds;
|
---|
[1098] | 19 | import org.expeditee.gio.EcosystemManager;
|
---|
| 20 | import org.expeditee.gio.gesture.Gesture;
|
---|
[1155] | 21 | import org.expeditee.gio.gesture.Gesture.GestureType;
|
---|
[1098] | 22 | import org.expeditee.gio.gesture.GestureAction;
|
---|
| 23 | import org.expeditee.gio.gesture.GestureListener;
|
---|
| 24 | import org.expeditee.gio.gesture.StandardGestureActions;
|
---|
| 25 | import org.expeditee.gio.gesture.StandardGestureActions.StandardGestureType;
|
---|
| 26 | import org.expeditee.gio.gesture.data.ItemSpecificGestureData;
|
---|
[1155] | 27 | import org.expeditee.gio.gesture.data.PickUpGestureData;
|
---|
| 28 | import org.expeditee.gio.input.KBMInputEvent.Key;
|
---|
[1098] | 29 | import org.expeditee.gio.input.StandardInputEventListeners;
|
---|
| 30 | import org.expeditee.gui.DisplayController;
|
---|
| 31 | import org.expeditee.gui.Frame;
|
---|
| 32 | import org.expeditee.gui.FrameIO;
|
---|
| 33 | import org.expeditee.gui.FreeItems;
|
---|
| 34 | import org.expeditee.items.Dot;
|
---|
| 35 | import org.expeditee.items.Item;
|
---|
[1155] | 36 | import org.expeditee.items.Item.HighlightMode;
|
---|
[1098] | 37 | import org.expeditee.items.ItemUtils;
|
---|
| 38 | import org.expeditee.items.Line;
|
---|
| 39 | import org.expeditee.items.Text;
|
---|
| 40 | import org.expeditee.items.UserAppliedPermission;
|
---|
[1179] | 41 | import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException;
|
---|
| 42 | import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException;
|
---|
[1098] | 43 | import org.expeditee.items.widgets.Widget;
|
---|
| 44 | import org.expeditee.items.widgets.WidgetCorner;
|
---|
| 45 | import org.expeditee.items.widgets.WidgetEdge;
|
---|
| 46 |
|
---|
[1155] | 47 | public class ApolloGestureActions implements GestureListener {
|
---|
[1158] | 48 | //@formatter:off
|
---|
[1155] | 49 | public enum ApolloGestureType {
|
---|
[1158] | 50 | ADJUST_INITIATION_TIME,
|
---|
| 51 | ADJUST_VERTICAL_POSITION,
|
---|
| 52 | CREATE_LINKED_TRACKS,
|
---|
| 53 | MODULUS_POSITION, // TODO: Think of a better name. cts16
|
---|
[1098] | 54 | TOGGLE_QUALITY_GRAPHICS
|
---|
| 55 | }
|
---|
[1158] | 56 | //@formatter:on
|
---|
[1155] | 57 |
|
---|
[1098] | 58 | private static ApolloGestureActions _instance = null;
|
---|
[1155] | 59 |
|
---|
| 60 | public static ApolloGestureActions getInstance() {
|
---|
[1098] | 61 | if (_instance == null) {
|
---|
| 62 | _instance = new ApolloGestureActions();
|
---|
| 63 | }
|
---|
[1155] | 64 |
|
---|
[1098] | 65 | return _instance;
|
---|
| 66 | }
|
---|
[1155] | 67 |
|
---|
[1098] | 68 | private HashMap<ApolloGestureType, GestureType> _gestureTypes;
|
---|
| 69 |
|
---|
| 70 | private HashMap<GestureType, GestureAction> _actions;
|
---|
[1155] | 71 |
|
---|
| 72 | private ApolloGestureActions() {
|
---|
[1098] | 73 | _gestureTypes = new HashMap<ApolloGestureType, GestureType>();
|
---|
| 74 | initialiseGestureTypes();
|
---|
| 75 | _actions = new HashMap<GestureType, GestureAction>();
|
---|
| 76 | initialiseActions();
|
---|
| 77 | }
|
---|
[1155] | 78 |
|
---|
| 79 | @Override
|
---|
| 80 | public void preGesture(final Gesture gesture) {
|
---|
| 81 | final GestureAction action = getGestureAction(gesture.getType());
|
---|
| 82 | if (action == null) {
|
---|
| 83 | return;
|
---|
| 84 | }
|
---|
| 85 | action.prepare(gesture);
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | @Override
|
---|
| 89 | public void onGesture(final Gesture gesture) {
|
---|
| 90 | final GestureAction action = getGestureAction(gesture.getType());
|
---|
| 91 | if (action == null) {
|
---|
| 92 | return;
|
---|
| 93 | }
|
---|
| 94 | action.exec(gesture);
|
---|
| 95 | }
|
---|
[1098] | 96 |
|
---|
| 97 | @Override
|
---|
[1155] | 98 | public void postGesture(final Gesture gesture) {
|
---|
| 99 | final GestureAction action = getGestureAction(gesture.getType());
|
---|
| 100 | if (action == null) {
|
---|
| 101 | return;
|
---|
| 102 | }
|
---|
| 103 | action.finalise(gesture);
|
---|
[1098] | 104 | }
|
---|
[1155] | 105 |
|
---|
| 106 | private void setGestureAction(GestureType type, GestureAction action) {
|
---|
[1179] | 107 | if (type == null) {
|
---|
[1155] | 108 | return;
|
---|
[1179] | 109 | }
|
---|
[1155] | 110 |
|
---|
[1098] | 111 | _actions.put(type, action);
|
---|
| 112 | }
|
---|
[1155] | 113 |
|
---|
| 114 | private GestureAction getGestureAction(GestureType type) {
|
---|
[1179] | 115 | if (type == null) {
|
---|
[1155] | 116 | return null;
|
---|
[1179] | 117 | }
|
---|
[1155] | 118 |
|
---|
[1098] | 119 | return _actions.get(type);
|
---|
| 120 | }
|
---|
[1155] | 121 |
|
---|
| 122 | private void initialiseActions() {
|
---|
[1098] | 123 | // Set the ADJUST_INITIATION_TIME action
|
---|
[1155] | 124 | setGestureAction(gestureType(ApolloGestureType.ADJUST_INITIATION_TIME), new GestureAction() {
|
---|
[1098] | 125 | @Override
|
---|
[1155] | 126 | public void exec(Gesture gesture) {
|
---|
[1098] | 127 | TrackAdjustmentGestureData data = (TrackAdjustmentGestureData) gesture.getData();
|
---|
[1155] | 128 |
|
---|
[1098] | 129 | Widget selectedIW = null;
|
---|
[1155] | 130 |
|
---|
[1098] | 131 | if (data.getCurrentItem() != null) {
|
---|
| 132 | if (data.getCurrentItem() instanceof WidgetEdge) {
|
---|
| 133 | selectedIW = ((WidgetEdge) data.getCurrentItem()).getWidgetSource();
|
---|
| 134 | } else if (data.getCurrentItem() instanceof WidgetCorner) {
|
---|
| 135 | selectedIW = ((WidgetCorner) data.getCurrentItem()).getWidgetSource();
|
---|
| 136 | }
|
---|
| 137 | }
|
---|
[1155] | 138 |
|
---|
[1179] | 139 | if (selectedIW != null) {
|
---|
[1155] | 140 | adjustInitiationTime(selectedIW, data.getAdjustment());
|
---|
[1179] | 141 | }
|
---|
[1098] | 142 | }
|
---|
| 143 | });
|
---|
[1155] | 144 |
|
---|
[1098] | 145 | // Set the ADJUST_VERTICAL_POSITION action
|
---|
[1155] | 146 | setGestureAction(gestureType(ApolloGestureType.ADJUST_VERTICAL_POSITION), new GestureAction() {
|
---|
[1098] | 147 | @Override
|
---|
[1155] | 148 | public void exec(Gesture gesture) {
|
---|
[1098] | 149 | TrackAdjustmentGestureData data = (TrackAdjustmentGestureData) gesture.getData();
|
---|
[1155] | 150 |
|
---|
[1098] | 151 | Widget selectedIW = null;
|
---|
[1155] | 152 |
|
---|
[1098] | 153 | if (data.getCurrentItem() != null) {
|
---|
| 154 | if (data.getCurrentItem() instanceof WidgetEdge) {
|
---|
| 155 | selectedIW = ((WidgetEdge) data.getCurrentItem()).getWidgetSource();
|
---|
| 156 | } else if (data.getCurrentItem() instanceof WidgetCorner) {
|
---|
| 157 | selectedIW = ((WidgetCorner) data.getCurrentItem()).getWidgetSource();
|
---|
| 158 | }
|
---|
| 159 | }
|
---|
[1155] | 160 |
|
---|
[1179] | 161 | if (selectedIW != null) {
|
---|
[1155] | 162 | adjustVerticalPosition(selectedIW, data.getAdjustment());
|
---|
[1179] | 163 | }
|
---|
[1098] | 164 | }
|
---|
| 165 | });
|
---|
[1155] | 166 |
|
---|
[1098] | 167 | // Set the CREATE_LINKED_TRACKS action
|
---|
[1155] | 168 | setGestureAction(gestureType(ApolloGestureType.CREATE_LINKED_TRACKS), new GestureAction() {
|
---|
[1098] | 169 | @Override
|
---|
[1155] | 170 | public void exec(Gesture gesture) {
|
---|
[1098] | 171 | ItemSpecificGestureData data = (ItemSpecificGestureData) gesture.getData();
|
---|
[1155] | 172 |
|
---|
[1098] | 173 | createLinkedTracks(data.getCurrentItem(), data.getCurrentItems());
|
---|
| 174 | }
|
---|
| 175 | });
|
---|
[1155] | 176 |
|
---|
[1098] | 177 | // Set the MOD_POSITION action
|
---|
[1155] | 178 | setGestureAction(gestureType(ApolloGestureType.MODULUS_POSITION), new GestureAction() {
|
---|
[1098] | 179 | @Override
|
---|
[1155] | 180 | public void exec(Gesture gesture) {
|
---|
[1098] | 181 | Frame current = DisplayController.getCurrentFrame();
|
---|
| 182 | Dimension windowSize = EcosystemManager.getGraphicsManager().getWindowSize();
|
---|
[1155] | 183 |
|
---|
[1415] | 184 | for (Item i : current.getSortedItems()) {
|
---|
[1098] | 185 | Point pos = i.getPosition();
|
---|
[1142] | 186 | pos.setX(pos.getX() % windowSize.width);
|
---|
| 187 | pos.setY(pos.getY() % windowSize.height);
|
---|
[1098] | 188 | i.setPosition(pos);
|
---|
| 189 | }
|
---|
| 190 | }
|
---|
| 191 | });
|
---|
[1155] | 192 |
|
---|
[1098] | 193 | // Set the TOGGLE_QUALITY_GRAPHICS action
|
---|
[1155] | 194 | setGestureAction(gestureType(ApolloGestureType.TOGGLE_QUALITY_GRAPHICS), new GestureAction() {
|
---|
[1098] | 195 | @Override
|
---|
[1155] | 196 | public void exec(Gesture gesture) {
|
---|
[1098] | 197 | ApolloSystem.useQualityGraphics = !ApolloSystem.useQualityGraphics;
|
---|
| 198 | }
|
---|
| 199 | });
|
---|
[1155] | 200 |
|
---|
[1098] | 201 | // Set the MOVE_CURSOR action
|
---|
[1155] | 202 | setGestureAction(StandardGestureActions.getInstance().gestureType(StandardGestureType.MOVE_CURSOR),
|
---|
| 203 | new GestureAction() {
|
---|
| 204 | @Override
|
---|
| 205 | public void exec(Gesture gesture) {
|
---|
[1523] | 206 | //mouseMoved(gesture.getData().getPosition());
|
---|
| 207 | if (isSnapOn()) {
|
---|
| 208 | snapFreeTracks(gesture.getData().getPosition());
|
---|
| 209 | }
|
---|
[1155] | 210 | }
|
---|
| 211 | });
|
---|
| 212 |
|
---|
[1098] | 213 | // Set the PLACE action
|
---|
[1155] | 214 | setGestureAction(StandardGestureActions.getInstance().gestureType(StandardGestureType.PLACE),
|
---|
| 215 | new GestureAction() {
|
---|
| 216 |
|
---|
[1517] | 217 | final List<SampledTrack> sampledTracksOnFreeItems = new ArrayList<SampledTrack>();
|
---|
[1155] | 218 |
|
---|
| 219 | @Override
|
---|
| 220 | public void prepare(final Gesture gesture) {
|
---|
| 221 | final FreeItems freeItems = FreeItems.getInstance();
|
---|
| 222 | List<Widget> widgets = null;
|
---|
| 223 | if (freeItems != null && !freeItems.isEmpty()) {
|
---|
| 224 | widgets = ItemUtils.extractWidgets(freeItems);
|
---|
| 225 | }
|
---|
| 226 | widgets.forEach(w -> {
|
---|
| 227 | if (w instanceof SampledTrack) {
|
---|
| 228 | final SampledTrack st = (SampledTrack) w;
|
---|
| 229 | st.setIgnoreInjection(true);
|
---|
[1517] | 230 | sampledTracksOnFreeItems.add(st);
|
---|
[1155] | 231 | }
|
---|
| 232 | });
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | @Override
|
---|
[1517] | 236 | public void exec(final Gesture gesture) {
|
---|
[1155] | 237 | final PickUpGestureData data = (PickUpGestureData) gesture.getData();
|
---|
[1179] | 238 | final List<Item> widgetPieces = new LinkedList<Item>();
|
---|
[1155] | 239 | if (data.getCopy()) {
|
---|
[1517] | 240 | sampledTracksOnFreeItems.forEach(st -> {
|
---|
[1179] | 241 | st.getItems().forEach(i -> {
|
---|
| 242 | StandardGestureActions.anchor(i);
|
---|
| 243 | widgetPieces.add(i);
|
---|
| 244 | });
|
---|
| 245 | });
|
---|
[1517] | 246 | //FreeItems.getInstance().clear();
|
---|
| 247 | FreeItems.getInstance().removeAll(widgetPieces);
|
---|
[1179] | 248 | anchorTracks(widgetPieces);
|
---|
| 249 | final List<Item> toPickup = new LinkedList<Item>();
|
---|
[1517] | 250 | sampledTracksOnFreeItems.forEach(st -> {
|
---|
[1179] | 251 | try {
|
---|
| 252 | final Widget copy = st.copy();
|
---|
| 253 | toPickup.addAll(copy.getItems());
|
---|
| 254 | } catch (InteractiveWidgetNotAvailableException e) {
|
---|
| 255 | e.printStackTrace();
|
---|
| 256 | } catch (InteractiveWidgetInitialisationFailedException e) {
|
---|
| 257 | e.printStackTrace();
|
---|
| 258 | }
|
---|
| 259 | });
|
---|
| 260 | StandardGestureActions.pickup(toPickup);
|
---|
| 261 | } else {
|
---|
| 262 | anchorTracks(FreeItems.getInstance());
|
---|
[1155] | 263 | }
|
---|
| 264 | }
|
---|
| 265 |
|
---|
| 266 | @Override
|
---|
| 267 | public void finalise(final Gesture gesture) {
|
---|
[1517] | 268 | sampledTracksOnFreeItems.forEach(st -> st.setIgnoreInjection(false));
|
---|
| 269 | sampledTracksOnFreeItems.clear();
|
---|
[1155] | 270 | }
|
---|
| 271 | });
|
---|
[1098] | 272 | }
|
---|
[1155] | 273 |
|
---|
[1098] | 274 | /** Initialises the set of gesture types. */
|
---|
[1155] | 275 | private void initialiseGestureTypes() {
|
---|
[1098] | 276 | for (ApolloGestureType type : ApolloGestureType.values()) {
|
---|
| 277 | GestureType gestureType;
|
---|
| 278 | if ((gestureType = GestureType.register(type.toString())) == null) {
|
---|
| 279 | gestureType = GestureType.get(type.toString());
|
---|
| 280 | }
|
---|
| 281 | _gestureTypes.put(type, gestureType);
|
---|
| 282 | }
|
---|
| 283 | }
|
---|
[1155] | 284 |
|
---|
[1098] | 285 | /** Gets the gesture type associated with the given standard type. */
|
---|
[1155] | 286 | public GestureType gestureType(ApolloGestureType type) {
|
---|
[1179] | 287 | if (type == null) {
|
---|
[1155] | 288 | return null;
|
---|
[1179] | 289 | }
|
---|
[1155] | 290 |
|
---|
[1098] | 291 | return _gestureTypes.get(type);
|
---|
| 292 | }
|
---|
| 293 |
|
---|
[1155] | 294 | /*
|
---|
| 295 | * TODO: EVERYTHING BELOW HERE IS ONLY TEMPORARILY SITUATED IN THIS CLASS
|
---|
| 296 | *
|
---|
| 297 | * The following methods were mostly copy-pasted here from the old
|
---|
| 298 | * ApolloFrameKeyboardActions and ApolloFrameMouseActions classes (to enable
|
---|
| 299 | * quick change-over to the new input system). Really they should be relocated
|
---|
| 300 | * to more suitable homes based on their function.
|
---|
[1098] | 301 | */
|
---|
[1155] | 302 |
|
---|
| 303 | public static void adjustInitiationTime(Widget track, long adjustment) {
|
---|
[1098] | 304 | if (track instanceof SampledTrack) {
|
---|
| 305 | adjustInitiationTime((SampledTrack) track, adjustment);
|
---|
| 306 | } else if (track instanceof LinkedTrack) {
|
---|
| 307 | adjustInitiationTime((LinkedTrack) track, adjustment);
|
---|
| 308 | }
|
---|
| 309 | }
|
---|
[1155] | 310 |
|
---|
| 311 | public static void adjustInitiationTime(SampledTrack track, long adjustment) {
|
---|
[1098] | 312 | Mutable.Long oldIt = track.getInitiationTimeFromMeta();
|
---|
[1179] | 313 | if (oldIt == null) {
|
---|
[1155] | 314 | oldIt = Mutable.createMutableLong(0);
|
---|
[1179] | 315 | }
|
---|
[1098] | 316 | track.setInitiationTime(oldIt.value + adjustment);
|
---|
| 317 | }
|
---|
[1155] | 318 |
|
---|
| 319 | public static void adjustInitiationTime(LinkedTrack track, long adjustment) {
|
---|
[1098] | 320 | Mutable.Long oldIt = track.getInitiationTimeFromMeta();
|
---|
[1179] | 321 | if (oldIt == null) {
|
---|
[1155] | 322 | oldIt = Mutable.createMutableLong(0);
|
---|
[1179] | 323 | }
|
---|
[1098] | 324 | track.setInitiationTime(oldIt.value + adjustment);
|
---|
| 325 | }
|
---|
[1155] | 326 |
|
---|
| 327 | public static void adjustVerticalPosition(Widget track, long adjustment) {
|
---|
[1098] | 328 | if (track instanceof SampledTrack) {
|
---|
| 329 | adjustVerticalPosition((SampledTrack) track, adjustment);
|
---|
| 330 | } else if (track instanceof LinkedTrack) {
|
---|
| 331 | adjustVerticalPosition((LinkedTrack) track, adjustment);
|
---|
| 332 | }
|
---|
| 333 | }
|
---|
[1155] | 334 |
|
---|
| 335 | public static void adjustVerticalPosition(SampledTrack track, long adjustment) {
|
---|
[1098] | 336 | track.setYPosition(track.getY() + (int) adjustment);
|
---|
| 337 | }
|
---|
[1155] | 338 |
|
---|
| 339 | public static void adjustVerticalPosition(LinkedTrack track, long adjustment) {
|
---|
[1098] | 340 | track.setYPosition(track.getY() + (int) adjustment);
|
---|
| 341 | }
|
---|
| 342 |
|
---|
[1155] | 343 | public static void createLinkedTracks(Item currentItem, Collection<Item> enclosedItems) {
|
---|
[1098] | 344 | if (currentItem == null) {
|
---|
| 345 |
|
---|
| 346 | if (enclosedItems != null) {
|
---|
[1155] | 347 |
|
---|
[1098] | 348 | Frame current = DisplayController.getCurrentFrame();
|
---|
[1155] | 349 |
|
---|
[1098] | 350 | Collection<Item> toRemove = new LinkedHashSet<Item>(enclosedItems.size());
|
---|
| 351 | LinkedList<LinkedTrack> enclosedLinkedTracks = new LinkedList<LinkedTrack>();
|
---|
| 352 | LinkedList<SampledTrack> enclosedTracks = new LinkedList<SampledTrack>();
|
---|
[1155] | 353 |
|
---|
[1098] | 354 | // Get enclosing shape and enclosed tracks
|
---|
| 355 | for (Item ip : enclosedItems) {
|
---|
[1179] | 356 | if (ip.getParent() != current) {
|
---|
[1155] | 357 | continue;
|
---|
[1179] | 358 | }
|
---|
[1155] | 359 |
|
---|
[1098] | 360 | if (ip.hasPermission(UserAppliedPermission.full)) {
|
---|
[1155] | 361 | // Only include lines if one of their enpoints are also being removed
|
---|
[1098] | 362 | if (ip instanceof Line) {
|
---|
| 363 | Line l = (Line) ip;
|
---|
| 364 | Item end = l.getEndItem();
|
---|
| 365 | Item start = l.getStartItem();
|
---|
| 366 |
|
---|
| 367 | // If one end of a line is being delted, remove the
|
---|
| 368 | // other end if all its connecting lines are being
|
---|
| 369 | // delted
|
---|
| 370 | if (enclosedItems.contains(end)) {
|
---|
[1155] | 371 | if (!enclosedItems.contains(start) && enclosedItems.containsAll(start.getLines())) {
|
---|
[1098] | 372 | toRemove.add(start);
|
---|
| 373 | }
|
---|
| 374 | } else if (enclosedItems.contains(start)) {
|
---|
| 375 | if (enclosedItems.containsAll(end.getLines())) {
|
---|
| 376 | toRemove.add(end);
|
---|
| 377 | }
|
---|
| 378 | } else {
|
---|
| 379 | continue;
|
---|
| 380 | }
|
---|
[1155] | 381 | } else if (ip instanceof WidgetCorner) {
|
---|
| 382 | Widget iw = ((WidgetCorner) ip).getWidgetSource();
|
---|
[1098] | 383 | if (!enclosedTracks.contains(iw) && iw instanceof SampledTrack) {
|
---|
[1155] | 384 | enclosedTracks.add((SampledTrack) iw);
|
---|
[1098] | 385 | } else if (!enclosedLinkedTracks.contains(iw) && iw instanceof LinkedTrack) {
|
---|
[1155] | 386 | enclosedLinkedTracks.add((LinkedTrack) iw);
|
---|
[1098] | 387 | }
|
---|
| 388 | } else {
|
---|
[1155] | 389 | if ((ip instanceof Line || ip instanceof Dot)
|
---|
| 390 | && ip.getHighlightMode() == HighlightMode.Enclosed) {
|
---|
[1098] | 391 | toRemove.add(ip);
|
---|
| 392 | toRemove.addAll(ip.getConnected());
|
---|
| 393 | }
|
---|
| 394 | }
|
---|
[1155] | 395 |
|
---|
[1098] | 396 | }
|
---|
| 397 | } // End searching enclosed items
|
---|
[1155] | 398 |
|
---|
[1098] | 399 | // If there was some enclosed tracks
|
---|
[1155] | 400 | if (current != null && !toRemove.isEmpty()
|
---|
| 401 | && (!enclosedLinkedTracks.isEmpty() || !enclosedTracks.isEmpty())) {
|
---|
[1098] | 402 |
|
---|
| 403 | // Remove enclosure
|
---|
| 404 | current.removeAllItems(toRemove);
|
---|
[1155] | 405 |
|
---|
[1098] | 406 | // Determine initiation time of group
|
---|
| 407 | Mutable.Long initTime = null;
|
---|
| 408 | Point initiatePosition = null;
|
---|
[1155] | 409 |
|
---|
[1098] | 410 | for (SampledTrack st : enclosedTracks) {
|
---|
[1155] | 411 |
|
---|
[1098] | 412 | if (initTime == null) {
|
---|
| 413 | initTime = st.getInitiationTimeFromMeta();
|
---|
| 414 | initiatePosition = st.getPosition();
|
---|
[1155] | 415 | } else if (st.getInitiationTimeFromMeta() != null
|
---|
| 416 | && st.getInitiationTimeFromMeta().value < initTime.value) {
|
---|
[1098] | 417 | initTime = st.getInitiationTimeFromMeta();
|
---|
| 418 | initiatePosition = st.getPosition();
|
---|
| 419 | }
|
---|
| 420 | }
|
---|
| 421 | for (LinkedTrack lt : enclosedLinkedTracks) {
|
---|
| 422 |
|
---|
| 423 | if (initTime == null) {
|
---|
| 424 | initTime = lt.getInitiationTimeFromMeta();
|
---|
| 425 | initiatePosition = lt.getPosition();
|
---|
[1155] | 426 | } else if (lt.getInitiationTimeFromMeta() != null
|
---|
| 427 | && lt.getInitiationTimeFromMeta().value < initTime.value) {
|
---|
[1098] | 428 | initTime = lt.getInitiationTimeFromMeta();
|
---|
| 429 | initiatePosition = lt.getPosition();
|
---|
| 430 | }
|
---|
| 431 | }
|
---|
[1155] | 432 |
|
---|
| 433 | assert (initTime != null);
|
---|
| 434 | assert (initiatePosition != null);
|
---|
| 435 |
|
---|
[1098] | 436 | // Creat the link to contain all tracks
|
---|
| 437 | String name = current.getTitle();
|
---|
[1179] | 438 | if (name == null) {
|
---|
[1155] | 439 | name = "Unnamed";
|
---|
[1179] | 440 | }
|
---|
[1098] | 441 | name += " group";
|
---|
[1155] | 442 |
|
---|
[1098] | 443 | Text linkSource = new Text(current.getNextItemID());
|
---|
| 444 | linkSource.addToData(TrackWidgetCommons.META_NAME_TAG + name);
|
---|
| 445 | linkSource.addToData(TrackWidgetCommons.META_INITIATIONTIME_TAG + initTime);
|
---|
| 446 | linkSource.setPosition(initiatePosition);
|
---|
| 447 | linkSource.setParent(current);
|
---|
| 448 | LinkedTrack linkedVersion = new LinkedTrack(linkSource, null);
|
---|
[1155] | 449 |
|
---|
[1098] | 450 | // Create a new frame to hold the track group
|
---|
| 451 | Frame newFrame = FrameIO.CreateNewFrame(linkedVersion.getItems().get(0));
|
---|
| 452 |
|
---|
| 453 | for (SampledTrack st : enclosedTracks) {
|
---|
| 454 | st.saveAudio(); // Blocking
|
---|
| 455 | current.removeAllItems(st.getItems());
|
---|
| 456 | newFrame.addAllItems(st.getItems());
|
---|
| 457 | }
|
---|
[1155] | 458 |
|
---|
[1098] | 459 | for (LinkedTrack lt : enclosedLinkedTracks) {
|
---|
| 460 | current.removeAllItems(lt.getItems());
|
---|
| 461 | newFrame.addAllItems(lt.getItems());
|
---|
| 462 | }
|
---|
[1155] | 463 |
|
---|
[1098] | 464 | FrameIO.SaveFrame(newFrame);
|
---|
[1155] | 465 |
|
---|
[1098] | 466 | // Link the linked tracks
|
---|
| 467 | linkedVersion.setLink(newFrame.getName(), null);
|
---|
[1155] | 468 |
|
---|
[1098] | 469 | // Add the new link
|
---|
| 470 | current.addAllItems(linkedVersion.getItems());
|
---|
[1155] | 471 |
|
---|
| 472 | // Ensure initiation time is retained to the exact frame... avoiding loss due to
|
---|
| 473 | // resolution
|
---|
[1098] | 474 | linkedVersion.setInitiationTime(initTime.value);
|
---|
| 475 | }
|
---|
| 476 | }
|
---|
| 477 | }
|
---|
| 478 | }
|
---|
[1155] | 479 |
|
---|
| 480 | /**
|
---|
| 481 | * The minimum distance from a track widget to auto-align free space items to.
|
---|
| 482 | */
|
---|
[1098] | 483 | private static final int COARSE_X_PLACEMENT_TOLERANCE = 80;
|
---|
| 484 |
|
---|
[1155] | 485 | private static final int COARSE_Y_PLACEMENT_TOLERANCE = 20;
|
---|
| 486 |
|
---|
[1523] | 487 | private void snapFreeTracks(Point position) {
|
---|
| 488 | // Get Apollo widgets that are attached to cursor
|
---|
| 489 | FreeItems freeItems = FreeItems.getInstance();
|
---|
| 490 | List<Widget> freeWidgets = ItemUtils.extractWidgets(freeItems);
|
---|
| 491 | List<Widget> freeApolloWidgets = new ArrayList<Widget>();
|
---|
| 492 | for (Widget w: freeWidgets) {
|
---|
| 493 | if (w instanceof SampledTrack || w instanceof LinkedTrack) { freeApolloWidgets.add(w); }
|
---|
| 494 | }
|
---|
| 495 | if (freeApolloWidgets.isEmpty()) { return; }
|
---|
| 496 |
|
---|
| 497 | // Get Apollo widgets that are on frame
|
---|
| 498 | Frame currentFrame = DisplayController.getCurrentFrame();
|
---|
| 499 | List<Widget> interactiveWidgets = currentFrame.getInteractiveWidgets();
|
---|
| 500 | List<Widget> anchoredApolloWidgets = new ArrayList<Widget>();
|
---|
| 501 | for (Widget w: interactiveWidgets) {
|
---|
| 502 | if (w instanceof SampledTrack || w instanceof LinkedTrack) { anchoredApolloWidgets.add(w); }
|
---|
| 503 | }
|
---|
| 504 | if (anchoredApolloWidgets.isEmpty()) { return; }
|
---|
| 505 |
|
---|
| 506 | // Snap the first freeApolloWidget.
|
---|
| 507 | // Snap the freeApolloWidgets, using the first as a guidepost.
|
---|
| 508 | Widget toSnap = freeApolloWidgets.remove(0);
|
---|
| 509 | Point origin = new Point(0,0);
|
---|
| 510 | Point canditateDistance = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
---|
| 511 | Widget anchoredWidgetToSnapTo = null;
|
---|
| 512 | AxisAlignedBoxBounds freeWidgetBounds = toSnap.getBounds();
|
---|
| 513 | for (Widget anchoredWidget: anchoredApolloWidgets) {
|
---|
| 514 | AxisAlignedBoxBounds anchoredWidgetBounds = anchoredWidget.getBounds();
|
---|
| 515 | Point distance = freeWidgetBounds.distanceFrom(anchoredWidgetBounds);
|
---|
| 516 | if (distance.getDistanceTo(origin) < canditateDistance.getDistanceTo(origin)) {
|
---|
| 517 | canditateDistance = distance;
|
---|
| 518 | anchoredWidgetToSnapTo = anchoredWidget;
|
---|
[1098] | 519 | }
|
---|
[1523] | 520 | }
|
---|
| 521 | AxisAlignedBoxBounds anchoredWidgetToSnapToBounds = anchoredWidgetToSnapTo.getBounds();
|
---|
| 522 |
|
---|
| 523 | int xDist = anchoredWidgetToSnapToBounds.getCentreX() < freeWidgetBounds.getCentreX() ? canditateDistance.getX() : -canditateDistance.getX();
|
---|
| 524 | int yDist = anchoredWidgetToSnapToBounds.getCentreY() < freeWidgetBounds.getCentreY() ? canditateDistance.getY() : -canditateDistance.getY();
|
---|
[1098] | 525 |
|
---|
[1523] | 526 | int direction = -1;
|
---|
| 527 | int tlX = toSnap.getX();
|
---|
| 528 | int tlY = toSnap.getY();
|
---|
| 529 | if ((xDist > 0 && yDist == 0) || (xDist == 0 && yDist == 0)) {
|
---|
| 530 | tlX = anchoredWidgetToSnapTo.getBounds().getMaxX();
|
---|
| 531 | tlY = anchoredWidgetToSnapTo.getBounds().getMinY();
|
---|
| 532 | direction = 0;
|
---|
| 533 | } else if (xDist < 0 && yDist == 0) {
|
---|
| 534 | tlX = anchoredWidgetToSnapTo.getBounds().getMinX() - toSnap.getWidth();
|
---|
| 535 | tlY = anchoredWidgetToSnapTo.getBounds().getMinY();
|
---|
| 536 | direction = 1;
|
---|
| 537 | } else if (yDist > 0 && xDist == 0) {
|
---|
| 538 | tlX = anchoredWidgetToSnapTo.getBounds().getMinX();
|
---|
| 539 | tlY = anchoredWidgetToSnapTo.getBounds().getMaxY();
|
---|
| 540 | direction = 2;
|
---|
| 541 | } else if (yDist < 0 && xDist == 0) {
|
---|
| 542 | tlX = anchoredWidgetToSnapTo.getBounds().getMinX();
|
---|
| 543 | tlY = anchoredWidgetToSnapTo.getBounds().getMinY() - toSnap.getHeight();
|
---|
| 544 | direction = 3;
|
---|
| 545 | }
|
---|
| 546 | toSnap.setPosition(tlX, tlY);
|
---|
| 547 |
|
---|
| 548 | for (Widget toSnapNext: freeApolloWidgets) {
|
---|
| 549 | switch (direction) {
|
---|
| 550 | case 0:
|
---|
| 551 | tlX = toSnap.getBounds().getMaxX();
|
---|
| 552 | tlY = toSnap.getBounds().getMinY();
|
---|
| 553 | toSnapNext.setPosition(tlX, tlY);
|
---|
| 554 | break;
|
---|
| 555 | case 1:
|
---|
| 556 | tlX = toSnap.getBounds().getMinX() - toSnapNext.getWidth();
|
---|
| 557 | tlY = toSnap.getBounds().getMinY();
|
---|
| 558 | toSnapNext.setPosition(tlX, tlY);
|
---|
| 559 | break;
|
---|
| 560 | case 2:
|
---|
| 561 | tlX = toSnap.getBounds().getMinX();
|
---|
| 562 | tlY = toSnap.getBounds().getMaxX();
|
---|
| 563 | toSnapNext.setPosition(tlX, tlY);
|
---|
| 564 | break;
|
---|
| 565 | case 3:
|
---|
| 566 | tlX = toSnap.getBounds().getMinX();
|
---|
| 567 | tlY = toSnap.getBounds().getMinY() - toSnapNext.getHeight();
|
---|
| 568 | toSnapNext.setPosition(tlX, tlY);
|
---|
| 569 | break;
|
---|
| 570 | default:
|
---|
| 571 | break;
|
---|
[1098] | 572 | }
|
---|
[1523] | 573 | toSnap = toSnapNext;
|
---|
| 574 | }
|
---|
[1098] | 575 | }
|
---|
[1523] | 576 |
|
---|
[1098] | 577 | /**
|
---|
[1155] | 578 | * @return True if the user is restricting movement on the y-axis only
|
---|
[1098] | 579 | */
|
---|
[1155] | 580 | public static boolean isYAxisRestictionOn() {
|
---|
| 581 | return StandardInputEventListeners.kbmStateListener.isKeyDown(Key.CTRL)
|
---|
| 582 | && !StandardInputEventListeners.kbmStateListener.isKeyDown(Key.SHIFT);
|
---|
[1098] | 583 | }
|
---|
[1155] | 584 |
|
---|
| 585 | public static boolean isSnapOn() {
|
---|
| 586 | return StandardInputEventListeners.kbmStateListener.isKeyDown(Key.SHIFT)
|
---|
| 587 | && !StandardInputEventListeners.kbmStateListener.isKeyDown(Key.CTRL);
|
---|
[1098] | 588 | }
|
---|
[1155] | 589 |
|
---|
[1179] | 590 | private void anchorTracks(final List<Item> widgetPieces) {
|
---|
[1155] | 591 |
|
---|
[1098] | 592 | // Widget -> delta IT time
|
---|
| 593 | Map<LinkedTrack, Mutable.Long> anchoredLinkedTracks = null;
|
---|
| 594 | Map<SampledTrack, Mutable.Long> anchoredTracks = null;
|
---|
[1155] | 595 |
|
---|
[1179] | 596 | // if (FreeItems.getInstance().size() > 1) {
|
---|
| 597 | if (widgetPieces.size() > 1) {
|
---|
| 598 | // List<Widget> anchoringWidgets = ItemUtils.extractWidgets(FreeItems.getInstance());
|
---|
| 599 | List<Widget> anchoringWidgets = ItemUtils.extractWidgets(widgetPieces);
|
---|
[1098] | 600 |
|
---|
| 601 | Mutable.Long firstInitTime = null;
|
---|
| 602 | anchoredLinkedTracks = new HashMap<LinkedTrack, Mutable.Long>();
|
---|
| 603 | anchoredTracks = new HashMap<SampledTrack, Mutable.Long>();
|
---|
[1155] | 604 |
|
---|
[1098] | 605 | for (Widget iw : anchoringWidgets) {
|
---|
[1155] | 606 |
|
---|
[1098] | 607 | Mutable.Long it = null;
|
---|
[1155] | 608 |
|
---|
[1098] | 609 | if (iw instanceof LinkedTrack) {
|
---|
[1155] | 610 |
|
---|
| 611 | LinkedTrack lt = (LinkedTrack) iw;
|
---|
[1098] | 612 | it = lt.getInitiationTimeFromMeta();
|
---|
[1179] | 613 | if (it == null) {
|
---|
[1155] | 614 | it = Mutable.createMutableLong(0);
|
---|
[1179] | 615 | }
|
---|
[1155] | 616 |
|
---|
[1098] | 617 | anchoredLinkedTracks.put(lt, it);
|
---|
[1155] | 618 |
|
---|
[1098] | 619 | } else if (iw instanceof SampledTrack) {
|
---|
[1155] | 620 |
|
---|
| 621 | SampledTrack st = (SampledTrack) iw;
|
---|
[1098] | 622 | it = st.getInitiationTimeFromMeta();
|
---|
[1179] | 623 | if (it == null) {
|
---|
[1155] | 624 | it = Mutable.createMutableLong(0);
|
---|
[1179] | 625 | }
|
---|
[1155] | 626 |
|
---|
[1098] | 627 | anchoredTracks.put(st, it);
|
---|
[1155] | 628 |
|
---|
[1179] | 629 | } else {
|
---|
[1155] | 630 | continue;
|
---|
[1179] | 631 | }
|
---|
[1155] | 632 |
|
---|
[1098] | 633 | if (firstInitTime == null) {
|
---|
| 634 | firstInitTime = Mutable.createMutableLong(it.value); // Important to create new instance
|
---|
| 635 | } else if (it.value < firstInitTime.value) {
|
---|
| 636 | firstInitTime = Mutable.createMutableLong(it.value); // Important to create new instance
|
---|
| 637 | }
|
---|
| 638 | }
|
---|
[1155] | 639 |
|
---|
[1098] | 640 | // Should do a accurate anchor with init times properly aligned?
|
---|
| 641 | if ((anchoredLinkedTracks.size() + anchoredTracks.size()) > 1) {
|
---|
[1155] | 642 |
|
---|
| 643 | assert (firstInitTime != null);
|
---|
| 644 |
|
---|
[1098] | 645 | // Then calc all the deltas
|
---|
| 646 | for (LinkedTrack lt : anchoredLinkedTracks.keySet()) {
|
---|
| 647 | Mutable.Long it = anchoredLinkedTracks.get(lt);
|
---|
| 648 | it.value -= firstInitTime.value;
|
---|
| 649 | }
|
---|
[1155] | 650 |
|
---|
[1098] | 651 | for (SampledTrack st : anchoredTracks.keySet()) {
|
---|
| 652 | Mutable.Long it = anchoredTracks.get(st);
|
---|
| 653 | it.value -= firstInitTime.value;
|
---|
| 654 | }
|
---|
| 655 |
|
---|
| 656 | } else {
|
---|
| 657 | anchoredLinkedTracks = null;
|
---|
| 658 | anchoredTracks = null;
|
---|
| 659 | }
|
---|
[1155] | 660 |
|
---|
[1098] | 661 | }
|
---|
[1179] | 662 |
|
---|
[1098] | 663 | // If anchored a group of tracks .. adjust initiation times to
|
---|
| 664 | if (anchoredLinkedTracks != null) {
|
---|
[1155] | 665 |
|
---|
[1098] | 666 | Mutable.Long firstInitTime = null;
|
---|
[1155] | 667 |
|
---|
[1098] | 668 | for (LinkedTrack lt : anchoredLinkedTracks.keySet()) {
|
---|
| 669 | Mutable.Long it = anchoredLinkedTracks.get(lt);
|
---|
| 670 | if (it.value == 0) {
|
---|
| 671 | firstInitTime = lt.getInitiationTimeFromMeta();
|
---|
| 672 | break;
|
---|
| 673 | }
|
---|
| 674 | }
|
---|
| 675 | if (firstInitTime == null) {
|
---|
| 676 | for (SampledTrack st : anchoredTracks.keySet()) {
|
---|
| 677 | Mutable.Long it = anchoredTracks.get(st);
|
---|
| 678 | if (it.value == 0) {
|
---|
| 679 | firstInitTime = st.getInitiationTimeFromMeta();
|
---|
| 680 | break;
|
---|
| 681 | }
|
---|
| 682 | }
|
---|
| 683 | }
|
---|
[1155] | 684 | assert (firstInitTime != null);
|
---|
| 685 |
|
---|
[1098] | 686 | for (LinkedTrack lt : anchoredLinkedTracks.keySet()) {
|
---|
| 687 | Mutable.Long it = anchoredLinkedTracks.get(lt);
|
---|
[1179] | 688 | if (it.value == 0) {
|
---|
[1155] | 689 | continue;
|
---|
[1179] | 690 | }
|
---|
[1098] | 691 | lt.setInitiationTime(firstInitTime.value + it.value);
|
---|
| 692 | }
|
---|
[1155] | 693 |
|
---|
[1098] | 694 | for (SampledTrack st : anchoredTracks.keySet()) {
|
---|
| 695 | Mutable.Long it = anchoredTracks.get(st);
|
---|
[1179] | 696 | if (it.value == 0) {
|
---|
[1155] | 697 | continue;
|
---|
[1179] | 698 | }
|
---|
[1098] | 699 | st.setInitiationTime(firstInitTime.value + it.value);
|
---|
| 700 | }
|
---|
[1155] | 701 |
|
---|
[1098] | 702 | }
|
---|
| 703 | }
|
---|
| 704 | }
|
---|