Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 501716

Summary: Implement alignment feedback and snapping functionality.
Product: [Tools] GEF Reporter: Matthias Wienand <matthias.wienand>
Component: GEF MVCAssignee: gef-inbox <gef-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: nyssen, peter
Version: 1.0.0   
Target Milestone: 5.0.0 (Oxygen) RC1   
Hardware: All   
OS: All   
Whiteboard:

Description Matthias Wienand CLA 2016-09-19 08:42:46 EDT
When placing visual elements within a diagram, the elements should often be aligned to other, already existing, visual elements. In many graphical applications, the user is supported when placing visuals by alignment feedback and snapping functionality.

When a currently manipulated visual aligns with another visual, then a horizontal or vertical feedback line should be drawn to highlight the alignment. This is called alignment feedback.

When a currently manipulated visual is placed near to a position where it would align with another visual, then it should snap to the alignment position and alignment feedback should be shown. This is called snapping functionality.

Within MVC.FX, a dedicated model and behavior implementations should be provided for snapping feedabck, and dedicated policies should be provided for implementing snapping functionality.
Comment 1 Matthias Wienand CLA 2017-05-05 11:20:49 EDT
I implemented snap-to-geometry functionality and pushed the changes to master. However, the snap-to-grid and snap-to-geometry functionality still need to be refactored so that they are based on a unified snap-to concept.
Comment 2 Alexander Nyßen CLA 2017-05-18 02:52:50 EDT
With the latest changes, MVC.FX tests now fail with an NPE:

java.lang.NullPointerException
	at org.eclipse.gef.mvc.fx.handlers.SnapToSupport.stopSnapping(SnapToSupport.java:359)
	at org.eclipse.gef.mvc.fx.handlers.TranslateSelectedOnDragHandler.endDrag(TranslateSelectedOnDragHandler.java:131)
	at org.eclipse.gef.mvc.fx.gestures.ClickDragGesture.release(ClickDragGesture.java:471)
	at org.eclipse.gef.mvc.fx.gestures.ClickDragGesture$1.handle(ClickDragGesture.java:141)
	at org.eclipse.gef.mvc.fx.gestures.ClickDragGesture$1.handle(ClickDragGesture.java:1)
	at com.sun.javafx.event.CompositeEventHandler$NormalEventFilterRecord.handleCapturingEvent(CompositeEventHandler.java:282)
	at com.sun.javafx.event.CompositeEventHandler.dispatchCapturingEvent(CompositeEventHandler.java:98)
	at com.sun.javafx.event.EventHandlerManager.dispatchCapturingEvent(EventHandlerManager.java:223)
	at com.sun.javafx.event.EventHandlerManager.dispatchCapturingEvent(EventHandlerManager.java:180)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchCapturingEvent(CompositeEventDispatcher.java:43)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:52)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.event.Event.fireEvent(Event.java:198)
	at org.eclipse.gef.mvc.tests.fx.rules.FXNonApplicationThreadRule.lambda$5(FXNonApplicationThreadRule.java:558)
	at org.eclipse.gef.mvc.tests.fx.rules.FXNonApplicationThreadRule$$Lambda$238/797539755.run(Unknown Source)
	at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
	at com.sun.javafx.application.PlatformImpl$$Lambda$68/1821095226.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
	at com.sun.javafx.application.PlatformImpl$$Lambda$67/1506938939.run(Unknown Source)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
	at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
	at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126)
	at com.sun.glass.ui.gtk.GtkApplication$$Lambda$47/71515465.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Comment 3 Matthias Wienand CLA 2017-05-18 10:26:10 EDT
I refactored the code so that both snap-to-grid and snap-to-geometry are based on a unified snap-to concept, and I resolved the obvious errors.

The interface for snapping algorithms is defined by ISnapToStrategy, which provides a method to compute the translation that needs to be applied to a source snapping location in order to align it with a target snapping location.

The source and target snapping locations are either provided by an IHandler or by an ISnappingLocationProvider that is registered for the individual parts that participate in snapping.

A snapping location is the combination of an orientation (horizontal or vertical) and a coordinate value (x- or y-coordinate, depending on orientation).

The SnapToSupport class can be used by an IHandler to perform snapping. The supported snapping strategies and snapping locations needed for alignment feedback are stored in the SnappingModel.

The code is published on the master branch, therefore, I resolve this ticket as fixed for 5.0.0 RC1.