From 9bba960f5283d5e092988a2c0510be9767ce0050 Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Wed, 12 Aug 2026 18:09:57 +0200 Subject: [PATCH] fix: Adjust window sizes and snapping logic for better alignment and docking Signed-off-by: Hans Kokx --- lib/main.dart | 4 +++ lib/src/docking/dock_controller.dart | 31 +++++++++++++++++++----- lib/src/docking/dock_logic.dart | 14 ++++++++++- lib/src/main_window/playlist_window.dart | 8 +++--- lib/src/windows/sub_window_app.dart | 4 +-- test/dock_controller_test.dart | 2 +- 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index be677e9..95c3a6c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -490,6 +490,10 @@ class _WinampRootState extends State { final saved = _savedSubPositions[type]; if (saved != null) { rect = Rect.fromLTWH(saved.$1, saved.$2, size.width, size.height); + // If the saved position is near the main window's bottom edge within + // the snap tolerance, snap it exactly so the window restores docked + // rather than merely appearing visually aligned but detached. + rect = DockLogic.snapWindowBelow(rect, mainRect, snapLen: _dock.snapLen); } else if (_pendingSubBounds.containsKey(window)) { rect = _pendingSubBounds[window]!; } diff --git a/lib/src/docking/dock_controller.dart b/lib/src/docking/dock_controller.dart index a571cb9..053b5ae 100644 --- a/lib/src/docking/dock_controller.dart +++ b/lib/src/docking/dock_controller.dart @@ -10,13 +10,13 @@ import "dock_logic.dart"; const Map _mainSizes = { DockWindow.main: Size(275, 116), DockWindow.eq: Size(275, 116), - DockWindow.pl: Size(280, 290), + DockWindow.pl: Size(275, 290), }; const Map _shadeSizes = { DockWindow.main: Size(275, 14), DockWindow.eq: Size(275, 14), - DockWindow.pl: Size(280, 14), + DockWindow.pl: Size(275, 14), }; /// How a moved window rect is applied natively. @@ -104,7 +104,13 @@ class DockController { _attached = DockLogic.dockedBelow( rects: _rects, dragged: DockWindow.main, - snapLen: snapLen, + // When beginning a main-window drag we must snapshot only windows + // that are truly attached (exactly sitting on the main window's + // bottom). Using the configured snapLen here would pick up nearby + // windows and cause the main window to "initiate" docking while + // dragging, which is incorrect. Use zero tolerance to require exact + // edge equality. + snapLen: 0.0, ); debugPrint( "dock beginMainDrag ptr=${pointer.dx.toStringAsFixed(1)}," @@ -127,9 +133,22 @@ class DockController { Rect target, { Set? attached, }) { - attached = - attached ?? - DockLogic.dockedBelow(rects: _rects, dragged: driven, snapLen: snapLen); + // Prefer an explicit attached set when provided. During an active main + // drag prefer the snapshot taken at `beginMainDrag` (`_attached`) so we + // never pick up nearby windows via snap tolerance and accidentally make + // the main window initiate docking. Otherwise compute the attached set + // from current rects using the configured `snapLen`. + if (attached == null) { + if (_grab != null && _attached != null && driven == DockWindow.main) { + attached = _attached!; + } else { + attached = DockLogic.dockedBelow( + rects: _rects, + dragged: driven, + snapLen: snapLen, + ); + } + } final prevDriven = _rects[driven]; if (prevDriven == null) { _rects[driven] = target; diff --git a/lib/src/docking/dock_logic.dart b/lib/src/docking/dock_logic.dart index 998e891..ca69f67 100644 --- a/lib/src/docking/dock_logic.dart +++ b/lib/src/docking/dock_logic.dart @@ -127,7 +127,19 @@ abstract final class DockLogic { }) { if (!_overlaps1(dest.left, dest.right, src.left, src.right)) return src; if (!_closeTo(src.top, dest.bottom, snapLen)) return src; - return Rect.fromLTWH(src.left, dest.bottom, src.width, src.height); + // Snap vertically below `dest`. Additionally, if the src's left edge is + // near either of `dest`'s vertical edges (left or right minus src.width), + // snap horizontally to the nearest vertical edge so the restored docked + // position is aligned both vertically and horizontally. + var left = src.left; + final leftEdge = dest.left; + final rightEdge = dest.right - src.width; + final leftDist = (src.left - leftEdge).abs(); + final rightDist = (src.left - rightEdge).abs(); + if (leftDist <= snapLen || rightDist <= snapLen) { + left = leftDist <= rightDist ? leftEdge : rightEdge; + } + return Rect.fromLTWH(left, dest.bottom, src.width, src.height); } /// Port of `MoveRect` (DOCK.cpp:81). diff --git a/lib/src/main_window/playlist_window.dart b/lib/src/main_window/playlist_window.dart index 133b736..928c43d 100644 --- a/lib/src/main_window/playlist_window.dart +++ b/lib/src/main_window/playlist_window.dart @@ -9,13 +9,13 @@ import "../player/player_state.dart"; import "../skin/skin_cursors.dart"; import "../windows/sub_window_channel.dart"; -const Size _plMainSize = Size(280, 290); -const Size _plShadeSize = Size(280, 14); +const Size _plMainSize = Size(275, 290); +const Size _plShadeSize = Size(275, 14); -const double _plWidth = 280; +const double _plWidth = 275; const double _plShadeHeight = 14; const double _listLeft = 12; -const double _listRight = 260; +const double _listRight = 255; /// Visible rows for a 290-tall window: `(290 - 58) / pe_fontheight(13)`. const int _numSongs = 17; diff --git a/lib/src/windows/sub_window_app.dart b/lib/src/windows/sub_window_app.dart index 59c49cf..cdaa5c3 100644 --- a/lib/src/windows/sub_window_app.dart +++ b/lib/src/windows/sub_window_app.dart @@ -17,8 +17,8 @@ import "window_args.dart"; const Size _eqMainSize = Size(275, 116); const Size _eqShadeSize = Size(275, 14); -const Size _plMainSize = Size(280, 290); -const Size _plShadeSize = Size(280, 14); +const Size _plMainSize = Size(275, 290); +const Size _plShadeSize = Size(275, 14); /// The root of an Equalizer or Playlist sub-window. /// diff --git a/test/dock_controller_test.dart b/test/dock_controller_test.dart index 33f1175..a010ee0 100644 --- a/test/dock_controller_test.dart +++ b/test/dock_controller_test.dart @@ -278,7 +278,7 @@ void main() { ); expect( DockController.scaledSize(DockWindow.pl, false, 1.2), - const Size(336, 348), + const Size(330, 348), ); }); }