fix: Adjust window sizes and snapping logic for better alignment and docking

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-08-12 18:09:57 +02:00
parent 9a8a8a02ad
commit 9bba960f52
6 changed files with 49 additions and 14 deletions
+4
View File
@@ -490,6 +490,10 @@ class _WinampRootState extends State<WinampRoot> {
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]!;
}
+25 -6
View File
@@ -10,13 +10,13 @@ import "dock_logic.dart";
const Map<DockWindow, Size> _mainSizes = {
DockWindow.main: Size(275, 116),
DockWindow.eq: Size(275, 116),
DockWindow.pl: Size(280, 290),
DockWindow.pl: Size(275, 290),
};
const Map<DockWindow, Size> _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<DockWindow>? 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;
+13 -1
View File
@@ -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).
+4 -4
View File
@@ -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;
+2 -2
View File
@@ -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.
///
+1 -1
View File
@@ -278,7 +278,7 @@ void main() {
);
expect(
DockController.scaledSize(DockWindow.pl, false, 1.2),
const Size(336, 348),
const Size(330, 348),
);
});
}