Add mouse controller for resizing rect elements

To avoid having to guess which size is needed.
When the mouse hovers near the border of a rectangle,
the cursor changes for a resizing arrow and dragging
it allows resizing the rectangle visually.
This commit is contained in:
maltaisn 2021-01-16 21:57:16 -05:00
parent 822a6f02a4
commit d73cd785be
No known key found for this signature in database
GPG Key ID: 82A9C1DCBB9C2513
2 changed files with 158 additions and 3 deletions

View File

@ -13,6 +13,7 @@ import de.neemann.digital.core.io.InValue;
import de.neemann.digital.core.io.Out;
import de.neemann.digital.core.switching.Switch;
import de.neemann.digital.draw.elements.*;
import de.neemann.digital.draw.graphics.Polygon;
import de.neemann.digital.draw.graphics.Vector;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.library.*;
@ -23,6 +24,7 @@ import de.neemann.digital.draw.shapes.InputShape;
import de.neemann.digital.draw.shapes.ShapeFactory;
import de.neemann.digital.gui.Main;
import de.neemann.digital.gui.Settings;
import de.neemann.digital.gui.components.data.DummyElement;
import de.neemann.digital.gui.components.modification.*;
import de.neemann.digital.lang.Lang;
import de.neemann.digital.testing.TestCaseElement;
@ -108,6 +110,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
private final MouseControllerMoveSelected mouseMoveSelected;
private final MouseController mouseRun;
private final MouseControllerInsertCopied mouseInsertList;
private final MouseControllerResizeRect mouseResizeRect;
private final Cursor normalCursor;
private final Cursor moveCursor;
private final ToolTipAction copyAction;
private final ToolTipAction cutAction;
@ -235,7 +239,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
}
});
Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
moveCursor = new Cursor(Cursor.MOVE_CURSOR);
mouseNormal = new MouseControllerNormal(normalCursor);
mouseInsertElement = new MouseControllerInsertElement(normalCursor);
@ -248,6 +252,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
mouseSelect = new MouseControllerSelect(new Cursor(Cursor.CROSSHAIR_CURSOR));
mouseMoveSelected = new MouseControllerMoveSelected(moveCursor);
mouseRun = new MouseControllerRun(normalCursor);
mouseResizeRect = new MouseControllerResizeRect(normalCursor);
undoManager = new UndoManager<>(new Circuit());
addListener(this);
@ -1657,6 +1662,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
private final class MouseControllerNormal extends MouseController {
private Vector pos;
private MouseEvent downButton;
private VisualElement hoveredElement;
private MouseControllerNormal(Cursor cursor) {
super(cursor);
@ -1666,6 +1672,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
void activate() {
super.activate();
pos = null;
hoveredElement = null;
}
@Override
@ -1705,18 +1712,34 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
pos = getPosVector(e);
}
@Override
void moved(MouseEvent e) {
Vector p = getPosVector(e);
hoveredElement = getCircuit().getElementAt(p, false);
if (!isLocked() && hoveredElement != null &&
hoveredElement.equalsDescription(DummyElement.RECTDESCRIPTION)) {
setCursorForResizingRect(hoveredElement, p);
} else {
setCursor(normalCursor);
}
}
@Override
boolean dragged(MouseEvent e) {
if (mouse.isPrimaryClick(downButton)) {
Vector p = getPosVector(e);
if (pos == null)
pos = p;
mouseSelect.activate(pos, p);
if (!isLocked() && hoveredElement != null &&
hoveredElement.equalsDescription(DummyElement.RECTDESCRIPTION)) {
mouseResizeRect.activate(hoveredElement, pos);
} else {
mouseSelect.activate(pos, p);
}
return true;
}
return !mouse.isSecondaryClick(downButton);
}
}
private final class MouseControllerInsertElement extends MouseController {
@ -2563,6 +2586,137 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
}
}
private final class MouseControllerResizeRect extends MouseController {
private VisualElement element;
private Vector startPos;
private int rectX;
private int rectY;
private int rectWidth;
private int rectHeight;
private boolean changeNorth;
private boolean changeSouth;
private boolean changeWest;
private boolean changeEast;
private MouseControllerResizeRect(Cursor cursor) {
super(cursor);
}
void activate(VisualElement element, Vector pos) {
super.activate();
this.element = element;
this.startPos = raster(pos);
// Get current rectangle attributes.
rectX = element.getPos().x;
rectY = element.getPos().y;
rectWidth = element.getElementAttributes().get(Keys.RECT_WIDTH) * SIZE;
rectHeight = element.getElementAttributes().get(Keys.RECT_HEIGHT) * SIZE;
// Find which directions are being changed.
Vector posInRect = raster(pos.sub(element.getPos()));
changeNorth = posInRect.y <= 0;
changeSouth = posInRect.y == rectHeight;
changeEast = posInRect.x == 0;
changeWest = posInRect.x == rectWidth;
}
@Override
boolean dragged(MouseEvent e) {
ElementAttributes attributes = element.getElementAttributes();
Vector d = raster(getPosVector(e)).sub(startPos);
if (changeNorth) {
rectY = element.getPos().y + d.y;
rectHeight = attributes.get(Keys.RECT_HEIGHT) * SIZE - d.y;
} else if (changeSouth) {
rectHeight = attributes.get(Keys.RECT_HEIGHT) * SIZE + d.y;
}
if (changeEast) {
rectX = element.getPos().x + d.x;
rectWidth = attributes.get(Keys.RECT_WIDTH) * SIZE - d.x;
} else if (changeWest) {
rectWidth = attributes.get(Keys.RECT_WIDTH) * SIZE + d.x;
}
repaint();
return true;
}
@Override
void released(MouseEvent e) {
// Flip rectangle vertically or horizontally if needed.
if (rectWidth < 0) {
rectWidth = -rectWidth;
rectX -= rectWidth;
}
if (rectHeight < 0) {
rectHeight = -rectHeight;
rectY -= rectHeight;
}
// Enforce rectangle min dimensions.
rectWidth = Math.max(rectWidth, Keys.RECT_WIDTH.getMin() * SIZE);
rectHeight = Math.max(rectHeight, Keys.RECT_HEIGHT.getMin() * SIZE);
ElementAttributes newAttributes = new ElementAttributes(element.getElementAttributes())
.set(Keys.RECT_WIDTH, rectWidth / SIZE)
.set(Keys.RECT_HEIGHT, rectHeight / SIZE);
modify(new Modifications.Builder<Circuit>(Lang.get("mod_resizeRect"))
.add(new ModifyAttributes(element, newAttributes))
.add(new ModifyMoveAndRotElement(element, new Vector(rectX, rectY), element.getRotate()))
.build());
mouseNormal.activate();
}
@Override
public void drawTo(Graphic gr) {
gr.drawPolygon(new Polygon(true)
.add(rectX, rectY)
.add(rectX + rectWidth, rectY)
.add(rectX + rectWidth, rectY + rectHeight)
.add(rectX, rectY + rectHeight), Style.HIGHLIGHT);
}
}
/**
* Updates the cursor for when the mouse hovers nears the border of a rectangle.
*
* @param rect The rectangle element.
* @param pos Current mouse position in circuit coordinates.
*/
public void setCursorForResizingRect(VisualElement rect, Vector pos) {
Vector posInRect = raster(pos.sub(rect.getPos()));
int width = rect.getElementAttributes().get(Keys.RECT_WIDTH) * SIZE;
int height = rect.getElementAttributes().get(Keys.RECT_HEIGHT) * SIZE;
int cursor;
if (posInRect.x == width) {
if (posInRect.y <= 0) {
cursor = Cursor.NE_RESIZE_CURSOR;
} else if (posInRect.y == height) {
cursor = Cursor.SE_RESIZE_CURSOR;
} else {
cursor = Cursor.E_RESIZE_CURSOR;
}
} else if (posInRect.x == 0) {
if (posInRect.y <= 0) {
cursor = Cursor.NW_RESIZE_CURSOR;
} else if (posInRect.y == height) {
cursor = Cursor.SW_RESIZE_CURSOR;
} else {
cursor = Cursor.W_RESIZE_CURSOR;
}
} else if (posInRect.y <= 0) {
cursor = Cursor.N_RESIZE_CURSOR;
} else {
cursor = Cursor.S_RESIZE_CURSOR;
}
setCursor(new Cursor(cursor));
}
/**
* Activate a wizard
*

View File

@ -1655,6 +1655,7 @@
<string name="mod_groupEdit">Modified attributes of selected components.</string>
<string name="mod_splitWire">Splits a single wire into two wires.</string>
<string name="mod_modifiedByRunningModel">Changes made by the running simulation.</string>
<string name="mod_resizeRect">Resizes and moves a rectangle.</string>
<string name="lib_Logic">Logic</string>
<string name="lib_arithmetic">Arithmetic</string>