@witchcraft/layout 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -24
- package/dist/module.json +1 -1
- package/dist/runtime/components/FrameDragHandle.d.vue.ts +15 -0
- package/dist/runtime/components/FrameDragHandle.vue +28 -0
- package/dist/runtime/components/FrameDragHandle.vue.d.ts +15 -0
- package/dist/runtime/components/LayoutDecos.d.vue.ts +2 -4
- package/dist/runtime/components/LayoutDecos.vue +10 -29
- package/dist/runtime/components/LayoutDecos.vue.d.ts +2 -4
- package/dist/runtime/components/LayoutEdges.d.vue.ts +3 -3
- package/dist/runtime/components/LayoutEdges.vue +9 -10
- package/dist/runtime/components/LayoutEdges.vue.d.ts +3 -3
- package/dist/runtime/components/LayoutFrame.d.vue.ts +1 -1
- package/dist/runtime/components/LayoutFrame.vue +1 -4
- package/dist/runtime/components/LayoutFrame.vue.d.ts +1 -1
- package/dist/runtime/components/LayoutShapeSquare.d.vue.ts +3 -1
- package/dist/runtime/components/LayoutShapeSquare.vue +3 -5
- package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +3 -1
- package/dist/runtime/components/LayoutWindow.d.vue.ts +26 -12
- package/dist/runtime/components/LayoutWindow.vue +95 -84
- package/dist/runtime/components/LayoutWindow.vue.d.ts +26 -12
- package/dist/runtime/composables/useFrames.d.ts +15 -13
- package/dist/runtime/composables/useFrames.js +59 -39
- package/dist/runtime/demo/App.vue +116 -30
- package/dist/runtime/demo/DemoControls.d.vue.ts +4 -1
- package/dist/runtime/demo/DemoControls.vue +98 -4
- package/dist/runtime/demo/DemoControls.vue.d.ts +4 -1
- package/dist/runtime/drag/CloseAction.d.ts +26 -5
- package/dist/runtime/drag/CloseAction.js +87 -40
- package/dist/runtime/drag/DragActionHandler.d.ts +20 -8
- package/dist/runtime/drag/DragActionHandler.js +47 -12
- package/dist/runtime/drag/FrameDragAction.d.ts +45 -0
- package/dist/runtime/drag/FrameDragAction.js +143 -0
- package/dist/runtime/drag/SplitAction.d.ts +32 -11
- package/dist/runtime/drag/SplitAction.js +82 -24
- package/dist/runtime/drag/createDefaultHandlers.d.ts +9 -0
- package/dist/runtime/drag/createDefaultHandlers.js +10 -0
- package/dist/runtime/drag/defaultDragActions.d.ts +9 -0
- package/dist/runtime/drag/defaultDragActions.js +10 -0
- package/dist/runtime/drag/types.d.ts +82 -13
- package/dist/runtime/drag/types.js +1 -0
- package/dist/runtime/helpers/createZoneSideClipPath.d.ts +12 -0
- package/dist/runtime/helpers/createZoneSideClipPath.js +17 -0
- package/dist/runtime/helpers/doEdgesOverlap.d.ts +3 -1
- package/dist/runtime/helpers/doEdgesOverlap.js +5 -5
- package/dist/runtime/helpers/getDockBoundaries.d.ts +19 -0
- package/dist/runtime/helpers/getDockBoundaries.js +14 -0
- package/dist/runtime/helpers/getEdgeLength.d.ts +2 -0
- package/dist/runtime/helpers/getEdgeLength.js +5 -0
- package/dist/runtime/helpers/getIntersections.js +2 -2
- package/dist/runtime/helpers/getIntersectionsCss.js +2 -2
- package/dist/runtime/helpers/getMoveEdgeInfo.js +2 -2
- package/dist/runtime/helpers/getResizeLimit.js +2 -2
- package/dist/runtime/helpers/getShapeSquareCss.js +2 -2
- package/dist/runtime/helpers/getVisualEdgeCss.js +2 -2
- package/dist/runtime/helpers/getVisualEdges.d.ts +1 -1
- package/dist/runtime/helpers/getVisualEdges.js +4 -3
- package/dist/runtime/helpers/index.d.ts +4 -0
- package/dist/runtime/helpers/index.js +4 -0
- package/dist/runtime/helpers/isEdgeEqual.js +2 -4
- package/dist/runtime/helpers/isWindowEdge.js +2 -2
- package/dist/runtime/helpers/isWindowEdgePoint.js +2 -2
- package/dist/runtime/helpers/moveEdge.js +2 -2
- package/dist/runtime/helpers/numberToScaledPercent.d.ts +1 -1
- package/dist/runtime/helpers/numberToScaledPercent.js +2 -2
- package/dist/runtime/helpers/numberToScaledSize.js +2 -2
- package/dist/runtime/helpers/rotateFrames.d.ts +7 -0
- package/dist/runtime/helpers/rotateFrames.js +36 -0
- package/dist/runtime/helpers/scaledPointToPx.d.ts +13 -0
- package/dist/runtime/helpers/scaledPointToPx.js +7 -0
- package/dist/runtime/helpers/toWindowCoord.js +2 -2
- package/dist/runtime/layout/applyFrameChanges.d.ts +10 -0
- package/dist/runtime/layout/applyFrameChanges.js +29 -0
- package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +6 -1
- package/dist/runtime/layout/createSplitDecoFromDrag.js +4 -4
- package/dist/runtime/layout/createSplitDecoShapes.d.ts +7 -0
- package/dist/runtime/layout/{createSplitDecoEdge.js → createSplitDecoShapes.js} +6 -3
- package/dist/runtime/layout/debugFrame.js +2 -1
- package/dist/runtime/layout/findSafeSplitEdge.js +2 -2
- package/dist/runtime/layout/frameCreate.js +2 -2
- package/dist/runtime/layout/getCloseFrameInfo.d.ts +7 -6
- package/dist/runtime/layout/getCloseFrameInfo.js +10 -3
- package/dist/runtime/layout/getDragZones.d.ts +8 -0
- package/dist/runtime/layout/getDragZones.js +32 -0
- package/dist/runtime/layout/getFillEmptySpaceInfo.d.ts +65 -0
- package/dist/runtime/layout/getFillEmptySpaceInfo.js +69 -0
- package/dist/runtime/layout/getFrameCollapseInfo.d.ts +13 -0
- package/dist/runtime/layout/getFrameCollapseInfo.js +93 -0
- package/dist/runtime/layout/getFrameDockInfo.d.ts +9 -0
- package/dist/runtime/layout/getFrameDockInfo.js +82 -0
- package/dist/runtime/layout/getFrameDragZones.d.ts +16 -0
- package/dist/runtime/layout/getFrameDragZones.js +74 -0
- package/dist/runtime/layout/getFrameRearrangeInfo.d.ts +139 -0
- package/dist/runtime/layout/getFrameRearrangeInfo.js +87 -0
- package/dist/runtime/layout/getFrameSplitInfo.d.ts +7 -5
- package/dist/runtime/layout/getFrameSplitInfo.js +10 -3
- package/dist/runtime/layout/getFrameSwapInfo.d.ts +9 -0
- package/dist/runtime/layout/getFrameSwapInfo.js +27 -0
- package/dist/runtime/layout/getFrameTo.js +2 -2
- package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +12 -0
- package/dist/runtime/layout/getFrameUncollapseInfo.js +88 -0
- package/dist/runtime/layout/getFrameUndockInfo.d.ts +13 -0
- package/dist/runtime/layout/getFrameUndockInfo.js +51 -0
- package/dist/runtime/layout/getFramesRedistributeInfo.d.ts +29 -0
- package/dist/runtime/layout/getFramesRedistributeInfo.js +53 -0
- package/dist/runtime/layout/getWindowDragZones.d.ts +6 -0
- package/dist/runtime/layout/getWindowDragZones.js +49 -0
- package/dist/runtime/layout/index.d.ts +14 -5
- package/dist/runtime/layout/index.js +14 -5
- package/dist/runtime/layout/isPointInRect.d.ts +7 -0
- package/dist/runtime/layout/{isPointInFrame.js → isPointInRect.js} +1 -1
- package/dist/runtime/layout/resizeFrame.js +2 -2
- package/dist/runtime/settings.d.ts +41 -16
- package/dist/runtime/settings.js +95 -53
- package/dist/runtime/types/index.d.ts +324 -55
- package/dist/runtime/types/index.js +54 -20
- package/package.json +28 -29
- package/src/runtime/components/FrameDragHandle.vue +30 -0
- package/src/runtime/components/LayoutDecos.vue +12 -36
- package/src/runtime/components/LayoutEdges.vue +27 -22
- package/src/runtime/components/LayoutFrame.vue +6 -5
- package/src/runtime/components/LayoutShapeSquare.vue +11 -5
- package/src/runtime/components/LayoutWindow.vue +110 -101
- package/src/runtime/composables/useFrames.ts +80 -50
- package/src/runtime/demo/App.vue +126 -36
- package/src/runtime/demo/DemoControls.vue +115 -6
- package/src/runtime/drag/CloseAction.ts +106 -44
- package/src/runtime/drag/DragActionHandler.ts +71 -20
- package/src/runtime/drag/FrameDragAction.ts +202 -0
- package/src/runtime/drag/SplitAction.ts +106 -34
- package/src/runtime/drag/createDefaultHandlers.ts +19 -0
- package/src/runtime/drag/defaultDragActions.ts +19 -0
- package/src/runtime/drag/types.ts +90 -20
- package/src/runtime/helpers/createZoneSideClipPath.ts +41 -0
- package/src/runtime/helpers/doEdgesOverlap.ts +11 -5
- package/src/runtime/helpers/getDockBoundaries.ts +36 -0
- package/src/runtime/helpers/getEdgeLength.ts +10 -0
- package/src/runtime/helpers/getIntersections.ts +2 -2
- package/src/runtime/helpers/getIntersectionsCss.ts +2 -2
- package/src/runtime/helpers/getMoveEdgeInfo.ts +2 -2
- package/src/runtime/helpers/getResizeLimit.ts +2 -2
- package/src/runtime/helpers/getShapeSquareCss.ts +2 -2
- package/src/runtime/helpers/getVisualEdgeCss.ts +2 -2
- package/src/runtime/helpers/getVisualEdges.ts +5 -4
- package/src/runtime/helpers/index.ts +4 -0
- package/src/runtime/helpers/isEdgeEqual.ts +2 -4
- package/src/runtime/helpers/isWindowEdge.ts +2 -2
- package/src/runtime/helpers/isWindowEdgePoint.ts +2 -2
- package/src/runtime/helpers/moveEdge.ts +2 -2
- package/src/runtime/helpers/numberToScaledPercent.ts +3 -3
- package/src/runtime/helpers/numberToScaledSize.ts +2 -2
- package/src/runtime/helpers/rotateFrames.ts +45 -0
- package/src/runtime/helpers/scaledPointToPx.ts +13 -0
- package/src/runtime/helpers/toWindowCoord.ts +2 -2
- package/src/runtime/layout/applyFrameChanges.ts +39 -0
- package/src/runtime/layout/createSplitDecoFromDrag.ts +12 -6
- package/src/runtime/layout/{createSplitDecoEdge.ts → createSplitDecoShapes.ts} +17 -7
- package/src/runtime/layout/debugFrame.ts +1 -1
- package/src/runtime/layout/findSafeSplitEdge.ts +3 -3
- package/src/runtime/layout/frameCreate.ts +2 -2
- package/src/runtime/layout/getCloseFrameInfo.ts +21 -8
- package/src/runtime/layout/getDragZones.ts +48 -0
- package/src/runtime/layout/getFillEmptySpaceInfo.ts +177 -0
- package/src/runtime/layout/getFrameCollapseInfo.ts +164 -0
- package/src/runtime/layout/getFrameDockInfo.ts +126 -0
- package/src/runtime/layout/getFrameDragZones.ts +100 -0
- package/src/runtime/layout/getFrameRearrangeInfo.ts +261 -0
- package/src/runtime/layout/getFrameSplitInfo.ts +21 -8
- package/src/runtime/layout/getFrameSwapInfo.ts +45 -0
- package/src/runtime/layout/getFrameTo.ts +2 -2
- package/src/runtime/layout/getFrameUncollapseInfo.ts +160 -0
- package/src/runtime/layout/getFrameUndockInfo.ts +97 -0
- package/src/runtime/layout/getFramesRedistributeInfo.ts +98 -0
- package/src/runtime/layout/getWindowDragZones.ts +59 -0
- package/src/runtime/layout/index.ts +14 -5
- package/src/runtime/layout/isPointInRect.ts +7 -0
- package/src/runtime/layout/resizeFrame.ts +2 -2
- package/src/runtime/settings.ts +69 -49
- package/src/runtime/types/index.ts +143 -28
- package/dist/runtime/layout/closeFrame.d.ts +0 -5
- package/dist/runtime/layout/closeFrame.js +0 -13
- package/dist/runtime/layout/closeFrames.d.ts +0 -2
- package/dist/runtime/layout/closeFrames.js +0 -8
- package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -2
- package/dist/runtime/layout/frameSplit.d.ts +0 -16
- package/dist/runtime/layout/frameSplit.js +0 -9
- package/dist/runtime/layout/isPointInFrame.d.ts +0 -2
- package/src/runtime/layout/closeFrame.ts +0 -33
- package/src/runtime/layout/closeFrames.ts +0 -14
- package/src/runtime/layout/frameSplit.ts +0 -31
- package/src/runtime/layout/isPointInFrame.ts +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSplitDecoShapes } from "./createSplitDecoShapes.js";
|
|
2
2
|
import { dirToOrientation } from "../helpers/dirToOrientation.js";
|
|
3
|
-
import {
|
|
4
|
-
export function createSplitDecoFromDrag(frames, frame, dragDirection, dragPoint, snapAmount =
|
|
3
|
+
import { settings } from "../settings.js";
|
|
4
|
+
export function createSplitDecoFromDrag(frames, frame, dragDirection, dragPoint, snapAmount = settings.snapPointScaled, minSize = settings.minSizeScaled, classes = {}) {
|
|
5
5
|
const orientation = dirToOrientation(dragDirection);
|
|
6
6
|
const deco = {
|
|
7
7
|
type: "split",
|
|
@@ -9,6 +9,6 @@ export function createSplitDecoFromDrag(frames, frame, dragDirection, dragPoint,
|
|
|
9
9
|
position: dragPoint[orientation === "horizontal" ? "x" : "y"],
|
|
10
10
|
direction: dragDirection
|
|
11
11
|
};
|
|
12
|
-
deco.shapes =
|
|
12
|
+
deco.shapes = createSplitDecoShapes(frames, deco, snapAmount, minSize, classes);
|
|
13
13
|
return deco;
|
|
14
14
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LayoutFrame, LayoutShape, Point, RawSplitDeco, Size } from "../types/index.js";
|
|
2
|
+
export declare function createSplitDecoShapes(frames: Record<string, LayoutFrame>, deco: RawSplitDeco, snapAmount?: Point, minSize?: Size, classes?: {
|
|
3
|
+
/** @default "deco-split-edge bg-red-500" */
|
|
4
|
+
splitEdge?: string;
|
|
5
|
+
/** @default "deco-split-new-frame bg-blue-500/50" */
|
|
6
|
+
splitNewFrame?: string;
|
|
7
|
+
}): LayoutShape[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findSafeSplitEdgeAndPosition } from "./findSafeSplitEdge.js";
|
|
2
|
-
import {
|
|
3
|
-
export function
|
|
2
|
+
import { settings } from "../settings.js";
|
|
3
|
+
export function createSplitDecoShapes(frames, deco, snapAmount = settings.snapPointScaled, minSize = settings.minSizeScaled, classes = {}) {
|
|
4
4
|
const frame = frames[deco.id];
|
|
5
5
|
const { edge, position } = findSafeSplitEdgeAndPosition(frame, deco.direction, deco.position, snapAmount, minSize);
|
|
6
6
|
const newFrame = { x: frame.x, y: frame.y, width: frame.width, height: frame.height };
|
|
@@ -20,5 +20,8 @@ export function createSplitDecoEdge(frames, deco, snapAmount = getSnapPoint(), m
|
|
|
20
20
|
newFrame.height = position - frame.y;
|
|
21
21
|
break;
|
|
22
22
|
}
|
|
23
|
-
return
|
|
23
|
+
return [
|
|
24
|
+
{ type: "edge", data: edge, attrs: { class: classes.splitEdge ?? "deco-split-edge bg-red-500" } },
|
|
25
|
+
{ type: "square", data: newFrame, attrs: { class: classes.splitNewFrame ?? "deco-split-new-frame bg-blue-500/50" } }
|
|
26
|
+
];
|
|
24
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export function debugFrame(frame) {
|
|
2
2
|
const f = frame;
|
|
3
|
-
return `id: ${f.id.slice(0, 4)}, x: ${f.x}, y: ${f.y}, w: ${f.width}, h: ${f.height}
|
|
3
|
+
return `id: ${f.id.slice(0, 4)}, x: ${f.x}, y: ${f.y}, w: ${f.width}, h: ${f.height}
|
|
4
|
+
docked: ${f.docked}, collapsed: ${f.collapsed}`;
|
|
4
5
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { clampNumber, snapNumber } from "@alanscodelog/utils";
|
|
2
2
|
import { dirToOrientation } from "../helpers/dirToOrientation.js";
|
|
3
3
|
import { oppositeSide } from "../helpers/oppositeSide.js";
|
|
4
|
-
import {
|
|
5
|
-
export function findSafeSplitEdgeAndPosition(frame, dragDirection, dragPointOrPosition, snapAmount =
|
|
4
|
+
import { settings } from "../settings.js";
|
|
5
|
+
export function findSafeSplitEdgeAndPosition(frame, dragDirection, dragPointOrPosition, snapAmount = settings.snapPointScaled, minSize = settings.minSizeScaled) {
|
|
6
6
|
const orientation = dirToOrientation(dragDirection);
|
|
7
7
|
const position = typeof dragPointOrPosition === "number" ? dragPointOrPosition : dragPointOrPosition[orientation === "horizontal" ? "x" : "y"];
|
|
8
8
|
const coordKey = orientation === "vertical" ? "y" : "x";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { v4 as uuidv4 } from "uuid";
|
|
2
|
-
import {
|
|
2
|
+
import { settings } from "../settings.js";
|
|
3
3
|
export function frameCreate(opts = {}) {
|
|
4
|
-
const maxInt =
|
|
4
|
+
const maxInt = settings.maxInt;
|
|
5
5
|
return {
|
|
6
6
|
width: maxInt,
|
|
7
7
|
height: maxInt,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type Direction, type Edge, type EdgeSide, LAYOUT_ERROR, type LayoutFrame, type Size } from "../types/index.js";
|
|
1
|
+
import { type Direction, type Edge, type EdgeSide, LAYOUT_ERROR, type LayoutChange, type LayoutFrame, type Size } from "../types/index.js";
|
|
2
2
|
import { KnownError } from "../utils/KnownError.js";
|
|
3
3
|
/**
|
|
4
|
-
* Returns the information necessary to close a frame or frames (if force: true).
|
|
4
|
+
* Returns a {@link LayoutChange} with the information necessary to close a frame or frames (if force: true).
|
|
5
|
+
*
|
|
6
|
+
* Changes can be applied to a window with {@link applyFrameChanges}.
|
|
5
7
|
*
|
|
6
8
|
* Can close by direction or by frame edge.
|
|
7
9
|
*
|
|
@@ -60,6 +62,8 @@ import { KnownError } from "../utils/KnownError.js";
|
|
|
60
62
|
*│C │ │
|
|
61
63
|
*└─────────┴──┘
|
|
62
64
|
* ```
|
|
65
|
+
*
|
|
66
|
+
* Changes can be applied with {@link applyFrameChanges}.
|
|
63
67
|
*/
|
|
64
68
|
export declare function getCloseFrameInfo<T extends "edge" | "dir">(frames: LayoutFrame[], visualEdges: Edge[], frame: LayoutFrame,
|
|
65
69
|
/**
|
|
@@ -67,7 +71,4 @@ export declare function getCloseFrameInfo<T extends "edge" | "dir">(frames: Layo
|
|
|
67
71
|
*
|
|
68
72
|
* For example, a frame that touches the right window edge can only be closed "to the right" in the horizontal direction or by it's left edge. Another way to think about it is the left edge is "collapsed" towards the "right".
|
|
69
73
|
*/
|
|
70
|
-
closeDirOrSide: (T extends "dir" ? Direction : EdgeSide), closeBy?: T, force?: boolean, minSize?: Size):
|
|
71
|
-
modifiedFrames: LayoutFrame[];
|
|
72
|
-
deletedFrames: LayoutFrame[];
|
|
73
|
-
} | KnownError<typeof LAYOUT_ERROR.CANT_CLOSE_NEARBY_FRAMES_TOO_SMALL | typeof LAYOUT_ERROR.CANT_CLOSE_NO_DRAG_EDGE | typeof LAYOUT_ERROR.CANT_CLOSE_SINGLE_FRAME | typeof LAYOUT_ERROR.CANT_CLOSE_WITHOUT_FORCE>;
|
|
74
|
+
closeDirOrSide: (T extends "dir" ? Direction : EdgeSide), closeBy?: T, force?: boolean, minSize?: Size): LayoutChange | KnownError<typeof LAYOUT_ERROR.CANT_CLOSE_NEARBY_FRAMES_TOO_SMALL | typeof LAYOUT_ERROR.CANT_CLOSE_NO_DRAG_EDGE | typeof LAYOUT_ERROR.CANT_CLOSE_SINGLE_FRAME | typeof LAYOUT_ERROR.CANT_CLOSE_WITHOUT_FORCE | typeof LAYOUT_ERROR.CANT_LEAVE_NO_UNDOCKED_FRAMES>;
|
|
@@ -8,10 +8,10 @@ import { dirToSide } from "../helpers/dirToSide.js";
|
|
|
8
8
|
import { findFrameDraggableEdges } from "../helpers/findFrameDraggableEdges.js";
|
|
9
9
|
import { getEdgeOrientation } from "../helpers/getEdgeOrientation.js";
|
|
10
10
|
import { oppositeSide } from "../helpers/oppositeSide.js";
|
|
11
|
-
import {
|
|
11
|
+
import { settings } from "../settings.js";
|
|
12
12
|
import { LAYOUT_ERROR } from "../types/index.js";
|
|
13
13
|
import { KnownError } from "../utils/KnownError.js";
|
|
14
|
-
export function getCloseFrameInfo(frames, visualEdges, frame, closeDirOrSide, closeBy = "dir", force = false, minSize =
|
|
14
|
+
export function getCloseFrameInfo(frames, visualEdges, frame, closeDirOrSide, closeBy = "dir", force = false, minSize = settings.minSizeScaled) {
|
|
15
15
|
if (frames.length === 1) {
|
|
16
16
|
return new KnownError(
|
|
17
17
|
LAYOUT_ERROR.CANT_CLOSE_SINGLE_FRAME,
|
|
@@ -19,6 +19,13 @@ export function getCloseFrameInfo(frames, visualEdges, frame, closeDirOrSide, cl
|
|
|
19
19
|
{ frame }
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
+
if (!frame.docked && frames.filter((_) => !_.docked).length === 0) {
|
|
23
|
+
return new KnownError(
|
|
24
|
+
LAYOUT_ERROR.CANT_LEAVE_NO_UNDOCKED_FRAMES,
|
|
25
|
+
`Can't close last undocked frame. One undocked frame must remain`,
|
|
26
|
+
{ frame: frame.id }
|
|
27
|
+
);
|
|
28
|
+
}
|
|
22
29
|
const side = closeBy === "dir" ? oppositeSide(dirToSide(closeDirOrSide)) : closeDirOrSide;
|
|
23
30
|
const sideOpposite = oppositeSide(side);
|
|
24
31
|
const draggableEdges = findFrameDraggableEdges(frame, visualEdges, !force, [side]);
|
|
@@ -99,5 +106,5 @@ export function getCloseFrameInfo(frames, visualEdges, frame, closeDirOrSide, cl
|
|
|
99
106
|
clone[sizeKey] += moveAmount;
|
|
100
107
|
modifiedFrames.push(clone);
|
|
101
108
|
}
|
|
102
|
-
return { modifiedFrames, deletedFrames };
|
|
109
|
+
return { modified: modifiedFrames, created: [], deleted: deletedFrames };
|
|
103
110
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DragState, DragZone } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Find the drag zone under the drag point.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDragZones(state: Pick<DragState, "dragPoint" | "dragHoveredFrame" | "frames" | "win">, { frameEdgePx, windowEdgePx }: {
|
|
6
|
+
frameEdgePx: number;
|
|
7
|
+
windowEdgePx: number;
|
|
8
|
+
}): DragZone | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getFrameDragZones } from "./getFrameDragZones.js";
|
|
2
|
+
import { getWindowDragZones } from "./getWindowDragZones.js";
|
|
3
|
+
import { isPointInRect } from "./isPointInRect.js";
|
|
4
|
+
export function getDragZones(state, { frameEdgePx, windowEdgePx }) {
|
|
5
|
+
const { dragPoint, win } = state;
|
|
6
|
+
const frameId = state.dragHoveredFrame?.id;
|
|
7
|
+
if (!frameId) return;
|
|
8
|
+
const frame = state.frames[frameId];
|
|
9
|
+
if (!frame || !dragPoint) return;
|
|
10
|
+
const frameZones = getFrameDragZones(frame, frameEdgePx, win.pxWidth, win.pxHeight);
|
|
11
|
+
const windowZones = getWindowDragZones(win, windowEdgePx);
|
|
12
|
+
let matchedZone;
|
|
13
|
+
for (const zone of windowZones) {
|
|
14
|
+
if (isPointInRect(zone, dragPoint)) {
|
|
15
|
+
matchedZone = {
|
|
16
|
+
...zone,
|
|
17
|
+
type: "window"
|
|
18
|
+
};
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!matchedZone) {
|
|
23
|
+
for (const zone of frameZones) {
|
|
24
|
+
if (isPointInRect(zone, dragPoint)) {
|
|
25
|
+
matchedZone = zone;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!matchedZone) return void 0;
|
|
31
|
+
return matchedZone;
|
|
32
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { LayoutChange, LayoutFrame, LayoutWindow } from "../types/index.js";
|
|
2
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
3
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
4
|
+
/**
|
|
5
|
+
* Finds a frame to fill the empty space left behind by a moved/empty frame (e.g. a dragged frame's original position).
|
|
6
|
+
*
|
|
7
|
+
* Returns a {@link LayoutChange} with the information necessary information..
|
|
8
|
+
*
|
|
9
|
+
* Changes can be applied to a window with {@link applyFrameChanges}.
|
|
10
|
+
*
|
|
11
|
+
* Examples where * would be the empty space:
|
|
12
|
+
*
|
|
13
|
+
* Selection priority:
|
|
14
|
+
* 1. Prefer frames listed in preferredFrames (for dragging these are the dragged and target frames).
|
|
15
|
+
* ┌─────┬─────┐
|
|
16
|
+
* │A │* │
|
|
17
|
+
* ├─────┼─────┤
|
|
18
|
+
* │C │B │
|
|
19
|
+
* └─────┴─────┘
|
|
20
|
+
*
|
|
21
|
+
* Without preferredFrames set to B, A would be preferred as it shares the shortest edge with the empty space.
|
|
22
|
+
*
|
|
23
|
+
* ┌─────┬─────┐
|
|
24
|
+
* │A │B │
|
|
25
|
+
* ├─────┤ │
|
|
26
|
+
* │C │ │
|
|
27
|
+
* └─────┴─────┘
|
|
28
|
+
*
|
|
29
|
+
* In a more complex example:
|
|
30
|
+
*
|
|
31
|
+
* ┌─────┬─────┬─────┐
|
|
32
|
+
* │A │* │C │
|
|
33
|
+
* │ │ ├─────┤
|
|
34
|
+
* │ │ │D │
|
|
35
|
+
* └─────┴─────┴─────┘
|
|
36
|
+
*
|
|
37
|
+
* If preferredFrames is C OR D (usually it's both but it might only be one, just take all other frames along that edge if they end at the empty frames end).
|
|
38
|
+
*
|
|
39
|
+
* ┌─────┬──────────┐
|
|
40
|
+
* │A │C │
|
|
41
|
+
* │ ├──────────┤
|
|
42
|
+
* │ │D │
|
|
43
|
+
* └─────┴──────────┘
|
|
44
|
+
*
|
|
45
|
+
* And then in the following we would not be able to even expand C or D so we would not be able to satisfy the preference:
|
|
46
|
+
*
|
|
47
|
+
* ┌─────┬─────┬─────┐
|
|
48
|
+
* │A │* │C │
|
|
49
|
+
* │ │ ├─────┤
|
|
50
|
+
* │ │ │ │
|
|
51
|
+
* │ ├─────┤D │
|
|
52
|
+
* │ │B │ │
|
|
53
|
+
* └─────┴─────┴─────┘
|
|
54
|
+
*
|
|
55
|
+
* 2. Prefer the shortest frame that shares an exact edge. Taking the previous example it would be B:
|
|
56
|
+
*
|
|
57
|
+
* ┌─────┬─────┬─────┐
|
|
58
|
+
* │A │B │C │
|
|
59
|
+
* │ │ ├─────┤
|
|
60
|
+
* │ │ │ │
|
|
61
|
+
* │ │ │D │
|
|
62
|
+
* │ │ │ │
|
|
63
|
+
* └─────┴─────┴─────┘
|
|
64
|
+
*/
|
|
65
|
+
export declare function getFillEmptySpaceInfo(win: LayoutWindow, emptyFrame: Omit<LayoutFrame, "id">, preferredFrames?: string[], skipFrames?: string[]): LayoutChange | KnownError<typeof LAYOUT_ERROR.NO_FILL_CANDIDATES>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { doEdgesOverlap } from "../helpers/doEdgesOverlap.js";
|
|
2
|
+
import { frameToEdges } from "../helpers/frameToEdges.js";
|
|
3
|
+
import { getEdgeLength } from "../helpers/getEdgeLength.js";
|
|
4
|
+
import { oppositeSide } from "../helpers/oppositeSide.js";
|
|
5
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
6
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
7
|
+
export function getFillEmptySpaceInfo(win, emptyFrame, preferredFrames = [], skipFrames = []) {
|
|
8
|
+
const emptyEdges = frameToEdges(emptyFrame);
|
|
9
|
+
const vacHeight = emptyFrame.height;
|
|
10
|
+
const vacWidth = emptyFrame.width;
|
|
11
|
+
const candidatesBySides = /* @__PURE__ */ new Map();
|
|
12
|
+
for (const frame of Object.values(win.frames)) {
|
|
13
|
+
if (skipFrames.includes(frame.id)) continue;
|
|
14
|
+
const frameEdges = frameToEdges(frame);
|
|
15
|
+
for (const frameSide of ["top", "bottom", "left", "right"]) {
|
|
16
|
+
const frameEdge = frameEdges[frameSide];
|
|
17
|
+
const emptyOppositeSide = oppositeSide(frameSide);
|
|
18
|
+
const emptyEdge = emptyEdges[emptyOppositeSide];
|
|
19
|
+
if (candidatesBySides.get(emptyOppositeSide)?.skip) continue;
|
|
20
|
+
const exact = frameEdge.startX === emptyEdge.startX && frameEdge.startY === emptyEdge.startY && frameEdge.endX === emptyEdge.endX && frameEdge.endY === emptyEdge.endY;
|
|
21
|
+
if (exact || doEdgesOverlap(frameEdge, emptyEdge, void 0, false)) {
|
|
22
|
+
if (!candidatesBySides.has(emptyOppositeSide)) {
|
|
23
|
+
candidatesBySides.set(emptyOppositeSide, { candidates: [], skip: false, totalLength: 0, hasExact: false, hasPreferred: false });
|
|
24
|
+
}
|
|
25
|
+
const group = candidatesBySides.get(emptyOppositeSide);
|
|
26
|
+
if (!exact) {
|
|
27
|
+
const isVertical = frameEdge.startX === emptyEdge.startX;
|
|
28
|
+
const extendsBeyond = isVertical ? frameEdge.startY < emptyEdge.startY || frameEdge.endY > emptyEdge.endY : frameEdge.startX < emptyEdge.startX || frameEdge.endX > emptyEdge.endX;
|
|
29
|
+
if (extendsBeyond) {
|
|
30
|
+
group.skip = true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const len = getEdgeLength(frameEdge);
|
|
34
|
+
group.totalLength += len;
|
|
35
|
+
if (exact) group.hasExact = true;
|
|
36
|
+
if (preferredFrames.includes(frame.id)) group.hasPreferred = true;
|
|
37
|
+
group.candidates.push({ frame, frameSide, emptySide: emptyOppositeSide, edgeLength: len, exact });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const entries = [...candidatesBySides.values()];
|
|
42
|
+
const preferredSides = entries.filter((c) => c.hasPreferred && !c.skip).sort((a, b) => a.totalLength - b.totalLength);
|
|
43
|
+
const fallbackSides = entries.filter((c) => !c.hasPreferred && !c.skip).sort((a, b) => a.totalLength - b.totalLength);
|
|
44
|
+
if (preferredSides.length === 0 && fallbackSides.length === 0) return new KnownError(LAYOUT_ERROR.NO_FILL_CANDIDATES, `No fill candidates found.`, {});
|
|
45
|
+
const chosenCandidates = preferredSides.length > 0 ? preferredSides[0].candidates : fallbackSides[0].candidates;
|
|
46
|
+
const result = [];
|
|
47
|
+
for (const chosen of chosenCandidates) {
|
|
48
|
+
const { frame, frameSide } = chosen;
|
|
49
|
+
const updated = { ...frame };
|
|
50
|
+
switch (frameSide) {
|
|
51
|
+
case "top":
|
|
52
|
+
updated.y -= vacHeight;
|
|
53
|
+
updated.height += vacHeight;
|
|
54
|
+
break;
|
|
55
|
+
case "bottom":
|
|
56
|
+
updated.height += vacHeight;
|
|
57
|
+
break;
|
|
58
|
+
case "left":
|
|
59
|
+
updated.x -= vacWidth;
|
|
60
|
+
updated.width += vacWidth;
|
|
61
|
+
break;
|
|
62
|
+
case "right":
|
|
63
|
+
updated.width += vacWidth;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
result.push(updated);
|
|
67
|
+
}
|
|
68
|
+
return { modified: result, created: [], deleted: [] };
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LayoutChange, LayoutWindow } from "../types/index.js";
|
|
2
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
3
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
4
|
+
/**
|
|
5
|
+
* Returns a {@link LayoutChange} with the information necessary to collapse a docked frame.
|
|
6
|
+
*
|
|
7
|
+
* Changes can be applied to a window with {@link applyFrameChanges}.
|
|
8
|
+
*
|
|
9
|
+
* Collapsing shrinks the frame to the configured collapse size and redistributes
|
|
10
|
+
* the freed space to neighboring frames. The pre-collapse size is stored in
|
|
11
|
+
* `collapsed` so it can be restored later.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getFrameCollapseInfo(win: LayoutWindow, frameId: string): LayoutChange | KnownError<typeof LAYOUT_ERROR.CANT_COLLAPSE_NOT_DOCKED>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { pushIfNotIn } from "@alanscodelog/utils/pushIfNotIn";
|
|
2
|
+
import { walk } from "@alanscodelog/utils/walk";
|
|
3
|
+
import { applyFrameChanges } from "./applyFrameChanges.js";
|
|
4
|
+
import { getFramesRedistributeInfo } from "./getFramesRedistributeInfo.js";
|
|
5
|
+
import { oppositeSide } from "../helpers/oppositeSide.js";
|
|
6
|
+
import { settings } from "../settings.js";
|
|
7
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
8
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
9
|
+
export function getFrameCollapseInfo(win, frameId) {
|
|
10
|
+
win = walk(win, void 0, { save: true });
|
|
11
|
+
const frame = win.frames[frameId];
|
|
12
|
+
if (!frame) throw new Error(`Unknown frame ${frameId}`);
|
|
13
|
+
if (!frame.docked) throw new Error(`Frame ${frameId} is not docked.`);
|
|
14
|
+
if (typeof frame.collapsed === "number") throw new Error(`Frame ${frameId} is already collapsed.`);
|
|
15
|
+
const toExtract = [frame.id];
|
|
16
|
+
if (frame.docked === void 0) {
|
|
17
|
+
return new KnownError(
|
|
18
|
+
LAYOUT_ERROR.CANT_COLLAPSE_NOT_DOCKED,
|
|
19
|
+
`Frame ${frameId} is not docked and cannot be collapsed.`,
|
|
20
|
+
{ frame }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
const isVertical = frame.docked === "left" || frame.docked === "right";
|
|
24
|
+
const sizeKey = isVertical ? "width" : "height";
|
|
25
|
+
const posKey = isVertical ? "x" : "y";
|
|
26
|
+
const oppositePosKey = isVertical ? "y" : "x";
|
|
27
|
+
const oppositeSizeKey = isVertical ? "height" : "width";
|
|
28
|
+
const collapseSize = settings.collapseSizeScaled;
|
|
29
|
+
const currentSize = frame[sizeKey];
|
|
30
|
+
const collapseAmount = collapseSize[sizeKey];
|
|
31
|
+
const shrinkAmount = currentSize - collapseAmount;
|
|
32
|
+
const dockedSide = frame.docked;
|
|
33
|
+
const framesToFix = [];
|
|
34
|
+
const opposite = oppositeSide(dockedSide);
|
|
35
|
+
for (const other of Object.values(win.frames)) {
|
|
36
|
+
if (frame.id === other.id || !other.docked) continue;
|
|
37
|
+
if (other.docked === opposite) continue;
|
|
38
|
+
if (dockedSide === "left" || dockedSide === "top") {
|
|
39
|
+
if (other[posKey] !== 0) continue;
|
|
40
|
+
other[posKey] = frame[posKey] + frame[sizeKey];
|
|
41
|
+
other[sizeKey] -= frame[sizeKey];
|
|
42
|
+
framesToFix.push({
|
|
43
|
+
id: other.id,
|
|
44
|
+
posKey,
|
|
45
|
+
sizeKey,
|
|
46
|
+
type: "start"
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
if (other[posKey] + other[sizeKey] !== settings.maxInt) continue;
|
|
50
|
+
other[sizeKey] -= frame[sizeKey];
|
|
51
|
+
framesToFix.push({
|
|
52
|
+
id: other.id,
|
|
53
|
+
posKey,
|
|
54
|
+
sizeKey,
|
|
55
|
+
type: "end"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const otherFrameIds = Object.keys(win.frames).filter((id) => id !== frameId);
|
|
60
|
+
const redistributeSide = oppositeSide(dockedSide);
|
|
61
|
+
const changes = getFramesRedistributeInfo(win, redistributeSide, otherFrameIds, -shrinkAmount, true);
|
|
62
|
+
if (changes instanceof KnownError) {
|
|
63
|
+
if (changes.code === LAYOUT_ERROR.REDISTRIBUTE_OUT_OF_BOUNDS || LAYOUT_ERROR.NO_SPACE_TO_REDISTRIBUTE) {
|
|
64
|
+
changes.message = `This error should never happen, please file a bug report: ${changes.message}`;
|
|
65
|
+
throw changes;
|
|
66
|
+
}
|
|
67
|
+
return changes;
|
|
68
|
+
}
|
|
69
|
+
applyFrameChanges(win, changes);
|
|
70
|
+
pushIfNotIn(toExtract, changes.modified.map((_) => _.id));
|
|
71
|
+
for (const fix of framesToFix) {
|
|
72
|
+
const other = win.frames[fix.id];
|
|
73
|
+
if (fix.type === "start") {
|
|
74
|
+
const sizeDiff = other[fix.posKey];
|
|
75
|
+
other[fix.posKey] = 0;
|
|
76
|
+
other[fix.sizeKey] += sizeDiff;
|
|
77
|
+
} else {
|
|
78
|
+
const sizeDiff = settings.maxInt - (other[fix.posKey] + other[fix.sizeKey]);
|
|
79
|
+
other[fix.sizeKey] += sizeDiff;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
pushIfNotIn(toExtract, framesToFix.map((_) => _.id));
|
|
83
|
+
if (frame.docked === "right" || frame.docked === "bottom") {
|
|
84
|
+
frame[posKey] = frame[posKey] + (frame[sizeKey] - collapseSize[sizeKey]);
|
|
85
|
+
}
|
|
86
|
+
frame[sizeKey] = collapseSize[sizeKey];
|
|
87
|
+
frame.collapsed = currentSize;
|
|
88
|
+
if (collapseSize[sizeKey] === 0) {
|
|
89
|
+
frame[oppositePosKey] = 0;
|
|
90
|
+
frame[oppositeSizeKey] = settings.maxInt;
|
|
91
|
+
}
|
|
92
|
+
return { modified: toExtract.map((_) => win.frames[_]), created: [], deleted: [] };
|
|
93
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EdgeSide, LayoutChange, LayoutWindow } from "../types/index.js";
|
|
2
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
3
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
4
|
+
/**
|
|
5
|
+
* Returns a {@link LayoutChange} with the information necessary to dock a frame to a window edge.
|
|
6
|
+
*
|
|
7
|
+
* Changes can be applied to a window with {@link applyFrameChanges}.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getFrameDockInfo(win: LayoutWindow, frameId: string, side: EdgeSide, maxPerpendicularLength?: number): LayoutChange | KnownError<typeof LAYOUT_ERROR.REDISTRIBUTE_OUT_OF_BOUNDS> | KnownError<typeof LAYOUT_ERROR.NO_SPACE_TO_REDISTRIBUTE> | KnownError<typeof LAYOUT_ERROR.CANT_LEAVE_NO_UNDOCKED_FRAMES> | KnownError<typeof LAYOUT_ERROR.FRAME_ALREADY_DOCKED_ON_SIDE> | KnownError<typeof LAYOUT_ERROR.CANT_UNDOCK_COLLAPSED_FRAME> | KnownError<typeof LAYOUT_ERROR.NO_FILL_CANDIDATES>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { pushIfNotIn } from "@alanscodelog/utils/pushIfNotIn";
|
|
2
|
+
import { walk } from "@alanscodelog/utils/walk";
|
|
3
|
+
import { applyFrameChanges } from "./applyFrameChanges.js";
|
|
4
|
+
import { getFillEmptySpaceInfo } from "./getFillEmptySpaceInfo.js";
|
|
5
|
+
import { getFramesRedistributeInfo } from "./getFramesRedistributeInfo.js";
|
|
6
|
+
import { getFrameUndockInfo } from "./getFrameUndockInfo.js";
|
|
7
|
+
import { cloneFrame } from "../helpers/cloneFrame.js";
|
|
8
|
+
import { getDockBoundaries } from "../helpers/getDockBoundaries.js";
|
|
9
|
+
import { oppositeSide } from "../helpers/oppositeSide.js";
|
|
10
|
+
import { settings } from "../settings.js";
|
|
11
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
12
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
13
|
+
export function getFrameDockInfo(win, frameId, side, maxPerpendicularLength) {
|
|
14
|
+
win = walk(win, void 0, { save: true });
|
|
15
|
+
const frame = win.frames[frameId];
|
|
16
|
+
if (!frame) {
|
|
17
|
+
throw new Error(`Unknown frame ${frameId}`);
|
|
18
|
+
}
|
|
19
|
+
if (frame.docked === side) throw new Error(`Frame ${frameId} is already docked on side ${side}.`);
|
|
20
|
+
const alreadyDockedOnSide = Object.values(win.frames).find((f) => f.docked === side);
|
|
21
|
+
if (alreadyDockedOnSide) {
|
|
22
|
+
return new KnownError(LAYOUT_ERROR.FRAME_ALREADY_DOCKED_ON_SIDE, `Frame ${alreadyDockedOnSide.id} already docked on side ${side}.`, { id: alreadyDockedOnSide.id, side });
|
|
23
|
+
}
|
|
24
|
+
if (frame.docked && frame.docked !== side) {
|
|
25
|
+
const undockInfo = getFrameUndockInfo(win, frameId);
|
|
26
|
+
if (undockInfo instanceof Error) return undockInfo;
|
|
27
|
+
applyFrameChanges(win, undockInfo);
|
|
28
|
+
}
|
|
29
|
+
const isHorizontal = side === "left" || side === "right";
|
|
30
|
+
const perpendicular = isHorizontal ? "width" : "height";
|
|
31
|
+
const oldFrame = cloneFrame(frame);
|
|
32
|
+
const otherFrameIds = Object.keys(win.frames).filter((_) => _ !== frameId);
|
|
33
|
+
const nonDockedFrameIds = otherFrameIds.filter((id) => !win.frames[id].docked);
|
|
34
|
+
if (nonDockedFrameIds.length === 0) {
|
|
35
|
+
return new KnownError(LAYOUT_ERROR.CANT_LEAVE_NO_UNDOCKED_FRAMES, `Can't dock frame ${frameId} because there are no other undocked frames.`, { frameId });
|
|
36
|
+
}
|
|
37
|
+
const effectiveMaxPerpendicular = maxPerpendicularLength ?? settings.maxPerpendicularLengthScaled.width;
|
|
38
|
+
const perpendicularLength = otherFrameIds.length > 0 ? Math.min(frame[perpendicular], effectiveMaxPerpendicular) : frame[perpendicular];
|
|
39
|
+
frame.docked = side;
|
|
40
|
+
frame.collapsed = false;
|
|
41
|
+
const toExtract = [frame.id];
|
|
42
|
+
const changes = getFillEmptySpaceInfo(win, oldFrame, [], [frameId]);
|
|
43
|
+
if (changes instanceof Error) return changes;
|
|
44
|
+
applyFrameChanges(win, changes);
|
|
45
|
+
pushIfNotIn(toExtract, changes.modified.map((_) => _.id));
|
|
46
|
+
const sideToPushTowards = oppositeSide(side);
|
|
47
|
+
const redistributeChanges = getFramesRedistributeInfo(win, sideToPushTowards, nonDockedFrameIds, perpendicularLength);
|
|
48
|
+
if (redistributeChanges instanceof KnownError) {
|
|
49
|
+
return redistributeChanges;
|
|
50
|
+
}
|
|
51
|
+
applyFrameChanges(win, redistributeChanges);
|
|
52
|
+
pushIfNotIn(toExtract, redistributeChanges.modified.map((_) => _.id));
|
|
53
|
+
const { minX, maxX, minY, maxY } = getDockBoundaries(win);
|
|
54
|
+
switch (side) {
|
|
55
|
+
case "left":
|
|
56
|
+
frame.x = 0;
|
|
57
|
+
frame.y = minY;
|
|
58
|
+
frame.width = perpendicularLength;
|
|
59
|
+
frame.height = maxY - minY;
|
|
60
|
+
break;
|
|
61
|
+
case "right":
|
|
62
|
+
frame.x = settings.maxInt - perpendicularLength;
|
|
63
|
+
frame.y = minY;
|
|
64
|
+
frame.width = perpendicularLength;
|
|
65
|
+
frame.height = maxY - minY;
|
|
66
|
+
break;
|
|
67
|
+
case "top":
|
|
68
|
+
frame.x = minX;
|
|
69
|
+
frame.y = 0;
|
|
70
|
+
frame.width = maxX - minX;
|
|
71
|
+
frame.height = perpendicularLength;
|
|
72
|
+
break;
|
|
73
|
+
case "bottom":
|
|
74
|
+
frame.x = minX;
|
|
75
|
+
frame.y = settings.maxInt - perpendicularLength;
|
|
76
|
+
frame.width = maxX - minX;
|
|
77
|
+
frame.height = perpendicularLength;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
const res = toExtract.map((_) => win.frames[_]);
|
|
81
|
+
return { modified: res, created: [], deleted: [] };
|
|
82
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DragZone } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns frame drag zones (in **unrounded** scaled coordinate space).
|
|
4
|
+
*
|
|
5
|
+
* If the frame is too narrow for both left+right zones, only the center zone is returned.
|
|
6
|
+
*
|
|
7
|
+
* Same logic applies to top/bottom for very short frames.
|
|
8
|
+
*
|
|
9
|
+
* Unrounded because these are for display purposes only.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getFrameDragZones(frame: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}, thresholdPx: number, windowPxWidth: number, windowPxHeight: number): DragZone[];
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { settings } from "../settings.js";
|
|
2
|
+
export function getFrameDragZones(frame, thresholdPx, windowPxWidth, windowPxHeight) {
|
|
3
|
+
const thX = thresholdPx / windowPxWidth * settings.maxInt;
|
|
4
|
+
const thY = thresholdPx / windowPxHeight * settings.maxInt;
|
|
5
|
+
const pxWidth = frame.width / settings.maxInt * windowPxWidth;
|
|
6
|
+
const pxHeight = frame.height / settings.maxInt * windowPxHeight;
|
|
7
|
+
if (frame.width <= 3 * thX || frame.height <= 3 * thY) {
|
|
8
|
+
return [{
|
|
9
|
+
type: "frame",
|
|
10
|
+
side: "center",
|
|
11
|
+
// this is more like center/full
|
|
12
|
+
x: frame.x,
|
|
13
|
+
y: frame.y,
|
|
14
|
+
width: frame.width,
|
|
15
|
+
height: frame.height,
|
|
16
|
+
pxWidth,
|
|
17
|
+
pxHeight
|
|
18
|
+
}];
|
|
19
|
+
}
|
|
20
|
+
const zones = [];
|
|
21
|
+
zones.push({
|
|
22
|
+
type: "frame",
|
|
23
|
+
side: "top",
|
|
24
|
+
x: frame.x,
|
|
25
|
+
y: frame.y,
|
|
26
|
+
width: frame.width,
|
|
27
|
+
height: thY,
|
|
28
|
+
pxWidth,
|
|
29
|
+
pxHeight: thresholdPx
|
|
30
|
+
});
|
|
31
|
+
zones.push({
|
|
32
|
+
type: "frame",
|
|
33
|
+
side: "bottom",
|
|
34
|
+
x: frame.x,
|
|
35
|
+
y: frame.y + frame.height - thY,
|
|
36
|
+
width: frame.width,
|
|
37
|
+
height: thY,
|
|
38
|
+
pxWidth,
|
|
39
|
+
pxHeight: thresholdPx
|
|
40
|
+
});
|
|
41
|
+
zones.push({
|
|
42
|
+
type: "frame",
|
|
43
|
+
side: "left",
|
|
44
|
+
x: frame.x,
|
|
45
|
+
y: frame.y,
|
|
46
|
+
width: thX,
|
|
47
|
+
height: frame.height,
|
|
48
|
+
pxWidth: thresholdPx,
|
|
49
|
+
pxHeight
|
|
50
|
+
});
|
|
51
|
+
zones.push({
|
|
52
|
+
type: "frame",
|
|
53
|
+
side: "right",
|
|
54
|
+
x: frame.x + frame.width - thX,
|
|
55
|
+
y: frame.y,
|
|
56
|
+
width: thX,
|
|
57
|
+
height: frame.height,
|
|
58
|
+
pxWidth: thresholdPx,
|
|
59
|
+
pxHeight
|
|
60
|
+
});
|
|
61
|
+
const cw = frame.width - 2 * thX;
|
|
62
|
+
const ch = frame.height - 2 * thY;
|
|
63
|
+
zones.push({
|
|
64
|
+
type: "frame",
|
|
65
|
+
side: "center",
|
|
66
|
+
x: frame.x + thX,
|
|
67
|
+
y: frame.y + thY,
|
|
68
|
+
width: cw,
|
|
69
|
+
height: ch,
|
|
70
|
+
pxWidth: cw / settings.maxInt * windowPxWidth,
|
|
71
|
+
pxHeight: ch / settings.maxInt * windowPxHeight
|
|
72
|
+
});
|
|
73
|
+
return zones;
|
|
74
|
+
}
|