@@ -31,6 +31,8 @@ This file is part of Universal Gcode Sender (UGS).
3131import java .awt .event .KeyEvent ;
3232import java .awt .event .MouseWheelEvent ;
3333import java .awt .event .MouseWheelListener ;
34+ import java .awt .geom .AffineTransform ;
35+ import java .awt .geom .Point2D ;
3436import 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