A board can no longer be selected, dragged or stretched through its own Underside Display, where dragging it moved the mirror under the mouse and the board went the wrong way

This commit is contained in:
Bane Stojkovic
2026-11-12 14:34:05 +01:00
parent 6e3f72dfb6
commit 86b54509bf
5 changed files with 59 additions and 6 deletions
@@ -768,8 +768,9 @@ public class DrawingManager {
} }
/** /**
* Finds the components that the underside mirror of a board shows at the specified point, top * Finds the components that the underside mirror of a board shows at the specified point and that
* first, or none when the point is not in a mirror. * can be edited through it, top first, or none when the point is not in a mirror. The board
* itself is left out (see {@link UndersideMirror#isEditableThrough}).
* *
* @param point * @param point
* @param project * @param project
@@ -789,7 +790,7 @@ public class DrawingManager {
/** /**
* Finds the components that the underside mirror of the specified board shows at the specified * Finds the components that the underside mirror of the specified board shows at the specified
* point, top first, or none when the point is not in that mirror. * point, other than the board itself, top first, or none when the point is not in that mirror.
* *
* @param point * @param point
* @param project * @param project
@@ -804,7 +805,7 @@ public class DrawingManager {
return components; return components;
} }
for (IDIYComponent<?> component : findComponentsAt(mirrorTx.transform(point, null), project)) { for (IDIYComponent<?> component : findComponentsAt(mirrorTx.transform(point, null), project)) {
if (UndersideMirror.isMirrored(board, component)) { if (UndersideMirror.isEditableThrough(board, component)) {
components.add(component); components.add(component);
} }
} }
@@ -966,7 +966,7 @@ public class Presenter implements IPlugInPort {
for (int i = currentProject.getComponents().size() - 1; i >= 0; i--) { for (int i = currentProject.getComponents().size() - 1; i >= 0; i--) {
IDIYComponent<?> component = currentProject.getComponents().get(i); IDIYComponent<?> component = currentProject.getComponents().get(i);
if (mirrorBoard != null && selectedComponents.contains(component) if (mirrorBoard != null && selectedComponents.contains(component)
&& !UndersideMirror.isMirrored(mirrorBoard, component)) { && !UndersideMirror.isEditableThrough(mirrorBoard, component)) {
continue; continue;
} }
for (int pointIndex = 0; pointIndex < component.getControlPointCount(); pointIndex++) { for (int pointIndex = 0; pointIndex < component.getControlPointCount(); pointIndex++) {
@@ -160,6 +160,15 @@ public class UndersideMirror {
return false; return false;
} }
/**
* @return true when the component can be selected, dragged or stretched through the board's
* mirror: any component the mirror shows except the board itself. The mirror is placed
* relative to the board, so moving the board through it would move the mirror as well.
*/
public static boolean isEditableThrough(IBoard board, IDIYComponent<?> component) {
return component != board && isMirrored(board, component);
}
/** /**
* @return the boards whose mirror contains the point, the topmost first, which is the one drawn * @return the boards whose mirror contains the point, the topmost first, which is the one drawn
* over the others where mirrors overlap * over the others where mirrors overlap
@@ -391,6 +391,46 @@ public class PresenterTests extends TestBase {
Assert.assertTrue(board.getBoardRectangle().contains(resistor.getControlPoint(0))); Assert.assertTrue(board.getBoardRectangle().contains(resistor.getControlPoint(0)));
} }
@Test
public void testBoardIsNotSelectableThroughItsUndersideMirror() {
BlankBoard board = mirroredBoard();
drawProject();
Rectangle2D region = UndersideMirror.getMirrorRegion(board);
Point inMirror = toScreen(new Point2D.Double(region.getCenterX(), region.getCenterY()));
Assert.assertTrue(presenter.findComponentsAt(inMirror, false).isEmpty());
presenter.mouseClicked(inMirror, MouseEvent.BUTTON1, false, false, false, 1);
Assert.assertTrue(presenter.getSelectedComponents().isEmpty());
}
@Test
public void testBoardIsNotDraggedThroughItsUndersideMirror() {
BlankBoard board = mirroredBoard();
drawProject();
Rectangle2D region = UndersideMirror.getMirrorRegion(board);
Rectangle2D before = board.getBoardRectangle();
// selected on the board itself, then dragged by its picture in the mirror
Point onBoard = toScreen(new Point2D.Double(before.getCenterX(), before.getCenterY()));
presenter.mouseClicked(onBoard, MouseEvent.BUTTON1, false, false, false, 1);
Assert.assertTrue(presenter.getSelectedComponents().contains(board));
Point inMirror = toScreen(new Point2D.Double(region.getCenterX(), region.getCenterY()));
presenter.mouseMoved(inMirror, false, false, false);
presenter.dragStarted(inMirror, java.awt.dnd.DnDConstants.ACTION_MOVE, false, false);
presenter.dragOver(new Point(inMirror.x + 100, inMirror.y + 100));
presenter.dragEnded(new Point(inMirror.x + 100, inMirror.y + 100));
Assert.assertEquals(before, board.getBoardRectangle());
}
// the hit tests read the areas recorded while drawing
private void drawProject() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
presenter.draw(g2d, EnumSet.of(DrawOption.ZOOM), null, null, null, null);
g2d.dispose();
}
// a board with its underside mirror below it, with nothing on it yet // a board with its underside mirror below it, with nothing on it yet
private BlankBoard mirroredBoard() { private BlankBoard mirroredBoard() {
BlankBoard board = new BlankBoard(); BlankBoard board = new BlankBoard();
+4 -1
View File
@@ -121,7 +121,10 @@ order.
- **Shared mirror geometry (done).** `org.diylc.presenter.UndersideMirror` holds the reflection - **Shared mirror geometry (done).** `org.diylc.presenter.UndersideMirror` holds the reflection
for a board, the region its mirror occupies (the board rectangle reflected about the pivot), and for a board, the region its mirror occupies (the board rectangle reflected about the pivot), and
which components a mirror shows: the board and every component with a control point on it. which components a mirror shows: the board and every component with a control point on it.
`DrawingManager` draws the mirror with it, so drawing and hit-testing cannot drift apart. `DrawingManager` draws the mirror with it, so drawing and hit-testing cannot drift apart. The
board itself cannot be selected, dragged or stretched through its own mirror
(`UndersideMirror.isEditableThrough`): the mirror is placed relative to the board, so moving the
board through it moved the mirror under the mouse and the board went the wrong way.
- **Stage 1: selecting in the mirror (done).** `DrawingManager.findMirroredComponentsAt` reflects a - **Stage 1: selecting in the mirror (done).** `DrawingManager.findMirroredComponentsAt` reflects a
point that falls in a mirror region and tests it again, limited to the components that board point that falls in a mirror region and tests it again, limited to the components that board
mirrors. `Presenter.findComponentsAtScaled` falls back to it when nothing selectable is hit in mirrors. `Presenter.findComponentsAtScaled` falls back to it when nothing selectable is hit in