diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java index 9de6841fd3..2941573fc7 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java @@ -18,9 +18,9 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.designer.actions; +import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.EntityGroup; -import com.willwinder.ugs.nbp.designer.entities.controls.Location; import com.willwinder.ugs.nbp.designer.entities.controls.ResizeUtils; import com.willwinder.ugs.nbp.designer.model.Size; @@ -34,30 +34,38 @@ This file is part of Universal Gcode Sender (UGS). * @author Joacim Breiler */ public class ResizeAction implements UndoableAction { - private final Location location; + private final Anchor anchor; private final List entities; private final Size originalSize; private final Size newSize; - public ResizeAction(List entities, Location location, Size originalSize, Size newSize) { + /** + * Resizes the entities from an anchor position + * + * @param entities a list of entities that is being resized + * @param anchor the corner that is being anchored + * @param originalSize the original size + * @param newSize the new size + */ + public ResizeAction(List entities, Anchor anchor, Size originalSize, Size newSize) { this.entities = new ArrayList<>(entities); - this.location = location; this.originalSize = originalSize; this.newSize = newSize; + this.anchor = anchor; } @Override public void redo() { EntityGroup entityGroup = new EntityGroup(); entityGroup.addAll(entities); - ResizeUtils.performScaling(entityGroup, location, originalSize, newSize); + ResizeUtils.performScaling(entityGroup, anchor, originalSize, newSize); } @Override public void undo() { EntityGroup entityGroup = new EntityGroup(); entityGroup.addAll(entities); - ResizeUtils.performScaling(entityGroup, location, newSize, originalSize); + ResizeUtils.performScaling(entityGroup, anchor, newSize, originalSize); } @Override diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/AbstractEntity.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/AbstractEntity.java index 885522bd5f..ac70cc5b7d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/AbstractEntity.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/AbstractEntity.java @@ -87,6 +87,12 @@ public Size getSize() { @Override public void setSize(Size size) { + setSize(Anchor.BOTTOM_LEFT, size); + } + + @Override + public void setSize(Anchor anchor, Size size) { + Point2D position = getPosition(anchor); if (size.getWidth() <= 0) { size = new Size(0.0001, size.getHeight()); } @@ -97,6 +103,7 @@ public void setSize(Size size) { Size currentSize = getSize(); scale(size.getWidth() / currentSize.getWidth(), size.getHeight() / currentSize.getHeight()); + setPosition(anchor, position); } @Override diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Anchor.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Anchor.java index 96e72bca6b..39def08764 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Anchor.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Anchor.java @@ -2,8 +2,12 @@ public enum Anchor { TOP_LEFT, + TOP_CENTER, TOP_RIGHT, CENTER, BOTTOM_LEFT, + BOTTOM_CENTER, + LEFT_CENTER, + RIGHT_CENTER, BOTTOM_RIGHT } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Entity.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Entity.java index f432d1924d..ed12701e6d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Entity.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/Entity.java @@ -94,6 +94,14 @@ public interface Entity { */ void setSize(Size size); + /** + * Changes the size of the entity from the given anchor. + * + * @param anchor the anchor to keep + * @param size the new size + */ + void setSize(Anchor anchor, Size size); + /** * Gets the bounds of the entity with the position and size in real space * diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/Location.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/Location.java deleted file mode 100644 index 7c5e847631..0000000000 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/Location.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2021 Will Winder - - This file is part of Universal Gcode Sender (UGS). - - UGS is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - UGS 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with UGS. If not, see . - */ -package com.willwinder.ugs.nbp.designer.entities.controls; - -/** - * @author Joacim Breiler - */ -public enum Location { - BOTTOM, - BOTTOM_LEFT, - BOTTOM_RIGHT, - TOP, - TOP_LEFT, - TOP_RIGHT, - LEFT, - RIGHT -} diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeControl.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeControl.java index 1305d4006b..d7c141e38d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeControl.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeControl.java @@ -21,6 +21,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.Utils; import com.willwinder.ugs.nbp.designer.actions.ResizeAction; import com.willwinder.ugs.nbp.designer.actions.UndoManager; +import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.EntityEvent; import com.willwinder.ugs.nbp.designer.entities.EventType; @@ -51,40 +52,41 @@ public class ResizeControl extends AbstractControl { public static final int SIZE = 8; public static final int MARGIN = 6; public static final double ARC_SIZE = 1d; - private final Location location; + private final RoundRectangle2D.Double shape; private final Controller controller; + private final Anchor anchor; private AffineTransform transform = new AffineTransform(); private Point2D.Double startOffset = new Point2D.Double(); private boolean isHovered; private Size originalSize; private Point2D originalPosition; - public ResizeControl(Controller controller, Location location) { + public ResizeControl(Controller controller, Anchor anchor) { super(controller.getSelectionManager()); this.controller = controller; - this.location = location; this.shape = new RoundRectangle2D.Double(0, 0, SIZE, SIZE, ARC_SIZE, ARC_SIZE); + this.anchor = anchor; } @Override public Optional getHoverCursor() { Cursor cursor = null; - if (location == Location.TOP_LEFT) { + if (anchor == Anchor.BOTTOM_RIGHT) { cursor = new Cursor(Cursor.NW_RESIZE_CURSOR); - } else if (location == Location.TOP_RIGHT) { + } else if (anchor == Anchor.BOTTOM_LEFT) { cursor = new Cursor(Cursor.NE_RESIZE_CURSOR); - } else if (location == Location.BOTTOM_LEFT) { + } else if (anchor == Anchor.TOP_RIGHT) { cursor = new Cursor(Cursor.SW_RESIZE_CURSOR); - } else if (location == Location.BOTTOM_RIGHT) { + } else if (anchor == Anchor.TOP_LEFT) { cursor = new Cursor(Cursor.SE_RESIZE_CURSOR); - } else if (location == Location.BOTTOM) { + } else if (anchor == Anchor.TOP_CENTER) { cursor = new Cursor(Cursor.S_RESIZE_CURSOR); - } else if (location == Location.TOP) { + } else if (anchor == Anchor.BOTTOM_CENTER) { cursor = new Cursor(Cursor.N_RESIZE_CURSOR); - } else if (location == Location.LEFT) { + } else if (anchor == Anchor.RIGHT_CENTER) { cursor = new Cursor(Cursor.W_RESIZE_CURSOR); - } else if (location == Location.RIGHT) { + } else if (anchor == Anchor.LEFT_CENTER) { cursor = new Cursor(Cursor.E_RESIZE_CURSOR); } return Optional.ofNullable(cursor); @@ -138,11 +140,11 @@ public void onEvent(EntityEvent entityEvent) { } else if (mouseShapeEvent.getType() == EventType.MOUSE_DRAGGED) { Size size = getSelectionManager().getSize(); Size newSize = calculateNewSize(size, mousePosition); - ResizeUtils.performScaling(getSelectionManager(), location, size, newSize); + ResizeUtils.performScaling(getSelectionManager(), anchor, size, newSize); } else if (mouseShapeEvent.getType() == EventType.MOUSE_RELEASED) { getSelectionManager().setPosition(originalPosition); Size newSize = calculateNewSize(originalSize, mousePosition); - addUndoAction(getSelectionManager(), location, originalSize, newSize); + addUndoAction(getSelectionManager(), anchor, originalSize, newSize); } else if (mouseShapeEvent.getType() == EventType.MOUSE_IN) { isHovered = true; } else if (mouseShapeEvent.getType() == EventType.MOUSE_OUT) { @@ -151,7 +153,7 @@ public void onEvent(EntityEvent entityEvent) { } } - private void addUndoAction(Entity target, Location location, Size originalSize, Size newSize) { + private void addUndoAction(Entity target, Anchor anchor, Size originalSize, Size newSize) { UndoManager undoManager = ControllerFactory.getUndoManager(); if (undoManager != null) { List entityList = new ArrayList<>(); @@ -160,7 +162,7 @@ private void addUndoAction(Entity target, Location location, Size originalSize, } else { entityList.add(target); } - ResizeAction resizeAction = new ResizeAction(entityList, location, originalSize, newSize); + ResizeAction resizeAction = new ResizeAction(entityList, anchor, originalSize, newSize); resizeAction.redo(); undoManager.addAction(resizeAction); } @@ -179,21 +181,21 @@ private void updatePosition(Drawing drawing) { Rectangle2D bounds = getSelectionManager().getRelativeShape().getBounds2D(); t.translate(bounds.getX(), bounds.getY()); - if (location == Location.BOTTOM_RIGHT) { + if (anchor == Anchor.TOP_LEFT) { t.translate(bounds.getWidth() + margin, -margin); - } else if (location == Location.TOP_LEFT) { + } else if (anchor == Anchor.BOTTOM_RIGHT) { t.translate(-margin, bounds.getHeight() + margin); - } else if (location == Location.TOP_RIGHT) { + } else if (anchor == Anchor.BOTTOM_LEFT) { t.translate(bounds.getWidth() + margin, bounds.getHeight() + margin); - } else if (location == Location.BOTTOM_LEFT) { + } else if (anchor == Anchor.TOP_RIGHT) { t.translate(-margin, -margin); - } else if (location == Location.TOP) { + } else if (anchor == Anchor.BOTTOM_CENTER) { t.translate(bounds.getWidth() / 2d, bounds.getHeight() + margin); - } else if (location == Location.BOTTOM) { + } else if (anchor == Anchor.TOP_CENTER) { t.translate(bounds.getWidth() / 2d, -margin); - } else if (location == Location.LEFT) { + } else if (anchor == Anchor.RIGHT_CENTER) { t.translate(-margin, bounds.getHeight() / 2d); - } else if (location == Location.RIGHT) { + } else if (anchor == Anchor.LEFT_CENTER) { t.translate(bounds.getWidth() + margin, bounds.getHeight() / 2d); } @@ -218,21 +220,21 @@ private Size calculateNewSize(Size size, Point2D mousePosition) { private Point2D getScaleFactor(double deltaX, double deltaY) { Point2D scaleFactor = new Point2D.Double(0, 0); - if (location == Location.BOTTOM_LEFT) { + if (anchor == Anchor.TOP_RIGHT) { scaleFactor.setLocation(1d - deltaX, 1d - deltaX); - } else if (location == Location.TOP_RIGHT) { + } else if (anchor == Anchor.BOTTOM_LEFT) { scaleFactor.setLocation(1d + deltaX, 1d + deltaX); - } else if (location == Location.BOTTOM_RIGHT) { + } else if (anchor == Anchor.TOP_LEFT) { scaleFactor.setLocation(1d + deltaX, 1d + deltaX); - } else if (location == Location.TOP_LEFT) { + } else if (anchor == Anchor.BOTTOM_RIGHT) { scaleFactor.setLocation(1d - deltaX, 1d - deltaX); - } else if (location == Location.LEFT) { + } else if (anchor == Anchor.RIGHT_CENTER) { scaleFactor.setLocation(1d - deltaX, 1d); - } else if (location == Location.BOTTOM) { + } else if (anchor == Anchor.TOP_CENTER) { scaleFactor.setLocation(1d, 1d - deltaY); - } else if (location == Location.TOP) { + } else if (anchor == Anchor.BOTTOM_CENTER) { scaleFactor.setLocation(1d, 1d + deltaY); - } else if (location == Location.RIGHT) { + } else if (anchor == Anchor.LEFT_CENTER) { scaleFactor.setLocation(1d + deltaX, 1d); } return scaleFactor; diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java index 077e277fa4..34ab6821fa 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.designer.entities.controls; +import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.model.Size; @@ -28,30 +29,35 @@ public class ResizeUtils { private ResizeUtils() { } - public static Point2D getDeltaMovement(Location location, Size size, Size newSize) { + public static Point2D getDeltaMovement(Anchor anchor, Size size, Size newSize) { Size deltaSize = new Size(size.getWidth() - newSize.getWidth(), size.getHeight() - newSize.getHeight()); Point2D movement = new Point2D.Double(0, 0); - if (location == Location.BOTTOM_LEFT) { + if (anchor == Anchor.TOP_RIGHT) { movement.setLocation(deltaSize.getWidth(), deltaSize.getHeight()); - } else if (location == Location.BOTTOM_RIGHT) { + } else if (anchor == Anchor.TOP_LEFT) { movement.setLocation(0, deltaSize.getHeight()); - } else if (location == Location.TOP_LEFT) { + } else if (anchor == Anchor.BOTTOM_RIGHT) { movement.setLocation(deltaSize.getWidth(), 0); - } else if (location == Location.LEFT) { - movement.setLocation(deltaSize.getWidth(), 0); - } else if (location == Location.BOTTOM) { - movement.setLocation(0, deltaSize.getHeight()); + } else if (anchor == Anchor.RIGHT_CENTER) { + movement.setLocation(deltaSize.getWidth(), deltaSize.getHeight() / 2); + } else if (anchor == Anchor.TOP_CENTER) { + movement.setLocation(deltaSize.getWidth() / 2, deltaSize.getHeight()); + } else if (anchor == Anchor.CENTER) { + movement.setLocation(deltaSize.getWidth() / 2, deltaSize.getHeight() / 2); + } else if (anchor == Anchor.BOTTOM_CENTER) { + movement.setLocation(deltaSize.getWidth() / 2, 0); + } else if (anchor == Anchor.LEFT_CENTER) { + movement.setLocation(0, deltaSize.getHeight() / 2); } return movement; } - public static void performScaling(Entity target, Location location, Size originalSize, Size newSize) { + public static void performScaling(Entity target, Anchor anchor, Size originalSize, Size newSize) { // Do not scale if the entity will become too small after operation if (newSize.getWidth() <= 0 || newSize.getHeight() <= 0) { return; } - - target.move(getDeltaMovement(location, originalSize, newSize)); + target.move(getDeltaMovement(anchor, originalSize, newSize)); target.setSize(newSize); } } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/Drawing.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/Drawing.java index 6a011da0af..5f5ea101c2 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/Drawing.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/Drawing.java @@ -20,6 +20,7 @@ This file is part of Universal Gcode Sender (UGS). import com.google.common.collect.Sets; import com.willwinder.ugs.nbp.designer.Throttler; +import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.EntityGroup; import com.willwinder.ugs.nbp.designer.entities.controls.Control; @@ -30,7 +31,6 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.entities.controls.EditTextControl; import com.willwinder.ugs.nbp.designer.entities.controls.GridControl; import com.willwinder.ugs.nbp.designer.entities.controls.HighlightModelControl; -import com.willwinder.ugs.nbp.designer.entities.controls.Location; import com.willwinder.ugs.nbp.designer.entities.controls.MoveControl; import com.willwinder.ugs.nbp.designer.entities.controls.ResizeControl; import com.willwinder.ugs.nbp.designer.entities.controls.RotationControl; @@ -86,14 +86,14 @@ public Drawing(Controller controller) { controlsRoot = new EntityGroup(); globalRoot.addChild(controlsRoot); - controlsRoot.addChild(new ResizeControl(controller, Location.TOP)); - controlsRoot.addChild(new ResizeControl(controller, Location.LEFT)); - controlsRoot.addChild(new ResizeControl(controller, Location.RIGHT)); - controlsRoot.addChild(new ResizeControl(controller, Location.BOTTOM)); - controlsRoot.addChild(new ResizeControl(controller, Location.BOTTOM_LEFT)); - controlsRoot.addChild(new ResizeControl(controller, Location.BOTTOM_RIGHT)); - controlsRoot.addChild(new ResizeControl(controller, Location.TOP_LEFT)); - controlsRoot.addChild(new ResizeControl(controller, Location.TOP_RIGHT)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.TOP_CENTER)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.LEFT_CENTER)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.RIGHT_CENTER)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.BOTTOM_CENTER)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.BOTTOM_LEFT)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.BOTTOM_RIGHT)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.TOP_LEFT)); + controlsRoot.addChild(new ResizeControl(controller, Anchor.TOP_RIGHT)); controlsRoot.addChild(new HighlightModelControl(controller.getSelectionManager())); controlsRoot.addChild(new MoveControl(controller)); controlsRoot.addChild(new RotationControl(controller)); diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/anchor/AnchorSelectorPanel.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/anchor/AnchorSelectorPanel.java index e341cb8814..4513f1129a 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/anchor/AnchorSelectorPanel.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/anchor/AnchorSelectorPanel.java @@ -1,9 +1,13 @@ package com.willwinder.ugs.nbp.designer.gui.anchor; import com.willwinder.ugs.nbp.designer.entities.Anchor; +import static com.willwinder.ugs.nbp.designer.entities.Anchor.BOTTOM_CENTER; import static com.willwinder.ugs.nbp.designer.entities.Anchor.BOTTOM_LEFT; import static com.willwinder.ugs.nbp.designer.entities.Anchor.BOTTOM_RIGHT; import static com.willwinder.ugs.nbp.designer.entities.Anchor.CENTER; +import static com.willwinder.ugs.nbp.designer.entities.Anchor.LEFT_CENTER; +import static com.willwinder.ugs.nbp.designer.entities.Anchor.RIGHT_CENTER; +import static com.willwinder.ugs.nbp.designer.entities.Anchor.TOP_CENTER; import static com.willwinder.ugs.nbp.designer.entities.Anchor.TOP_LEFT; import static com.willwinder.ugs.nbp.designer.entities.Anchor.TOP_RIGHT; import net.miginfocom.swing.MigLayout; @@ -19,48 +23,78 @@ public class AnchorSelectorPanel extends JPanel implements ActionListener { + public static final String FIELD_CONSTRAINTS = "alignx center, growy"; + public static final String FIELD_CONSTRAINTS_WRAP = "alignx center, growy, wrap"; private final JRadioButton topLeft; + private final JRadioButton topCenter; private final JRadioButton topRight; private final JRadioButton center; private final JRadioButton bottomRight; + private final JRadioButton bottomCenter; private final JRadioButton bottomLeft; + private final JRadioButton leftCenter; + private final JRadioButton rightCenter; private final Set anchorListeners = new HashSet<>(); public AnchorSelectorPanel() { - setLayout(new MigLayout("fill, insets 0, gap 2")); + setLayout(new MigLayout("fill, insets 0, gap 0")); topLeft = new JRadioButton(); topLeft.setBorder(BorderFactory.createEmptyBorder()); - add(topLeft, "alignx center, growy"); + add(topLeft, FIELD_CONSTRAINTS); + + topCenter = new JRadioButton(); + topCenter.setBorder(BorderFactory.createEmptyBorder()); + add(topCenter, FIELD_CONSTRAINTS); topRight = new JRadioButton(); topRight.setBorder(BorderFactory.createEmptyBorder()); - add(topRight, "alignx center, growy, wrap"); + add(topRight, FIELD_CONSTRAINTS_WRAP); + + leftCenter = new JRadioButton(); + leftCenter.setBorder(BorderFactory.createEmptyBorder()); + add(leftCenter, FIELD_CONSTRAINTS); center = new JRadioButton(); center.setBorder(BorderFactory.createEmptyBorder()); - add(center, "alignx center, spanx, growy, wrap"); + add(center, FIELD_CONSTRAINTS); + + rightCenter = new JRadioButton(); + rightCenter.setBorder(BorderFactory.createEmptyBorder()); + add(rightCenter, FIELD_CONSTRAINTS_WRAP); bottomLeft = new JRadioButton(); bottomLeft.setSelected(true); bottomLeft.setBorder(BorderFactory.createEmptyBorder()); - add(bottomLeft, "alignx center, growy"); + add(bottomLeft, FIELD_CONSTRAINTS); + + bottomCenter = new JRadioButton(); + bottomCenter.setBorder(BorderFactory.createEmptyBorder()); + add(bottomCenter, FIELD_CONSTRAINTS); bottomRight = new JRadioButton(); bottomRight.setBorder(BorderFactory.createEmptyBorder()); - add(bottomRight, "alignx center, growy, wrap"); + add(bottomRight, FIELD_CONSTRAINTS_WRAP); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(topLeft); + buttonGroup.add(topCenter); buttonGroup.add(topRight); + buttonGroup.add(leftCenter); buttonGroup.add(center); + buttonGroup.add(rightCenter); buttonGroup.add(bottomLeft); + buttonGroup.add(bottomCenter); buttonGroup.add(bottomRight); topLeft.addActionListener(this); + topCenter.addActionListener(this); topRight.addActionListener(this); + leftCenter.addActionListener(this); center.addActionListener(this); + rightCenter.addActionListener(this); bottomLeft.addActionListener(this); + bottomCenter.addActionListener(this); bottomRight.addActionListener(this); } @@ -69,12 +103,20 @@ public void actionPerformed(ActionEvent e) { JRadioButton button = (JRadioButton) e.getSource(); if (button == topLeft) { notifySelectedAnchor(TOP_LEFT); + } else if (button == topCenter) { + notifySelectedAnchor(TOP_CENTER); } else if (button == topRight) { notifySelectedAnchor(TOP_RIGHT); + } else if (button == leftCenter) { + notifySelectedAnchor(LEFT_CENTER); } else if (button == center) { notifySelectedAnchor(CENTER); + } else if (button == rightCenter) { + notifySelectedAnchor(RIGHT_CENTER); } else if (button == bottomLeft) { notifySelectedAnchor(BOTTOM_LEFT); + } else if (button == bottomCenter) { + notifySelectedAnchor(BOTTOM_CENTER); } else if (button == bottomRight) { notifySelectedAnchor(BOTTOM_RIGHT); } @@ -91,32 +133,48 @@ private void notifySelectedAnchor(Anchor anchor) { @Override public void setEnabled(boolean enabled) { topLeft.setEnabled(enabled); + topCenter.setEnabled(enabled); topRight.setEnabled(enabled); + leftCenter.setEnabled(enabled); center.setEnabled(enabled); + rightCenter.setEnabled(enabled); bottomLeft.setEnabled(enabled); + bottomCenter.setEnabled(enabled); bottomRight.setEnabled(enabled); } @Override public void setVisible(boolean visible) { topLeft.setVisible(visible); + topCenter.setVisible(visible); topRight.setVisible(visible); + leftCenter.setVisible(visible); center.setVisible(visible); + rightCenter.setVisible(visible); bottomLeft.setVisible(visible); + bottomCenter.setVisible(visible); bottomRight.setVisible(visible); } public void setAnchor(Anchor anchor) { if (anchor == TOP_LEFT) { topLeft.setSelected(true); + } else if (anchor == TOP_CENTER) { + topCenter.setSelected(true); } else if (anchor == TOP_RIGHT) { topRight.setSelected(true); + } else if (anchor == LEFT_CENTER) { + leftCenter.setSelected(true); } else if (anchor == CENTER) { center.setSelected(true); + } else if (anchor == RIGHT_CENTER) { + rightCenter.setSelected(true); } else if (anchor == BOTTOM_LEFT) { bottomLeft.setSelected(true); } else if (anchor == BOTTOM_RIGHT) { bottomRight.setSelected(true); + } else if (anchor == BOTTOM_CENTER) { + bottomCenter.setSelected(true); } } } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcher.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcher.java index a03f72347f..881c770726 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcher.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcher.java @@ -9,7 +9,6 @@ import com.willwinder.ugs.nbp.designer.actions.UndoActionList; import com.willwinder.ugs.nbp.designer.actions.UndoableAction; import com.willwinder.ugs.nbp.designer.entities.EntitySetting; -import com.willwinder.ugs.nbp.designer.entities.controls.Location; import com.willwinder.ugs.nbp.designer.entities.cuttable.Cuttable; import com.willwinder.ugs.nbp.designer.entities.cuttable.Group; import com.willwinder.ugs.nbp.designer.entities.cuttable.Text; @@ -92,12 +91,12 @@ private List handleSizeChange(EntitySetting entitySetting, Doubl double width = value; double scale = model.getLockRatio() ? currentWidth / width : 1; double height = currentHeight / scale; - actionList.add(new ResizeAction(selection.getChildren(), Location.TOP_RIGHT, selection.getSize(), new Size(width, height))); + actionList.add(new ResizeAction(selection.getChildren(), model.getAnchor(), selection.getSize(), new Size(width, height))); } else if (entitySetting == EntitySetting.HEIGHT) { double height = value; double scale = model.getLockRatio() ? currentHeight / height : 1; double width = currentWidth / scale; - actionList.add(new ResizeAction(selection.getChildren(), Location.TOP_RIGHT, selection.getSize(), new Size(width, height))); + actionList.add(new ResizeAction(selection.getChildren(), model.getAnchor(), selection.getSize(), new Size(width, height))); } return actionList; diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Size.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Size.java index bd8b8b0e32..824fcd2051 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Size.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Size.java @@ -18,6 +18,8 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.designer.model; +import org.apache.commons.lang3.builder.ToStringBuilder; + import java.io.Serializable; import java.util.Objects; @@ -25,8 +27,8 @@ This file is part of Universal Gcode Sender (UGS). * @author Joacim Breiler */ public class Size implements Serializable { - private double width; - private double height; + private final double width; + private final double height; public Size(double width, double height) { this.width = width; @@ -61,4 +63,9 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(width, height); } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/actions/ResizeActionTest.java b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/actions/ResizeActionTest.java new file mode 100644 index 0000000000..cecb6c6ab9 --- /dev/null +++ b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/actions/ResizeActionTest.java @@ -0,0 +1,122 @@ +package com.willwinder.ugs.nbp.designer.actions; + +import com.willwinder.ugs.nbp.designer.entities.Anchor; +import com.willwinder.ugs.nbp.designer.entities.Entity; +import com.willwinder.ugs.nbp.designer.entities.cuttable.Rectangle; +import com.willwinder.ugs.nbp.designer.model.Size; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.awt.geom.Point2D; +import java.util.List; + +public class ResizeActionTest { + + @Test + public void resizeWithTopLeftAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.TOP_LEFT, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(10, 0), entity.getPosition()); + } + + @Test + public void resizeWithBottomLeftAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.BOTTOM_LEFT, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(10, 10), entity.getPosition()); + } + + @Test + public void resizeWithBottomRightAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.BOTTOM_RIGHT, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(0, 10), entity.getPosition()); + } + + @Test + public void resizeWithTopRightAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.TOP_RIGHT, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(0, 0), entity.getPosition()); + } + + @Test + public void resizeWithTopCenterAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.TOP_CENTER, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(5, 0), entity.getPosition()); + } + + @Test + public void resizeWithBottomCenterAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.BOTTOM_CENTER, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(5, 10), entity.getPosition()); + } + + @Test + public void resizeWithLeftCenterAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.LEFT_CENTER, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(10, 5), entity.getPosition()); + } + + @Test + public void resizeWithRightCenterAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.RIGHT_CENTER, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(0, 5), entity.getPosition()); + } + + @Test + public void resizeWithCenterAnchor() { + Entity entity = new Rectangle(10, 10); + entity.setSize(new Size(10, 10)); + + ResizeAction resizeAction = new ResizeAction(List.of(entity), Anchor.CENTER, new Size(10, 10), new Size(20, 20)); + resizeAction.redo(); + + assertEquals(new Size(20, 20), entity.getSize()); + assertEquals(new Point2D.Double(5, 5), entity.getPosition()); + } +} \ No newline at end of file diff --git a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcherTest.java b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcherTest.java index 2b73e58a38..06c3b3e50f 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcherTest.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/gui/selectionsettings/FieldActionDispatcherTest.java @@ -22,6 +22,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.actions.UndoActionList; import com.willwinder.ugs.nbp.designer.actions.UndoManager; import com.willwinder.ugs.nbp.designer.actions.UndoableAction; +import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.EntitySetting; import com.willwinder.ugs.nbp.designer.entities.cuttable.Group; @@ -66,6 +67,7 @@ public void onFieldUpdateSettingWidthShouldAddAndUndoableAction() { Entity entity = new Rectangle(0, 0); mockSelectionManager(entity); when(model.get(EntitySetting.WIDTH)).thenReturn(0); + when(model.getAnchor()).thenReturn(Anchor.CENTER); ArgumentCaptor undoableActionArgumentCaptor = ArgumentCaptor.forClass(UndoableAction.class); doNothing().when(undoManager).addAction(undoableActionArgumentCaptor.capture());