-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathredistribute_panel_sizes.ts
More file actions
113 lines (101 loc) · 4.55 KB
/
redistribute_panel_sizes.ts
File metadata and controls
113 lines (101 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ░░░░░░░░▄▀░█▀▄░█▀▀░█▀▀░█░█░█░░░█▀█░█▀▄░░░░░█░░░█▀█░█░█░█▀█░█░█░▀█▀░▀▄░░░░░░░░
// ░░░░░░░▀▄░░█▀▄░█▀▀░█░█░█░█░█░░░█▀█░█▀▄░▀▀▀░█░░░█▀█░░█░░█░█░█░█░░█░░░▄▀░░░░░░░
// ░░░░░░░░░▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀░▀░▀░▀░░░░░▀▀▀░▀░▀░░▀░░▀▀▀░▀▀▀░░▀░░▀░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ * Copyright (c) 2026, the Regular Layout Authors. This file is part * ┃
// ┃ * of the Regular Layout library, distributed under the terms of the * ┃
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import { DEFAULT_PHYSICS } from "./constants.ts";
import type { Layout } from "./types.ts";
/**
* Adjusts panel sizes during a drag operation on a divider.
*
* The `delta` is distributed proportionally among affected panels, maintaining
* the sum:
*
* - Panels before and including the path index shrink by delta.
* - Panels after the path index grow by delta.
*
* @param panel - The root layout tree to modify.
* @param path - Path to the divider being dragged (identifies which split panel
* to resize).
* @param delta - Amount to resize, as a fraction (0-1). Positive values grow
* panels before the divider, negative values shrink them.
* @returns A new layout tree with updated sizes (original is not mutated).
* ```
*/
export function redistribute_panel_sizes(
panel: Layout,
path: number[],
delta: number | undefined,
physics = DEFAULT_PHYSICS,
): Layout {
// Clone the entire panel structure
const result = structuredClone(panel);
// Find the orientation of the insertion panel,
// and scale the delta on the respective axis if aligned.
let current: Layout = result;
const deltas = { horizontal: delta || 0, vertical: delta || 0 };
for (let i = 0; i < path.length - 1; i++) {
if (current.type === "split-panel") {
deltas[current.orientation] /= current.sizes[path[i]];
current = current.children[path[i]];
}
}
// Apply the redistribution at the final path index
if (current.type === "split-panel") {
if (delta === undefined) {
current.sizes = current.sizes.map((_) => 1 / current.sizes.length);
} else {
const delta = deltas[current.orientation];
const index = path[path.length - 1];
// It would be fun to remove this condition.
if (index < current.sizes.length - 1) {
current.sizes = add_and_redistribute(
physics,
current.sizes,
index,
delta,
);
}
}
}
return result;
}
function add_and_redistribute(
physics: typeof DEFAULT_PHYSICS,
arr: number[],
index: number,
delta: number,
): number[] {
const result = [...arr];
let before_total = 0;
for (let i = 0; i <= index; i++) {
before_total += arr[i];
}
let after_total = 0;
for (let i = index + 1; i < arr.length; i++) {
after_total += arr[i];
}
// Clamp `delta` to prevent redistributing either side to 0.
delta =
Math.sign(delta) *
Math.min(
Math.abs(delta),
(1 - physics.MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD) *
(delta > 0 ? before_total : after_total),
);
// Redistribute elements
for (let i = 0; i <= index; i++) {
const proportion = arr[i] / before_total;
result[i] = arr[i] - delta * proportion;
}
for (let i = index + 1; i < arr.length; i++) {
const proportion = arr[i] / after_total;
result[i] = arr[i] + delta * proportion;
}
return result;
}