Files
dartamp/test/dock_controller_test.dart
T

285 lines
13 KiB
Dart

import "dart:ui";
import "package:dartamp/src/docking/dock_controller.dart";
import "package:dartamp/src/docking/dock_logic.dart";
import "package:flutter_test/flutter_test.dart";
const screen = Rect.fromLTWH(0, 0, 1440, 900);
void main() {
late List<(DockWindow, Rect)> moved;
late Map<DockWindow, Rect>? persisted;
late DockController dock;
setUp(() {
moved = [];
persisted = null;
dock = DockController(
moveWindow: (window, rect) => moved.add((window, rect)),
persistRects: (rects) => persisted = rects,
)..screenRect = screen;
});
test("setRect and removeWindow maintain the rect map", () {
dock.setRect(DockWindow.eq, const Rect.fromLTWH(275, 0, 275, 116));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(275, 0));
expect(dock.rects.length, 1);
dock.removeWindow(DockWindow.eq);
expect(dock.rectOf(DockWindow.eq), isNull);
});
test("a main-window drag moves the group docked below by the same delta", () {
// Vertical column: main, eq below it, pl below eq.
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 232, 280, 290));
dock.beginMainDrag(const Offset(100, 50));
dock.mainDragTo(const Offset(300, 180));
dock.endMainDrag();
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(200, 130));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(200, 246));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(200, 362));
expect(persisted, isNotNull);
});
test(
"a main-window drag moves only the column below, not windows beside it",
() {
// eq docked to main's right; pl docked below main.
dock.setRect(
DockWindow.main,
const Rect.fromLTWH(100, 100, 275, 116),
);
dock.setRect(
DockWindow.eq,
const Rect.fromLTWH(375, 100, 275, 116),
);
dock.setRect(
DockWindow.pl,
const Rect.fromLTWH(100, 216, 280, 290),
);
dock.beginMainDrag(const Offset(200, 140));
dock.mainDragTo(const Offset(400, 260));
dock.endMainDrag();
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(300, 220));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(300, 336));
// eq is beside main, not docked below it: it does not follow.
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(375, 100));
},
);
test("a two-hop vertical chain (main -> eq -> pl) all follow the drag", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
// pl docks below eq (still overlapping main's x-band) but offset 30px.
dock.setRect(DockWindow.pl, const Rect.fromLTWH(30, 232, 280, 290));
dock.beginMainDrag(const Offset(100, 50));
dock.mainDragTo(const Offset(300, 180));
// mainDelta = (200, 130); the transitive column all shifts.
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(200, 130));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(200, 246));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(230, 362));
});
test("dragging a sub-window moves only that window (it undocks)", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 232, 280, 290));
// The sub reports it was dragged away from its dock.
dock.subBounds(DockWindow.eq, const Rect.fromLTWH(0, 146, 275, 116));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 146));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(0, 232));
});
test("subBounds leaves unattached windows untouched", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(800, 800, 280, 290));
dock.subBounds(DockWindow.eq, const Rect.fromLTWH(0, 146, 275, 116));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 146));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(800, 800));
});
test("movement tracks the cumulative pointer delta", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(500, 300, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(775, 300, 275, 116));
dock.beginMainDrag(const Offset(600, 340));
dock.mainDragTo(const Offset(700, 420));
dock.mainDragTo(const Offset(800, 500));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(700, 460));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(775, 300));
});
test("dragging to a screen corner snaps the main window", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(10, 10, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(285, 10, 275, 116));
dock.beginMainDrag(const Offset(100, 100));
dock.mainDragTo(const Offset(95, 95));
expect(dock.rectOf(DockWindow.main)!.topLeft, Offset.zero);
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(285, 10));
});
test("an unattached window stays put while the group moves", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(500, 300, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(800, 500, 275, 116));
dock.beginMainDrag(const Offset(600, 340));
dock.mainDragTo(const Offset(650, 400));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(550, 360));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(800, 500));
});
test(
"a main-window drag does not pull in a window it overlaps",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
// eq overlaps main's bottom edge; that is not a dock.
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 100, 275, 116));
dock.beginMainDrag(const Offset(100, 50));
dock.mainDragTo(const Offset(200, 150));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(100, 100));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 100));
},
);
test(
"a sub-window resizing re-pins windows docked below, not beside",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(275, 0, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 116, 280, 290));
dock.repinResized(DockWindow.main, const Rect.fromLTWH(0, 0, 330, 139.2));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(275, 0));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(0, 139.2));
},
);
test("subBounds re-pins the chain docked below the resized window", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 116, 280, 290));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 406, 275, 116));
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(0, 116, 280, 14));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 130));
});
test("repinResized keeps everything pinned when the edge does not move", () {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(275, 0, 275, 116));
dock.repinResized(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 14));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(275, 0));
});
test(
"dragging a sub-window far from the cluster moves only it",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 232, 280, 290));
// eq is dragged a long way away from main; only eq moves.
dock.subBounds(DockWindow.eq, const Rect.fromLTWH(600, 400, 275, 116));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(600, 400));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(0, 232));
},
);
test(
"dragging a non-docked window over the cluster does not stick to it",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(275, 0, 275, 116));
// pl starts far away (not docked to anything).
dock.setRect(DockWindow.pl, const Rect.fromLTWH(900, 900, 280, 290));
// Drag pl so it overlaps main's x-band (not an edge dock).
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(100, 50, 280, 290));
// main + eq must stay put; only pl moves to where it was dragged.
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(275, 0));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(100, 50));
},
);
test(
"a non-docked window reports a position but leaves others untouched",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(275, 0, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(900, 900, 280, 290));
// pl is just reporting a moved position, not on a dock.
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(800, 800, 280, 290));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(275, 0));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(800, 800));
},
);
test(
"dragging the middle of a 3-window column undocks it and moves only it",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 116, 280, 290));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 406, 275, 116));
// pl moves +50, +40; main + eq stay put (pl is dragged alone).
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(50, 156, 280, 290));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 406));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(50, 156));
// Frame 2: further +30, +20; still only pl moves.
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(80, 176, 280, 290));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 406));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(80, 176));
},
);
test(
"dragging the bottom of a 3-window column undocks it and moves only it",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 232, 280, 290));
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(30, 262, 280, 290));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 116));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(30, 262));
},
);
test(
"a main-window drag still moves the group after a sub drag ends",
() {
dock.setRect(DockWindow.main, const Rect.fromLTWH(0, 0, 275, 116));
dock.setRect(DockWindow.eq, const Rect.fromLTWH(0, 116, 275, 116));
dock.setRect(DockWindow.pl, const Rect.fromLTWH(0, 232, 280, 290));
// The sub drag moves pl away; main + eq stay put (undock).
dock.subBounds(DockWindow.pl, const Rect.fromLTWH(0, 400, 280, 290));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(0, 0));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(0, 116));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(0, 400));
// Main drag afterward: only the main + eq column follows.
dock.beginMainDrag(const Offset(100, 50));
dock.mainDragTo(const Offset(300, 180));
expect(dock.rectOf(DockWindow.main)!.topLeft, const Offset(200, 130));
expect(dock.rectOf(DockWindow.eq)!.topLeft, const Offset(200, 246));
expect(dock.rectOf(DockWindow.pl)!.topLeft, const Offset(0, 400));
dock.endMainDrag();
},
);
test("scaledSize accounts for shade state and UI scale", () {
expect(
DockController.scaledSize(DockWindow.main, false, 1.0),
const Size(275, 116),
);
expect(
DockController.scaledSize(DockWindow.eq, true, 1.0),
const Size(275, 14),
);
expect(
DockController.scaledSize(DockWindow.pl, false, 1.2),
const Size(330, 348),
);
});
}