@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,12 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComputedRef, InjectionKey, Ref } from "vue"
|
|
2
|
+
|
|
3
|
+
import type { Direction, Edge, FrameId, IntersectionEntry, LayoutFrame, LayoutShape, LayoutWindow, Orientation, Point } from "../types/index.js"
|
|
2
4
|
|
|
3
5
|
export type DragState = {
|
|
4
6
|
/** The current directions in the corresponding orientations that the user is dragging in. */
|
|
5
7
|
dragDirections: Record<Orientation, Direction | undefined>
|
|
6
8
|
/** The curren point (in scaled window coordinates) the user is dragging at. */
|
|
7
9
|
dragPoint?: Point
|
|
8
|
-
/** Whether the user is currently dragging. Is
|
|
9
|
-
isDragging: boolean
|
|
10
|
+
/** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
|
|
11
|
+
isDragging: boolean | "frame" | "edge"
|
|
12
|
+
/** Whether to show the moved frames while dragging. */
|
|
13
|
+
showDragging: boolean
|
|
14
|
+
/** The frame being dragged during a frame drag. Only set when isDragging is "frame". */
|
|
15
|
+
draggingFrameId?: FrameId
|
|
10
16
|
/**
|
|
11
17
|
* The edges that are currently being dragged. There are multiple edges if they drag an intersection since what's actually happening is we're just dragging the closest horizontal and vertical edges.
|
|
12
18
|
*/
|
|
@@ -46,18 +52,31 @@ export type DragState = {
|
|
|
46
52
|
win: LayoutWindow
|
|
47
53
|
}
|
|
48
54
|
|
|
55
|
+
|
|
56
|
+
export interface ActionDragChangeResult {
|
|
57
|
+
/** Whether the drag should update the edges. Defaults to false. */
|
|
58
|
+
updateEdges?: boolean
|
|
59
|
+
/** Deco shapes produced by this action during this drag step. */
|
|
60
|
+
shapes: LayoutShape[]
|
|
61
|
+
/** Whether to show the moved edges while dragging. Defaults to true. */
|
|
62
|
+
showDragging?: boolean
|
|
63
|
+
}
|
|
64
|
+
export type DragChangeResult = Omit<ActionDragChangeResult, "shapes">
|
|
65
|
+
|
|
49
66
|
/**
|
|
50
|
-
*
|
|
67
|
+
* Called when the drag coordinates change (during any event).
|
|
68
|
+
*
|
|
69
|
+
* Should return `{ allowed: true/false, shapes: LayoutShape[] }` to control whether the action is allowed and edges update and what deco shapes to render.
|
|
70
|
+
*
|
|
71
|
+
* Note that the allowed return type only affect the `move` event but is also typed as `boolean` for other events for ease of use.
|
|
51
72
|
*/
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
): boolean | undefined
|
|
60
|
-
}
|
|
73
|
+
export type DragChangeHandler = <T extends "start" | "move" | "end">(
|
|
74
|
+
type: T,
|
|
75
|
+
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
76
|
+
state: DragState,
|
|
77
|
+
forceRecalculateEdges: () => void,
|
|
78
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: DragState) => void
|
|
79
|
+
) => ActionDragChangeResult
|
|
61
80
|
|
|
62
81
|
/**
|
|
63
82
|
* A drag action describes when and how to handle a drag event.
|
|
@@ -70,12 +89,6 @@ export interface DragChangeHandler {
|
|
|
70
89
|
export interface IDragAction {
|
|
71
90
|
/** A unique name for your action. */
|
|
72
91
|
name: string
|
|
73
|
-
/**
|
|
74
|
-
* Called when the drag coordinates change (during any event). Should return true to allow the edges to be moved, or false to prevent it.
|
|
75
|
-
*
|
|
76
|
-
* Can be used to save some context/info to later apply safely during onDragApply.
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
92
|
onDragChange: DragChangeHandler
|
|
80
93
|
/**
|
|
81
94
|
*
|
|
@@ -103,5 +116,62 @@ export interface IDragAction {
|
|
|
103
116
|
*
|
|
104
117
|
* You should reset your state here.
|
|
105
118
|
*/
|
|
106
|
-
cancel(): void
|
|
119
|
+
cancel(e: PointerEvent | KeyboardEvent | undefined, state: DragState): void
|
|
120
|
+
/**
|
|
121
|
+
* Plugins should implement some basic debug logs by calling {@link DragActionHandler.debugState } at least before and after applying actions in onDragApply. Debug can be a string because it can be an object key to filter on (see the debugState function).
|
|
122
|
+
*
|
|
123
|
+
*
|
|
124
|
+
* Calls look like this usually, where this.state is the plugin state:
|
|
125
|
+
* ```ts
|
|
126
|
+
* DragActionHandler.debugState(this.name, "before", state, this.state, this.debug)
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
debug: boolean | string
|
|
130
|
+
/**
|
|
131
|
+
* The action handler will call this regardless of whether the action is active or not.
|
|
132
|
+
*
|
|
133
|
+
* Can be used by actions to return display hints.
|
|
134
|
+
*
|
|
135
|
+
* Actions should keep the state of the hints locally and update them in canHandlerRequest/onDrag*, etc. and only use this to return the state of the actions, not update them as that could become expensive.
|
|
136
|
+
*/
|
|
137
|
+
// todo think of a better way to do this, don't like that the action handler has to construct a bunch of objects on every change
|
|
138
|
+
getTextHints(type: "start" | "move" | "end"): {
|
|
139
|
+
/** Hint texts to display regarding the action state/usage. Undefined means no hint. */
|
|
140
|
+
actions?: string[]
|
|
141
|
+
/** Error texts/hints to display when the action produces an error. */
|
|
142
|
+
errors?: string[]
|
|
143
|
+
}
|
|
107
144
|
}
|
|
145
|
+
export type EdgeDragStartData = { edge?: Edge, intersection?: IntersectionEntry }
|
|
146
|
+
export type FrameDragStartData = { frameId: FrameId }
|
|
147
|
+
|
|
148
|
+
// drag start overloads for triggering dragsj
|
|
149
|
+
export type DragStartFn = {
|
|
150
|
+
(e: PointerEvent, type: "edge", data: EdgeDragStartData): void
|
|
151
|
+
(e: PointerEvent, type: "frame", data: FrameDragStartData): void
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface UseFramesContext {
|
|
155
|
+
dragStart: DragStartFn
|
|
156
|
+
dragMove: (e: PointerEvent) => void
|
|
157
|
+
dragEnd: (e?: PointerEvent, options?: { apply?: boolean }) => void
|
|
158
|
+
cancel: () => void
|
|
159
|
+
dragDirections: Ref<Record<Orientation, Direction | undefined>>
|
|
160
|
+
dragPoint: Ref<Point | undefined>
|
|
161
|
+
isDragging: Ref<false | "frame" | "edge">
|
|
162
|
+
draggingEdges: Ref<Edge[]>
|
|
163
|
+
draggingIntersection: Ref<IntersectionEntry | undefined>
|
|
164
|
+
visualEdges: Ref<Edge[]>
|
|
165
|
+
touchingFrames: Ref<Record<string, LayoutFrame>[]>
|
|
166
|
+
touchingFramesArrays: Ref<LayoutFrame[][]>
|
|
167
|
+
frames: ComputedRef<Record<string, LayoutFrame>>
|
|
168
|
+
dragHoveredFrame: ComputedRef<LayoutFrame | undefined>
|
|
169
|
+
intersections: ComputedRef<IntersectionEntry[]>
|
|
170
|
+
isDraggingFromWindowEdge: Ref<boolean>
|
|
171
|
+
forceRecalculateEdges: () => void
|
|
172
|
+
state: ComputedRef<DragState>
|
|
173
|
+
frameDragFrameId: Ref<FrameId | undefined>
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
export const dragContextInjectionKey = Symbol("dragContext") as InjectionKey<UseFramesContext>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the clip-path polygon for a zone's side. Ends the shape at a 45° angle.
|
|
3
|
+
*
|
|
4
|
+
* e.g. for a right zone, it looks like it's cutting the top and bottom left corners.
|
|
5
|
+
*
|
|
6
|
+
* Accepts scaled coordinates.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { DragZone } from "../types/index.js"
|
|
10
|
+
|
|
11
|
+
export function createZoneSideClipPath(
|
|
12
|
+
zone: DragZone,
|
|
13
|
+
{ frameEdgePx, windowEdgePx }: { frameEdgePx: number, windowEdgePx: number }
|
|
14
|
+
): string | undefined {
|
|
15
|
+
const side = zone.side
|
|
16
|
+
const thicknessPx = zone.type === "window" ? windowEdgePx : frameEdgePx
|
|
17
|
+
const pxLength = zone.side === "center"
|
|
18
|
+
? 0
|
|
19
|
+
: zone.side === "right" || zone.side === "left"
|
|
20
|
+
? zone.pxHeight
|
|
21
|
+
: zone.pxWidth
|
|
22
|
+
|
|
23
|
+
if (side === "center") return undefined
|
|
24
|
+
|
|
25
|
+
const t = thicknessPx
|
|
26
|
+
const l = pxLength
|
|
27
|
+
|
|
28
|
+
if (side === "bottom")
|
|
29
|
+
return `polygon(${t}px 0px, ${l - t}px 0px, ${l}px ${t}px, 0px ${t}px)`
|
|
30
|
+
|
|
31
|
+
if (side === "left")
|
|
32
|
+
return `polygon(0px 0px, ${t}px ${t}px, ${t}px ${l - t}px, 0px ${l}px)`
|
|
33
|
+
|
|
34
|
+
if (side === "top")
|
|
35
|
+
return `polygon(0px 0px, ${t}px ${t}px, ${l - t}px ${t}px, ${l}px 0px)`
|
|
36
|
+
|
|
37
|
+
if (side === "right")
|
|
38
|
+
return `polygon(${t}px 0px, 0px ${t}px, 0px ${l - t}px, ${t}px ${l}px)`
|
|
39
|
+
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
@@ -4,22 +4,28 @@ import { isEdgeParallel } from "./isEdgeParallel.js"
|
|
|
4
4
|
|
|
5
5
|
import type { Edge, Orientation } from "../types/index.js"
|
|
6
6
|
|
|
7
|
-
export function doEdgesOverlap(
|
|
7
|
+
export function doEdgesOverlap(
|
|
8
|
+
edgeA: Edge,
|
|
9
|
+
edgeB: Edge,
|
|
10
|
+
dir?: Orientation,
|
|
11
|
+
/** If you pass inclusive true it will also match edges that start where the other edge ends or vice versa. */
|
|
12
|
+
inclusive: boolean = false
|
|
13
|
+
): boolean {
|
|
8
14
|
dir ??= getEdgeOrientation(edgeA)
|
|
9
15
|
if (!isEdgeParallel(edgeA, edgeB)) return false
|
|
10
16
|
if (dir === "horizontal") {
|
|
11
17
|
if (edgeA.startY !== edgeB.startY) return false
|
|
12
18
|
const leftMost = edgeA.startX <= edgeB.startX ? edgeA : edgeB
|
|
13
19
|
const rightMost = edgeB === leftMost ? edgeA : edgeB
|
|
14
|
-
const startOverlaps = inRange(leftMost.endX, rightMost.startX, rightMost.endX)
|
|
15
|
-
const endOverlaps = inRange(rightMost.startX, leftMost.startX, leftMost.endX)
|
|
20
|
+
const startOverlaps = inRange(leftMost.endX, rightMost.startX, rightMost.endX, inclusive)
|
|
21
|
+
const endOverlaps = inRange(rightMost.startX, leftMost.startX, leftMost.endX, inclusive)
|
|
16
22
|
return startOverlaps || endOverlaps
|
|
17
23
|
} else {
|
|
18
24
|
if (edgeA.startX !== edgeB.startX) return false
|
|
19
25
|
const topMost = edgeA.startY <= edgeB.startY ? edgeA : edgeB
|
|
20
26
|
const bottomMost = edgeB === topMost ? edgeA : edgeB
|
|
21
|
-
const startOverlaps = inRange(topMost.endY, bottomMost.startY, bottomMost.endY)
|
|
22
|
-
const endOverlaps = inRange(bottomMost.startY, topMost.startY, topMost.endY)
|
|
27
|
+
const startOverlaps = inRange(topMost.endY, bottomMost.startY, bottomMost.endY, inclusive)
|
|
28
|
+
const endOverlaps = inRange(bottomMost.startY, topMost.startY, topMost.endY, inclusive)
|
|
23
29
|
return startOverlaps || endOverlaps
|
|
24
30
|
}
|
|
25
31
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
|
+
import type { LayoutWindow } from "../types/index.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compute the inner boundaries of a docked region by looking at already docked frames.
|
|
6
|
+
*
|
|
7
|
+
* For example, if A, B, and C are docked, this returns the area of C.
|
|
8
|
+
* ┌─────────┐
|
|
9
|
+
* │A* │
|
|
10
|
+
* ├────┬────┤
|
|
11
|
+
* │B* │C │
|
|
12
|
+
* ├────┴────┤
|
|
13
|
+
* │D* │
|
|
14
|
+
* └─────────┘
|
|
15
|
+
*/
|
|
16
|
+
export function getDockBoundaries(win: LayoutWindow): {
|
|
17
|
+
minX: number
|
|
18
|
+
maxX: number
|
|
19
|
+
minY: number
|
|
20
|
+
maxY: number
|
|
21
|
+
} {
|
|
22
|
+
let minX = 0
|
|
23
|
+
let maxX = settings.maxInt
|
|
24
|
+
let minY = 0
|
|
25
|
+
let maxY = settings.maxInt
|
|
26
|
+
|
|
27
|
+
for (const f of Object.values(win.frames)) {
|
|
28
|
+
if (f.docked === "left") minX = Math.max(minX, f.x + f.width)
|
|
29
|
+
if (f.docked === "right") maxX = Math.min(maxX, f.x)
|
|
30
|
+
if (f.docked === "top") minY = Math.max(minY, f.y + f.height)
|
|
31
|
+
if (f.docked === "bottom") maxY = Math.min(maxY, f.y)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { minX, maxX, minY, maxY }
|
|
35
|
+
}
|
|
36
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
2
|
+
|
|
3
|
+
import type { Edge } from "../types/index.js"
|
|
4
|
+
|
|
5
|
+
export function getEdgeLength(edge: Edge): number {
|
|
6
|
+
const orientation = getEdgeOrientation(edge)
|
|
7
|
+
return orientation === "horizontal"
|
|
8
|
+
? Math.abs(edge.endX - edge.startX)
|
|
9
|
+
: Math.abs(edge.endY - edge.startY)
|
|
10
|
+
}
|
|
@@ -6,7 +6,7 @@ import { edgeToPoints } from "./edgeToPoints.js"
|
|
|
6
6
|
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
7
7
|
import { inRange } from "./inRange.js"
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { settings } from "../settings.js"
|
|
10
10
|
import type {
|
|
11
11
|
Edge, IntersectionEntry,
|
|
12
12
|
Orientation,
|
|
@@ -25,7 +25,7 @@ export function getIntersections(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const points: IntersectionEntry[] = []
|
|
28
|
-
const maxInt =
|
|
28
|
+
const maxInt = settings.maxInt
|
|
29
29
|
for (const x of keys(intersections)) {
|
|
30
30
|
for (const y of keys(intersections[x])) {
|
|
31
31
|
// careful, x and y are really strings
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
2
|
import type {
|
|
3
3
|
IntersectionEntry, PointCss
|
|
4
4
|
} from "../types/index.js"
|
|
@@ -13,7 +13,7 @@ export function getIntersectionsCss(entries: IntersectionEntry[],
|
|
|
13
13
|
shiftAmount?: string
|
|
14
14
|
} = {}
|
|
15
15
|
): (PointCss & { _shifted?: true }) [] {
|
|
16
|
-
const unscale =
|
|
16
|
+
const unscale = settings.maxInt / 100
|
|
17
17
|
return entries.map(entry => {
|
|
18
18
|
const point = entry.point
|
|
19
19
|
const css = {
|
|
@@ -2,7 +2,7 @@ import { clampNumber } from "./clampNumber.js"
|
|
|
2
2
|
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
3
3
|
import { getResizeLimit } from "./getResizeLimit.js"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { settings } from "../settings.js"
|
|
6
6
|
import type {
|
|
7
7
|
Direction,
|
|
8
8
|
Edge, LayoutFrame,
|
|
@@ -14,7 +14,7 @@ export function getMoveEdgeInfo(
|
|
|
14
14
|
edge: Edge,
|
|
15
15
|
/** Window scaled/snaped position. See {@link toWindowCoord} */
|
|
16
16
|
position: Point,
|
|
17
|
-
margin: Size =
|
|
17
|
+
margin: Size = settings.minSizeScaled,
|
|
18
18
|
clamp = true
|
|
19
19
|
): {
|
|
20
20
|
x: number
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { castType } from "@alanscodelog/utils/castType"
|
|
2
2
|
import { keys } from "@alanscodelog/utils/keys"
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { settings } from "../settings.js"
|
|
5
5
|
import type {
|
|
6
6
|
Direction,
|
|
7
7
|
Edge, ExtendedDirection, LayoutFrame
|
|
@@ -51,7 +51,7 @@ export function getResizeLimit<TDir extends ExtendedDirection>(
|
|
|
51
51
|
for (const key of keys(limits)) {
|
|
52
52
|
// this happens when we drag window edges
|
|
53
53
|
if (limits[key] === -Infinity) limits[key] = 0
|
|
54
|
-
if (limits[key] === Infinity) limits[key] =
|
|
54
|
+
if (limits[key] === Infinity) limits[key] = settings.maxInt
|
|
55
55
|
|
|
56
56
|
limits[key]! += (dir === "left" || dir === "up" ? margin : -margin)
|
|
57
57
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
2
|
import type { BaseSquare } from "../types/index.js"
|
|
3
3
|
|
|
4
4
|
export function getShapeSquareCss(
|
|
@@ -10,7 +10,7 @@ export function getShapeSquareCss(
|
|
|
10
10
|
width: string
|
|
11
11
|
height: string
|
|
12
12
|
} {
|
|
13
|
-
const unscale =
|
|
13
|
+
const unscale = settings.maxInt / 100
|
|
14
14
|
const css = {
|
|
15
15
|
x: `${obj.x / unscale}%`,
|
|
16
16
|
y: `${obj.y / unscale}%`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { settings } from "../settings.js"
|
|
4
4
|
import type {
|
|
5
5
|
Edge,
|
|
6
6
|
EdgeCss } from "../types/index.js"
|
|
@@ -20,7 +20,7 @@ export function getVisualEdgeCss(
|
|
|
20
20
|
} = {}
|
|
21
21
|
): EdgeCss {
|
|
22
22
|
const dir = getEdgeOrientation(edge)
|
|
23
|
-
const unscale =
|
|
23
|
+
const unscale = settings.maxInt / 100
|
|
24
24
|
const w = (edge.endX - edge.startX) / unscale
|
|
25
25
|
const h = (edge.endY - edge.startY) / unscale
|
|
26
26
|
const width = dir === "vertical" ? edgeWidth : `${w}%`
|
|
@@ -10,7 +10,7 @@ import { inRange } from "./inRange.js"
|
|
|
10
10
|
import { splitEdge } from "./splitEdge.js"
|
|
11
11
|
import { unionEdges } from "./unionEdges.js"
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { settings } from "../settings.js"
|
|
14
14
|
import type {
|
|
15
15
|
Edge,
|
|
16
16
|
Intersections,
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
} from "../types/index.js"
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Returns the "visual" edges that can be dragged.
|
|
21
|
+
* Returns the "visual" edges that can be dragged (so will not return edges for collapsed frames without some area).
|
|
22
22
|
*
|
|
23
23
|
* Visual edges are a combination of all edges shared by frames that must be moved together.
|
|
24
24
|
*
|
|
@@ -75,8 +75,9 @@ export function getVisualEdges<T extends boolean = false>(
|
|
|
75
75
|
const intersections: Intersections = {
|
|
76
76
|
// x: {y: count}
|
|
77
77
|
}
|
|
78
|
-
const max =
|
|
78
|
+
const max = settings.maxInt
|
|
79
79
|
for (const frame of frames) {
|
|
80
|
+
if (frame.collapsed && (frame.width === 0 || frame.height === 0)) continue
|
|
80
81
|
const frameEdges = frameToEdges(frame)
|
|
81
82
|
addPointsToIntersection(intersections, Object.values(frameToPoints(frame)))
|
|
82
83
|
|
|
@@ -94,7 +95,7 @@ export function getVisualEdges<T extends boolean = false>(
|
|
|
94
95
|
if (containsEdge(edge, e, dir)) {
|
|
95
96
|
continue secondlabel
|
|
96
97
|
}
|
|
97
|
-
if (doEdgesOverlap(e, edge, dir)) {
|
|
98
|
+
if (doEdgesOverlap(e, edge, dir, true)) {
|
|
98
99
|
indexes.push(i)
|
|
99
100
|
edges.push(e)
|
|
100
101
|
}
|
|
@@ -15,6 +15,7 @@ export { containsEdge } from "./containsEdge.js"
|
|
|
15
15
|
export { convertLayoutWindowToWorkspace } from "./convertLayoutWindowToWorkspace.js"
|
|
16
16
|
export { copySize } from "./copySize.js"
|
|
17
17
|
export { createEdge } from "./createEdge.js"
|
|
18
|
+
export { createZoneSideClipPath } from "./createZoneSideClipPath.js"
|
|
18
19
|
export { dirToOrientation } from "./dirToOrientation.js"
|
|
19
20
|
export { dirToSide } from "./dirToSide.js"
|
|
20
21
|
export { doEdgesOverlap } from "./doEdgesOverlap.js"
|
|
@@ -24,6 +25,7 @@ export { findDraggableEdge } from "./findDraggableEdge.js"
|
|
|
24
25
|
export { findFrameDraggableEdges } from "./findFrameDraggableEdges.js"
|
|
25
26
|
export { frameToEdges } from "./frameToEdges.js"
|
|
26
27
|
export { frameToPoints } from "./frameToPoints.js"
|
|
28
|
+
export { getEdgeLength } from "./getEdgeLength.js"
|
|
27
29
|
export { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
28
30
|
export { getEdgeSharedDirection } from "./getEdgeSharedDirection.js"
|
|
29
31
|
export { getEdgeSide } from "./getEdgeSide.js"
|
|
@@ -55,6 +57,7 @@ export { numberToScaledPercent } from "./numberToScaledPercent.js"
|
|
|
55
57
|
export { numberToScaledSize } from "./numberToScaledSize.js"
|
|
56
58
|
export { oppositeSide } from "./oppositeSide.js"
|
|
57
59
|
export { resizeByEdge } from "./resizeByEdge.js"
|
|
60
|
+
export { scaledPointToPx } from "./scaledPointToPx.js"
|
|
58
61
|
export { sideToDirection } from "./sideToDirection.js"
|
|
59
62
|
export { sideToOrientation } from "./sideToOrientation.js"
|
|
60
63
|
export { splitEdge } from "./splitEdge.js"
|
|
@@ -62,3 +65,4 @@ export { toCoord } from "./toCoord.js"
|
|
|
62
65
|
export { toId } from "./toId.js"
|
|
63
66
|
export { toWindowCoord } from "./toWindowCoord.js"
|
|
64
67
|
export { unionEdges } from "./unionEdges.js"
|
|
68
|
+
export { updateWindowWithEvent } from "./updateWindowSizeWithEvent.js"
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
2
|
-
import { isEdgeParallel } from "./isEdgeParallel.js"
|
|
3
2
|
|
|
4
3
|
import type { Edge, Orientation } from "../types/index.js"
|
|
5
4
|
|
|
6
5
|
export function isEdgeEqual(edgeA: Edge, edgeB: Edge, orientation?: Orientation): boolean {
|
|
7
6
|
orientation ??= getEdgeOrientation(edgeA)
|
|
8
|
-
if (!isEdgeParallel(edgeA, edgeB)) return false
|
|
9
7
|
if (orientation === "horizontal") {
|
|
10
|
-
return edgeA.startY === edgeB.startY && edgeB.endY === edgeA.endY
|
|
8
|
+
return edgeA.startX === edgeB.startX && edgeB.endX === edgeA.endX && edgeA.startY === edgeB.startY && edgeB.endY === edgeA.endY
|
|
11
9
|
} else {
|
|
12
|
-
return edgeA.startX === edgeB.startX && edgeB.endX === edgeA.endX
|
|
10
|
+
return edgeA.startX === edgeB.startX && edgeB.endX === edgeA.endX && edgeA.startY === edgeB.startY && edgeB.endY === edgeA.endY
|
|
13
11
|
}
|
|
14
12
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getEdgeOrientation } from "./getEdgeOrientation.js"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { settings } from "../settings.js"
|
|
4
4
|
import type { Edge, Orientation } from "../types/index.js"
|
|
5
5
|
|
|
6
6
|
export function isWindowEdge(edge: Edge, edgeDirection?: Orientation): boolean {
|
|
7
7
|
edgeDirection ??= getEdgeOrientation(edge)
|
|
8
|
-
const max =
|
|
8
|
+
const max = settings.maxInt
|
|
9
9
|
return (edgeDirection === "vertical" && (edge.startX === 0 || edge.startX === max))
|
|
10
10
|
|| (edgeDirection === "horizontal" && (edge.startY === 0 || edge.startY === max))
|
|
11
11
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
2
|
import type { Point } from "../types/index.js"
|
|
3
3
|
|
|
4
4
|
export function isWindowEdgePoint(point: Point): boolean {
|
|
5
|
-
const max =
|
|
5
|
+
const max = settings.maxInt
|
|
6
6
|
return (point.x === 0 || point.x === max)
|
|
7
7
|
|| (point.y === 0 || point.y === max)
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getMoveEdgeInfo } from "./getMoveEdgeInfo.js"
|
|
2
2
|
import { resizeByEdge } from "./resizeByEdge.js"
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { settings } from "../settings.js"
|
|
5
5
|
import type {
|
|
6
6
|
Edge, LayoutFrame,
|
|
7
7
|
Point,
|
|
@@ -13,7 +13,7 @@ export function moveEdge(
|
|
|
13
13
|
edge: Edge | undefined,
|
|
14
14
|
/** Window scaled/snaped position. See {@link toWindowCoord} */
|
|
15
15
|
position: Point,
|
|
16
|
-
margin: Size =
|
|
16
|
+
margin: Size = settings.minSizeScaled
|
|
17
17
|
): void {
|
|
18
18
|
if (!edge || !touchingFrames) return
|
|
19
19
|
const { pos, dir, distance } = getMoveEdgeInfo(touchingFrames, edge, position, margin)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { snapNumber } from "@alanscodelog/utils/snapNumber"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { settings } from "../settings.js"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Given a number (e.g. the x coordinate in px), and the max value it could be (e.g. the max width of it's container in px), returns it's position as a scaled percentage.
|
|
6
|
+
* Given a number (e.g. the x coordinate in px), and the max value it could be (e.g. the max width of it's container in px), returns it's position as a rounded scaled percentage.
|
|
7
7
|
*
|
|
8
8
|
* ```
|
|
9
9
|
* -----------
|
|
@@ -14,6 +14,6 @@ import { getMaxInt } from "../settings.js"
|
|
|
14
14
|
* // returns 50 / 100 * scale or 50000 (50%)
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export function numberToScaledPercent(num: number, max: number, scale: number =
|
|
17
|
+
export function numberToScaledPercent(num: number, max: number, scale: number = settings.maxInt): number {
|
|
18
18
|
return snapNumber((num / max) * scale, 1)
|
|
19
19
|
}
|
|
@@ -2,13 +2,13 @@ import { unreachable } from "@alanscodelog/utils/unreachable"
|
|
|
2
2
|
|
|
3
3
|
import { numberToScaledPercent } from "./numberToScaledPercent.js"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { settings } from "../settings.js"
|
|
6
6
|
import type { LayoutWindow, PxSize, Size } from "../types/index.js"
|
|
7
7
|
|
|
8
8
|
export function numberToScaledSize(
|
|
9
9
|
win: LayoutWindow,
|
|
10
10
|
size: PxSize | number,
|
|
11
|
-
scale: number =
|
|
11
|
+
scale: number = settings.maxInt
|
|
12
12
|
): Size {
|
|
13
13
|
const scaledSize = {
|
|
14
14
|
width: numberToScaledPercent(
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
|
+
import type { LayoutFrame } from "../types/index.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rotates the list of frames given by 90, 180, or 270 degrees around the 50% center.
|
|
6
|
+
*
|
|
7
|
+
* Used mainly in testing to catch issues with incorrect handling of the same scenario in different orientations.
|
|
8
|
+
*/
|
|
9
|
+
export function rotateLayout(frames: LayoutFrame[], rotation: 90 | 180 | 270) {
|
|
10
|
+
const sides: NonNullable<LayoutFrame["docked"]>[] = ["top", "right", "bottom", "left"]
|
|
11
|
+
const shift = rotation / 90
|
|
12
|
+
|
|
13
|
+
for (const frame of frames) {
|
|
14
|
+
const { x, y, width, height, docked } = frame
|
|
15
|
+
|
|
16
|
+
if (docked) {
|
|
17
|
+
const currentIndex = sides.indexOf(docked)
|
|
18
|
+
if (currentIndex !== -1) {
|
|
19
|
+
frame.docked = sides[(currentIndex + shift) % 4]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
switch (rotation) {
|
|
23
|
+
case 90:
|
|
24
|
+
frame.x = settings.maxInt - (y + height)
|
|
25
|
+
frame.y = x
|
|
26
|
+
frame.width = height
|
|
27
|
+
frame.height = width
|
|
28
|
+
break
|
|
29
|
+
case 180:
|
|
30
|
+
frame.x = settings.maxInt - (x + width)
|
|
31
|
+
frame.y = settings.maxInt - (y + height)
|
|
32
|
+
frame.width = width
|
|
33
|
+
frame.height = height
|
|
34
|
+
break
|
|
35
|
+
case 270:
|
|
36
|
+
frame.x = y
|
|
37
|
+
frame.y = settings.maxInt - (x + width)
|
|
38
|
+
frame.width = height
|
|
39
|
+
frame.height = width
|
|
40
|
+
break
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Unknown rotation ${rotation}`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { settings } from "../settings.js"
|
|
2
|
+
|
|
3
|
+
/** Convert a scaled point to pixel coords for a given window. */
|
|
4
|
+
export function scaledPointToPx(
|
|
5
|
+
point: { x: number, y: number },
|
|
6
|
+
win: { pxWidth: number, pxHeight: number, pxX: number, pxY: number },
|
|
7
|
+
scale: number = settings.maxInt
|
|
8
|
+
): { x: number, y: number } {
|
|
9
|
+
return {
|
|
10
|
+
x: point.x / scale * win.pxWidth + win.pxX,
|
|
11
|
+
y: point.y / scale * win.pxHeight + win.pxY
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -2,13 +2,13 @@ import { snapNumber } from "@alanscodelog/utils/snapNumber"
|
|
|
2
2
|
|
|
3
3
|
import { numberToScaledPercent } from "./numberToScaledPercent.js"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { settings } from "../settings.js"
|
|
6
6
|
import type { LayoutWindow, Point } from "../types/index.js"
|
|
7
7
|
|
|
8
8
|
export function toWindowCoord(
|
|
9
9
|
win: LayoutWindow,
|
|
10
10
|
e: Pick<PointerEvent, "clientX" | "clientY">,
|
|
11
|
-
snapAmount: Point =
|
|
11
|
+
snapAmount: Point = settings.snapPointScaled
|
|
12
12
|
): Point {
|
|
13
13
|
const x = numberToScaledPercent((e.clientX - win.pxX), win.pxWidth)
|
|
14
14
|
const y = numberToScaledPercent((e.clientY - win.pxY), win.pxHeight)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { LAYOUT_ERROR, type LayoutChange, type LayoutWindow } from "../types/index.js"
|
|
2
|
+
import { KnownError } from "../utils/KnownError.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* Most actions that change the layout will return a LayoutChange object without mutating the window.
|
|
7
|
+
*
|
|
8
|
+
* This function applies the changes returned by them.
|
|
9
|
+
*
|
|
10
|
+
* Mutates the frame positions in the window given.
|
|
11
|
+
*/
|
|
12
|
+
export function applyFrameChanges(
|
|
13
|
+
win: LayoutWindow,
|
|
14
|
+
change: LayoutChange<any>
|
|
15
|
+
): void {
|
|
16
|
+
for (const frame of change.modified) {
|
|
17
|
+
const target = win.frames[frame.id]
|
|
18
|
+
if (!target) {
|
|
19
|
+
throw new KnownError(LAYOUT_ERROR.INVALID_ID, `Frame ${frame.id} not found in window ${win.id}`, { id: frame.id })
|
|
20
|
+
}
|
|
21
|
+
if ("docked" in frame) { target.docked = frame.docked }
|
|
22
|
+
if ("collapsed" in frame) { target.collapsed = frame.collapsed }
|
|
23
|
+
target.x = frame.x
|
|
24
|
+
target.y = frame.y
|
|
25
|
+
target.width = frame.width
|
|
26
|
+
target.height = frame.height
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const frame of change.created) {
|
|
30
|
+
if (win.frames[frame.id]) {
|
|
31
|
+
throw new KnownError(LAYOUT_ERROR.ID_ALREADY_EXISTS, `Frame ${frame.id} already exists in window ${win.id}`, { id: frame.id })
|
|
32
|
+
}
|
|
33
|
+
win.frames[frame.id] = frame
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const frame of change.deleted) {
|
|
37
|
+
delete win.frames[frame.id]
|
|
38
|
+
}
|
|
39
|
+
}
|