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
* first, or none when the point is not in a mirror.
* Finds the components that the underside mirror of a board shows at the specified point and that
* 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 project
@@ -789,7 +790,7 @@ public class DrawingManager {
/**
* 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 project
@@ -804,7 +805,7 @@ public class DrawingManager {
return components;
}
for (IDIYComponent<?> component : findComponentsAt(mirrorTx.transform(point, null), project)) {
if (UndersideMirror.isMirrored(board, component)) {
if (UndersideMirror.isEditableThrough(board, component)) {
components.add(component);
}
}
@@ -966,7 +966,7 @@ public class Presenter implements IPlugInPort {
for (int i = currentProject.getComponents().size() - 1; i >= 0; i--) {
IDIYComponent<?> component = currentProject.getComponents().get(i);
if (mirrorBoard != null && selectedComponents.contains(component)
&& !UndersideMirror.isMirrored(mirrorBoard, component)) {
&& !UndersideMirror.isEditableThrough(mirrorBoard, component)) {
continue;
}
for (int pointIndex = 0; pointIndex < component.getControlPointCount(); pointIndex++) {
@@ -160,6 +160,15 @@ public class UndersideMirror {
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
* over the others where mirrors overlap
@@ -391,6 +391,46 @@ public class PresenterTests extends TestBase {
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
private BlankBoard mirroredBoard() {
BlankBoard board = new BlankBoard();
+4 -1
View File
@@ -121,7 +121,10 @@ order.
- **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
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
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