Skip to content

Commit d889f02

Browse files
authored
Zoom at mouse position and adjust scrollbars (#3007)
1 parent abd5b92 commit d889f02

1 file changed

Lines changed: 40 additions & 13 deletions

File tree

ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/DrawingScrollContainer.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ This file is part of Universal Gcode Sender (UGS).
3131
import java.awt.event.KeyEvent;
3232
import java.awt.event.MouseWheelEvent;
3333
import java.awt.event.MouseWheelListener;
34+
import java.awt.geom.AffineTransform;
35+
import java.awt.geom.Point2D;
3436
import java.awt.geom.Rectangle2D;
3537

3638
/**
@@ -135,26 +137,51 @@ private void updateDrawingPositionFromScrollBars() {
135137
@Override
136138
public void mouseWheelMoved(MouseWheelEvent e) {
137139
BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class);
140+
Drawing drawing = controller.getDrawing();
141+
142+
// Mouse point in Drawing component coordinates
143+
Point2D mouseScreen = new Point2D.Double(e.getPoint().getX(), e.getPoint().getY());
144+
145+
// World point currently under the mouse
146+
Point2D mouseWorld;
147+
try {
148+
AffineTransform inv = drawing.getTransform().createInverse();
149+
mouseWorld = inv.transform(mouseScreen, null);
150+
} catch (Exception ex) {
151+
// If transform is temporarily non-invertible, fall back to old behavior (no anchor).
152+
double scaleFactor = (e.getPreciseWheelRotation() * drawing.getScale() * 0.1)
153+
* (backend.getSettings().isInvertMouseZoom() ? -1d : 1d);
154+
drawing.setScale(drawing.getScale() + scaleFactor);
155+
updateScrollBarsSizes();
156+
return;
157+
}
158+
159+
double scaleFactor = (e.getPreciseWheelRotation() * drawing.getScale() * 0.1)
160+
* (backend.getSettings().isInvertMouseZoom() ? -1d : 1d);
161+
162+
double newScale = Math.max(Math.abs(drawing.getScale() + scaleFactor), Drawing.MIN_SCALE);
163+
drawing.setScale(newScale);
164+
165+
// Scrollbar ranges depend on scale, so update them after scaling
166+
updateScrollBarsSizes();
138167

139-
double horizontalPercent = getScrollbarPercent(horizontalScrollBar);
140-
double verticalPercent = getScrollbarPercent(verticalScrollBar);
168+
// Get that same world point ends up after scaling
169+
Point2D mouseScreenAfter = drawing.getTransform().transform(mouseWorld, null);
141170

142-
// Apply the scaling
143-
double scaleFactor = (e.getPreciseWheelRotation() * controller.getDrawing().getScale() * 0.1) * (backend.getSettings().isInvertMouseZoom() ? -1d : 1d);
144-
controller.getDrawing().setScale(controller.getDrawing().getScale() + scaleFactor);
171+
// Adjust position so the world point stays under the mouse delta in screen coords
172+
double dx = mouseScreen.getX() - mouseScreenAfter.getX();
173+
double dy = mouseScreen.getY() - mouseScreenAfter.getY();
145174

146-
updateScrollBarsSizes();
147-
setScrollbarPercent(horizontalScrollBar, horizontalPercent);
148-
setScrollbarPercent(verticalScrollBar, verticalPercent);
175+
Point2D.Double posPx = drawing.getPosition();
176+
double newPosPxX = posPx.getX() - dx;
177+
double newPosPxY = posPx.getY() + dy;
178+
179+
horizontalScrollBar.setValue((int) Math.round(newPosPxX));
180+
verticalScrollBar.setValue((int) Math.round(-newPosPxY));
149181
}
150182

151183
private void setScrollbarPercent(JScrollBar scrollBar, double percent) {
152184
double width = ((double) scrollBar.getMaximum() - (double) scrollBar.getMinimum());
153185
scrollBar.setValue((int) Math.round(width * percent));
154186
}
155-
156-
private double getScrollbarPercent(JScrollBar scrollBar) {
157-
double width = ((double) scrollBar.getMaximum() - (double) scrollBar.getMinimum());
158-
return scrollBar.getValue() == 0 ? 0 : (scrollBar.getValue() / width);
159-
}
160187
}

0 commit comments

Comments
 (0)