This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
In the code (NB 6.0) of AlignWithSupport.locationSuggested y movement handling didn't use the "bothSides" flag, working as it is set always to true. The following implementation solves the problem and adds handling for "snap to centers" movements: public class FEPAlignWithSupport { private static final int GRAVITY = 10; private int gravity; private AlignWithWidgetCollector collector; private LayerWidget interractionLayer; private AlignWithMoveDecorator decorator; private ConnectionWidget lineWidget1; private ConnectionWidget lineWidget2; public FEPAlignWithSupport ( AlignWithWidgetCollector collector, LayerWidget interractionLayer, AlignWithMoveDecorator decorator ) { this(collector, interractionLayer, decorator, GRAVITY); } public FEPAlignWithSupport ( AlignWithWidgetCollector collector, LayerWidget interractionLayer, AlignWithMoveDecorator decorator, int gravity ) { this.collector = collector; this.interractionLayer = interractionLayer; this.decorator = decorator; this.gravity = gravity; } public int getGravity ( ) { return gravity; } public void hide ( ) { if ( interractionLayer != null ) { interractionLayer.removeChild(lineWidget1); interractionLayer.removeChild(lineWidget2); } } protected Point locationSuggested ( Widget widget, Rectangle sceneWidgetBounds, Point suggestedLocation, boolean horizontal, boolean vertical, boolean bothSides, boolean centers, boolean snapHack ) { Point point = new Point(suggestedLocation); Collection<Rectangle> regions = collector.getRegions(widget); if ( horizontal ) { boolean snap = false; int xs = 0; int x = 0; int dx = 0; int y1 = 0; int y2 = 0; int b1 = sceneWidgetBounds.x; int b2 = sceneWidgetBounds.x + sceneWidgetBounds.width; int b3 = sceneWidgetBounds.x + sceneWidgetBounds.width / 2; for ( Rectangle rectangle : regions ) { int d; int a1 = rectangle.x; int a2 = a1 + rectangle.width; int a3 = a1 + rectangle.width / 2; boolean snapNow = false; if ( centers ) { d = Math.abs(a3 - b3); if ( ( snap && d < dx ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; x = a3; xs = a3 - sceneWidgetBounds.width / 2; dx = d; } } d = Math.abs(a1 - b1); if ( ( snap && d < dx ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; x = a1; xs = a1; dx = d; } if ( bothSides ) { d = Math.abs(a1 - b2); if ( ( snap && d < dx ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; x = a1; xs = a1 - sceneWidgetBounds.width; dx = d; } } d = Math.abs(a2 - b1); if ( ( snap && d < dx ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; x = a2; xs = a2; dx = d; } if ( bothSides ) { d = Math.abs(a2 - b2); if ( ( snap && d < dx ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; x = a2; xs = a2 - sceneWidgetBounds.width; dx = d; } } if ( snapNow ) { y1 = rectangle.y; y2 = rectangle.y + rectangle.height; } } if ( snap ) { point.x = xs; if ( snapHack ) point.x -= widget.getBounds().x; } if ( interractionLayer != null ) { lineWidget1.setControlPoints( snap ? Arrays.asList( new Point(x, Math.min(sceneWidgetBounds.y, y1)), new Point(x, Math.max(sceneWidgetBounds.y + sceneWidgetBounds.height, y2)) ) : Collections.<Point>emptyList(), true ); } } if ( vertical ) { boolean snap = false; int ys = 0; int y = 0; int dy = 0; int x1 = 0; int x2 = 0; int b1 = sceneWidgetBounds.y; int b2 = sceneWidgetBounds.y + sceneWidgetBounds.height; int b3 = sceneWidgetBounds.y + sceneWidgetBounds.height / 2; for ( Rectangle rectangle : regions ) { int d; int a1 = rectangle.y; int a2 = a1 + rectangle.height; int a3 = a1 + rectangle.height / 2; boolean snapNow = false; if ( centers ) { d = Math.abs(a3 - b3); if ( ( snap && d < dy ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; y = a3; ys = a3 - sceneWidgetBounds.height / 2; dy = d; } } d = Math.abs(a1 - b1); if ( ( snap && d < dy ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; y = a1; ys = a1; dy = d; } if ( bothSides ) { d = Math.abs(a1 - b2); if ( ( snap && d < dy ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; y = a1; ys = a1 - sceneWidgetBounds.height; dy = d; } } d = Math.abs(a2 - b1); if ( ( snap && d < dy ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; y = a2; ys = a2; dy = d; } if ( bothSides ) { d = Math.abs(a2 - b2); if ( ( snap && d < dy ) || ( ! snap && d < gravity ) ) { snap = true; snapNow = true; y = a2; ys = a2 - sceneWidgetBounds.height; dy = d; } } if ( snapNow ) { x1 = rectangle.x; x2 = rectangle.x + rectangle.width; } } if ( snap ) { point.y = ys; if ( snapHack ) point.y -= widget.getBounds().y; } if ( interractionLayer != null ) { lineWidget2.setControlPoints( snap ? Arrays.asList( new Point(Math.min(sceneWidgetBounds.x, x1), y), new Point(Math.max(sceneWidgetBounds.x + sceneWidgetBounds.width, x2), y) ) : Collections.<Point>emptyList(), true ); } } return point; } public void setGravity ( int gravity ) { this.gravity = gravity; } public void show ( ) { if ( interractionLayer != null ) { if ( lineWidget1 == null ) lineWidget1 = decorator.createLineWidget(interractionLayer.getScene()); if ( lineWidget2 == null ) lineWidget2 = decorator.createLineWidget(interractionLayer.getScene()); interractionLayer.addChild(lineWidget1); interractionLayer.addChild(lineWidget2); lineWidget1.setControlPoints(Collections.<Point>emptySet(), true); lineWidget2.setControlPoints(Collections.<Point>emptySet(), true); } } } // class FEPAlignWithSupport Moreover, the following classes allow snapped movements handling of a selection of widgets using the selection lead for the snap operations: private class MultiAlignWithMoveStrategyProvider extends FEPAlignWithSupport implements MoveStrategy, MoveProvider { private boolean outerBounds; private Point original; private Map<Widget, Point> originals = new HashMap<Widget, Point>(); public MultiAlignWithMoveStrategyProvider ( AlignWithWidgetCollector collector, LayerWidget interractionLayer, AlignWithMoveDecorator decorator, boolean outerBounds ) { super(collector, interractionLayer, decorator); this.outerBounds = outerBounds; } public Point locationSuggested ( Widget widget, Point originalLocation, Point suggestedLocation ) { Point widgetLocation = widget.getLocation(); Rectangle widgetBounds = outerBounds ? widget.getBounds() : widget.getClientArea(); Rectangle bounds = widget.convertLocalToScene(widgetBounds); bounds.translate(suggestedLocation.x - widgetLocation.x, suggestedLocation.y - widgetLocation.y); Insets insets = widget.getBorder().getInsets(); if ( ! outerBounds ) { suggestedLocation.x += insets.left; suggestedLocation.y += insets.top; } Point point = super.locationSuggested(widget, bounds, suggestedLocation, true, true, true, true, true); if ( ! outerBounds ) { point.x -= insets.left; point.y -= insets.top; } return widget.getParentWidget().convertSceneToLocal(point); } public void movementStarted ( Widget widget ) { Object object = scene.findObject(widget); if ( scene.isNode(object) ) { for ( Object o : scene.getSelectedObjects() ) { if ( scene.isNode(o) ) { Widget w = scene.findWidget(o); if ( w != null ) originals.put(w, w.getPreferredLocation()); } } } else originals.put(widget, widget.getPreferredLocation()); show(); } public void movementFinished ( Widget widget ) { hide(); originals.clear(); original = null; } public Point getOriginalLocation ( Widget widget ) { original = widget.getPreferredLocation(); return original; } public void setNewLocation ( Widget widget, Point location ) { int dx = location.x - original.x; int dy = location.y - original.y; for ( Map.Entry<Widget, Point> entry : originals.entrySet() ) { Point point = entry.getValue(); entry.getKey().setPreferredLocation(new Point(point.x + dx, point.y + dy)); } } } // class MultiAlignWithMoveStrategyProvider private class MultiMoveProvider implements MoveProvider { private Point original; private Map<Widget, Point> originals = new HashMap<Widget, Point>(); public void movementStarted ( Widget widget ) { Object object = scene.findObject(widget); if ( scene.isNode(object) ) { for ( Object o : scene.getSelectedObjects() ) { if ( scene.isNode(o) ) { Widget w = scene.findWidget(o); if ( w != null ) originals.put(w, w.getPreferredLocation()); } } } else originals.put(widget, widget.getPreferredLocation()); } public void movementFinished ( Widget widget ) { originals.clear(); original = null; } public Point getOriginalLocation ( Widget widget ) { original = widget.getPreferredLocation(); return original; } public void setNewLocation ( Widget widget, Point location ) { int dx = location.x - original.x; int dy = location.y - original.y; for ( Map.Entry<Widget, Point> entry : originals.entrySet() ) { Point point = entry.getValue(); entry.getKey().setPreferredLocation(new Point(point.x + dx, point.y + dy)); } } } // class MultiMoveProvider Claudio