atagen

monolith

public
Star0
Watch0
25731952c6b8906c4b8e0ec539fdcbdd24cb9276
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/layout/src/tree.rsRust902 lines29.6 KB
1
use monolith_planner::Rect;
2
use slotmap::{SlotMap, new_key_type};
3
use std::collections::HashMap;
4
use std::hash::Hash;
5
6
new_key_type! { pub struct NodeId; }
7
8
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
11
pub enum Axis {
12
    Horizontal,
13
    Vertical,
14
}
15
16
impl Axis {
17
    pub fn other(self) -> Self {
18
        match self {
19
            Self::Horizontal => Self::Vertical,
20
            Self::Vertical => Self::Horizontal,
21
        }
22
    }
23
24
    fn index(self) -> usize {
25
        match self {
26
            Self::Horizontal => 0,
27
            Self::Vertical => 1,
28
        }
29
    }
30
}
31
32
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
33
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
35
pub enum Dir {
36
    Left,
37
    Right,
38
    Up,
39
    Down,
40
}
41
42
impl Dir {
43
    pub fn axis(self) -> Axis {
44
        match self {
45
            Self::Left | Self::Right => Axis::Horizontal,
46
            Self::Up | Self::Down => Axis::Vertical,
47
        }
48
    }
49
50
    pub fn forward(self) -> bool {
51
        matches!(self, Self::Right | Self::Down)
52
    }
53
}
54
55
const MIN_SHARE: f64 = 0.05;
56
57
/// A window's width and height relative to its neighbours'.
58
type Size = [f64; 2];
59
60
#[derive(Clone, Debug)]
61
enum Kind<W> {
62
    Leaf(W, Size),
63
    Container {
64
        axis: Axis,
65
        children: Vec<NodeId>,
66
        expanded: Option<NodeId>,
67
    },
68
}
69
70
#[derive(Clone, Debug)]
71
struct Node<W> {
72
    parent: Option<NodeId>,
73
    kind: Kind<W>,
74
}
75
76
/// One output's tiling tree. Every tiled window of every tag lives here, the
77
/// caller's visibility filter decides which ones take space.
78
///
79
/// Children run on the axis opposite their parent. Containers hold at least
80
/// two children, hidden ones included, and a container left with one child
81
/// is replaced by it.
82
#[derive(Clone, Debug)]
83
pub struct Tree<W> {
84
    nodes: SlotMap<NodeId, Node<W>>,
85
    root: Option<NodeId>,
86
    leaves: HashMap<W, NodeId>,
87
    stack: Axis,
88
}
89
90
impl<W: Copy + Eq + Hash> Default for Tree<W> {
91
    fn default() -> Self {
92
        Self {
93
            nodes: SlotMap::with_key(),
94
            root: None,
95
            leaves: HashMap::new(),
96
            stack: Axis::Vertical,
97
        }
98
    }
99
}
100
101
impl<W: Copy + Eq + Hash> Tree<W> {
102
    /// The axis tag rows stack along.
103
    pub fn stack_axis(&self) -> Axis {
104
        self.stack
105
    }
106
107
    pub fn contains(&self, w: W) -> bool {
108
        self.leaves.contains_key(&w)
109
    }
110
111
    pub fn is_empty(&self) -> bool {
112
        self.root.is_none()
113
    }
114
115
    pub fn windows(&self) -> impl Iterator<Item = W> + '_ {
116
        self.leaves.keys().copied()
117
    }
118
119
    /// Inserts `w` as the next sibling of `anchor`, or as a new row if
120
    /// `anchor` is not in the tree.
121
    pub fn insert_after(&mut self, w: W, anchor: W) {
122
        let Some(&a) = self.leaves.get(&anchor) else {
123
            return self.insert_row(w);
124
        };
125
        match self.position(a) {
126
            Some((p, i)) if Some(p) == self.root && self.axis(p) == Some(self.stack) => {
127
                let n = self.new_leaf(w, self.size(a));
128
                self.unlink(p, i);
129
                let c = self.new_container(self.stack.other());
130
                self.attach(c, 0, a);
131
                self.attach(c, 1, n);
132
                self.attach(p, i, c);
133
                self.reveal(n, true);
134
            }
135
            Some((p, i)) => {
136
                let n = self.new_leaf(w, self.size(p));
137
                self.attach(p, i + 1, n);
138
                self.reveal(n, true);
139
            }
140
            None => {
141
                let n = self.new_leaf(w, self.size(a));
142
                let c = self.new_container(self.stack.other());
143
                self.attach(c, 0, a);
144
                self.attach(c, 1, n);
145
                self.root = Some(c);
146
            }
147
        }
148
    }
149
150
    /// Inserts `w` after `anchor` by splitting `anchor` along `axis`. They
151
    /// share the space `anchor` had, and its siblings keep theirs.
152
    pub fn insert_split(&mut self, w: W, anchor: W, axis: Axis) {
153
        let Some(&a) = self.leaves.get(&anchor) else {
154
            return self.insert_row(w);
155
        };
156
        let size = self.size(a);
157
        let n = self.new_leaf(w, size);
158
        match self.position(a) {
159
            Some((p, i)) if self.axis(p) == Some(axis) => {
160
                self.halve(a, axis);
161
                self.halve(n, axis);
162
                self.attach(p, i + 1, n);
163
            }
164
            Some((p, i)) => {
165
                self.unlink(p, i);
166
                let c = self.new_container(axis);
167
                self.attach(c, 0, a);
168
                self.attach(c, 1, n);
169
                self.attach(p, i, c);
170
            }
171
            None => {
172
                let c = self.new_container(axis);
173
                self.attach(c, 0, a);
174
                self.attach(c, 1, n);
175
                self.root = Some(c);
176
            }
177
        }
178
        self.reveal(n, true);
179
    }
180
181
    fn halve(&mut self, leaf: NodeId, axis: Axis) {
182
        if let Kind::Leaf(_, size) = &mut self.nodes[leaf].kind {
183
            size[axis.index()] /= 2.0;
184
        }
185
    }
186
187
    /// Appends `w` as a row of its own along the stacking axis.
188
    pub fn insert_row(&mut self, w: W) {
189
        let size = self.root.map_or([1.0; 2], |r| self.size(r));
190
        let n = self.new_leaf(w, size);
191
        match self.root {
192
            None => self.root = Some(n),
193
            Some(r) if self.axis(r) == Some(self.stack) => {
194
                let end = self.children(r).len();
195
                self.attach(r, end, n);
196
            }
197
            Some(r) => {
198
                let c = self.new_container(self.stack);
199
                self.attach(c, 0, r);
200
                self.attach(c, 1, n);
201
                self.root = Some(c);
202
            }
203
        }
204
        self.reveal(n, true);
205
    }
206
207
    pub fn remove(&mut self, w: W) -> bool {
208
        let Some(n) = self.leaves.remove(&w) else {
209
            return false;
210
        };
211
        self.detach(n);
212
        self.nodes.remove(n);
213
        true
214
    }
215
216
    pub fn retain(&mut self, mut keep: impl FnMut(W) -> bool) {
217
        let gone: Vec<W> = self.windows().filter(|&w| !keep(w)).collect();
218
        for w in gone {
219
            self.remove(w);
220
        }
221
    }
222
223
    /// Moves a window one step in `dir`. Leaves swap slots with the next
224
    /// visible sibling, enter a sibling container, or step out beside their
225
    /// container. Hidden windows never move.
226
    pub fn move_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
227
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
228
            return false;
229
        };
230
        self.until_seen(&vis, |t| {
231
            let moved = t.move_node(n, dir, &vis, true);
232
            t.reveal(n, moved)
233
        })
234
    }
235
236
    /// Moves the container holding `w` as a rigid block. A window sitting
237
    /// directly in the root is its own block.
238
    pub fn move_container(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
239
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
240
            return false;
241
        };
242
        self.until_seen(&vis, |t| {
243
            let block = t.nodes[n]
244
                .parent
245
                .filter(|&p| Some(p) != t.root)
246
                .unwrap_or(n);
247
            let moved = t.move_node(block, dir, &vis, false);
248
            t.reveal(n, moved)
249
        })
250
    }
251
252
    /// Moves a window to the end of the next visible lane in `dir` among its
253
    /// siblings. A lone window there becomes a stack with it. A window with no
254
    /// sibling lane that way leaves its stack as `move_window` would, so it
255
    /// takes one press to step out and another to merge.
256
    pub fn merge_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
257
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
258
            return false;
259
        };
260
        self.until_seen(&vis, |t| {
261
            if let Some((p, i)) = t.position(n)
262
                && t.axis(p) == Some(dir.axis())
263
                && let Some(j) = t.next_shown(p, i, dir, &vis)
264
            {
265
                t.join_lane(n, p, j);
266
                return t.reveal(n, true);
267
            }
268
            let moved = t.move_node(n, dir, &vis, true);
269
            t.reveal(n, moved)
270
        })
271
    }
272
273
    /// Repeats `step` until the visible layout changes, or undoes it all when
274
    /// it never does. Steps around hidden windows otherwise ate keypresses
275
    /// and rearranged windows the user could not see.
276
    fn until_seen(
277
        &mut self,
278
        vis: &impl Fn(W) -> bool,
279
        mut step: impl FnMut(&mut Self) -> bool,
280
    ) -> bool {
281
        let seen = |t: &Self| -> Vec<(W, Rect)> {
282
            t.arrange(Rect::new(0.0, 0.0, 1000.0, 1000.0), 0.0, vis)
283
                .into_iter()
284
                .filter(|p| vis(p.0))
285
                .collect()
286
        };
287
        let same = |a: &[(W, Rect)], b: &[(W, Rect)]| {
288
            a.len() == b.len()
289
                && a.iter().all(|(v, r)| {
290
                    b.iter().any(|(w, s)| {
291
                        v == w
292
                            && [r.x - s.x, r.y - s.y, r.w - s.w, r.h - s.h]
293
                                .iter()
294
                                .all(|d| d.abs() < 1e-6)
295
                    })
296
                })
297
        };
298
        let before = self.clone();
299
        let start = seen(self);
300
        for _ in 0..=before.nodes.len() {
301
            if !step(self) {
302
                break;
303
            }
304
            if !same(&start, &seen(self)) {
305
                return true;
306
            }
307
        }
308
        *self = before;
309
        false
310
    }
311
312
    /// Undoes any expansion along `leaf`'s ancestry that favours another
313
    /// child, once it has `moved` or arrived. An expanded container gives its
314
    /// other children no room, so a window moved into one vanished while
315
    /// staying focused.
316
    fn reveal(&mut self, leaf: NodeId, moved: bool) -> bool {
317
        let mut cur = leaf;
318
        while moved && let Some(p) = self.nodes[cur].parent {
319
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
320
                && expanded.is_some_and(|e| e != cur)
321
            {
322
                *expanded = None;
323
            }
324
            cur = p;
325
        }
326
        moved
327
    }
328
329
    /// Whether every container above `w` is expanded towards it.
330
    pub fn maximized(&self, w: W, vis: impl Fn(W) -> bool) -> bool {
331
        let path = self.shown_path(w, &vis);
332
        !path.is_empty() && path.iter().all(|&(p, c)| self.expanded(p) == Some(c))
333
    }
334
335
    /// `w`'s ancestry as (container, child) pairs, leaving out containers
336
    /// where the child has no visible sibling. Those look like nothing on
337
    /// screen, so expanding there would do nothing the user could see.
338
    fn shown_path(&self, w: W, vis: &impl Fn(W) -> bool) -> Vec<(NodeId, NodeId)> {
339
        let Some(&leaf) = self.leaves.get(&w) else {
340
            return Vec::new();
341
        };
342
        let mut path = Vec::new();
343
        let mut cur = leaf;
344
        while let Some(p) = self.nodes[cur].parent {
345
            let shared = self
346
                .children(p)
347
                .iter()
348
                .any(|&c| c != cur && self.visible(c, vis));
349
            if shared {
350
                path.push((p, cur));
351
            }
352
            cur = p;
353
        }
354
        path
355
    }
356
357
    /// Transposes the whole tree.
358
    pub fn flip(&mut self) {
359
        self.stack = self.stack.other();
360
        for node in self.nodes.values_mut() {
361
            match &mut node.kind {
362
                Kind::Container { axis, .. } => *axis = axis.other(),
363
                Kind::Leaf(_, size) => size.reverse(),
364
            }
365
        }
366
    }
367
368
    /// Toggles expansion for `count` levels of `w`'s visible ancestry,
369
    /// starting `skip` levels up. Level 0 expands the window inside the
370
    /// nearest container where it has a visible sibling.
371
    pub fn toggle_expand(
372
        &mut self,
373
        w: W,
374
        skip: usize,
375
        count: usize,
376
        vis: impl Fn(W) -> bool,
377
    ) -> bool {
378
        let path: Vec<_> = self
379
            .shown_path(w, &vis)
380
            .into_iter()
381
            .skip(skip)
382
            .take(count)
383
            .collect();
384
        if path.is_empty() {
385
            return false;
386
        }
387
        let all = path.iter().all(|&(p, c)| self.expanded(p) == Some(c));
388
        for (p, c) in path {
389
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind {
390
                *expanded = (!all).then_some(c);
391
            }
392
        }
393
        true
394
    }
395
396
    /// Grows `w` by `delta`, a fraction of the visible length of the nearest
397
    /// container along `axis` where it has a visible sibling. Hidden siblings
398
    /// keep their sizes, and with them their share.
399
    pub fn resize(&mut self, w: W, axis: Axis, delta: f64, vis: impl Fn(W) -> bool) -> bool {
400
        let Some(&leaf) = self.leaves.get(&w) else {
401
            return false;
402
        };
403
        let mut cur = leaf;
404
        while let Some(p) = self.nodes[cur].parent {
405
            if self.axis(p) == Some(axis) {
406
                let shown: Vec<(NodeId, f64)> = self
407
                    .children(p)
408
                    .iter()
409
                    .filter(|&&c| self.visible(c, &vis))
410
                    .map(|&c| (c, self.extent(c, axis, &vis)))
411
                    .collect();
412
                if shown.len() >= 2 {
413
                    let sum: f64 = shown.iter().map(|s| s.1).sum();
414
                    let old = self.extent(cur, axis, &vis);
415
                    let max = 1.0 - MIN_SHARE * (shown.len() - 1) as f64;
416
                    let new = (old / sum + delta).clamp(MIN_SHARE, max) * sum;
417
                    let scale = (sum - new) / (sum - old);
418
                    for (c, _) in shown {
419
                        self.scale(c, axis, if c == cur { new / old } else { scale });
420
                    }
421
                    return true;
422
                }
423
            }
424
            cur = p;
425
        }
426
        false
427
    }
428
429
    /// Scales every window under `n` along `axis`, hidden ones too, so they
430
    /// keep their proportions for when they are shown again.
431
    fn scale(&mut self, n: NodeId, axis: Axis, by: f64) {
432
        match &mut self.nodes[n].kind {
433
            Kind::Leaf(_, size) => size[axis.index()] *= by,
434
            Kind::Container { children, .. } => {
435
                for c in children.clone() {
436
                    self.scale(c, axis, by);
437
                }
438
            }
439
        }
440
    }
441
442
    /// How much room `n` asks for along `axis` among its siblings. A
443
    /// container asks for the mean of what its visible children ask for, so
444
    /// windows of other tags sharing a lane change nothing on screen, and a
445
    /// window carries its own size wherever it moves.
446
    fn extent(&self, n: NodeId, axis: Axis, vis: &impl Fn(W) -> bool) -> f64 {
447
        match &self.nodes[n].kind {
448
            Kind::Leaf(_, size) => size[axis.index()],
449
            Kind::Container { children, .. } => {
450
                let shown: Vec<f64> = children
451
                    .iter()
452
                    .filter(|&&c| self.visible(c, vis))
453
                    .map(|&c| self.extent(c, axis, vis))
454
                    .collect();
455
                if shown.is_empty() {
456
                    children
457
                        .iter()
458
                        .map(|&c| self.extent(c, axis, vis))
459
                        .sum::<f64>()
460
                        / children.len() as f64
461
                } else {
462
                    shown.iter().sum::<f64>() / shown.len() as f64
463
                }
464
            }
465
        }
466
    }
467
468
    /// The size a window placed in `n`'s stead would take, ignoring
469
    /// visibility since new windows land on any tag.
470
    fn size(&self, n: NodeId) -> Size {
471
        let all = |_: W| true;
472
        [
473
            self.extent(n, Axis::Horizontal, &all),
474
            self.extent(n, Axis::Vertical, &all),
475
        ]
476
    }
477
478
    /// Lays the tree out in `area`. Hidden windows come back as zero-size
479
    /// rects on the boundary where they would reappear.
480
    pub fn arrange(&self, area: Rect, gap: f64, vis: impl Fn(W) -> bool) -> Vec<(W, Rect)> {
481
        let mut out = Vec::with_capacity(self.leaves.len());
482
        if let Some(r) = self.root {
483
            let area = if self.visible(r, &vis) {
484
                area
485
            } else {
486
                Rect::new(area.x + area.w / 2.0, area.y, 0.0, area.h)
487
            };
488
            self.place(r, area, gap, &vis, &mut out);
489
        }
490
        out
491
    }
492
493
    fn place(
494
        &self,
495
        n: NodeId,
496
        r: Rect,
497
        gap: f64,
498
        vis: &impl Fn(W) -> bool,
499
        out: &mut Vec<(W, Rect)>,
500
    ) {
501
        let (axis, children, expanded) = match &self.nodes[n].kind {
502
            Kind::Leaf(w, _) => return out.push((*w, r)),
503
            Kind::Container {
504
                axis,
505
                children,
506
                expanded,
507
            } => (*axis, children, *expanded),
508
        };
509
        let shown: Vec<bool> = children.iter().map(|&c| self.visible(c, vis)).collect();
510
        let (start, len) = span(r, axis);
511
        if let Some(e) = expanded.and_then(|e| children.iter().position(|&c| c == e))
512
            && shown[e]
513
        {
514
            for (i, &c) in children.iter().enumerate() {
515
                let sub = match i.cmp(&e) {
516
                    std::cmp::Ordering::Equal => r,
517
                    std::cmp::Ordering::Less => with_span(r, axis, start, 0.0),
518
                    std::cmp::Ordering::Greater => with_span(r, axis, start + len, 0.0),
519
                };
520
                self.place(c, sub, gap, vis, out);
521
            }
522
            return;
523
        }
524
        let count = shown.iter().filter(|s| **s).count();
525
        let extents: Vec<f64> = children
526
            .iter()
527
            .zip(&shown)
528
            .map(|(&c, &s)| if s { self.extent(c, axis, vis) } else { 0.0 })
529
            .collect();
530
        let total: f64 = extents.iter().sum();
531
        let gaps = count.saturating_sub(1) as f64;
532
        let gap = if gaps > 0.0 { gap.min(len / gaps) } else { gap };
533
        let avail = len - gap * gaps;
534
        let last = shown.iter().rposition(|s| *s);
535
        let mut pos = start;
536
        let mut seen = false;
537
        for (i, &c) in children.iter().enumerate() {
538
            if shown[i] {
539
                if seen {
540
                    pos += gap;
541
                }
542
                let l = avail * extents[i] / total;
543
                self.place(c, with_span(r, axis, pos, l), gap, vis, out);
544
                pos += l;
545
                seen = true;
546
            } else {
547
                let between = seen && last.is_some_and(|l| l > i);
548
                let at = if between { pos + gap / 2.0 } else { pos };
549
                self.place(c, with_span(r, axis, at, 0.0), gap, vis, out);
550
            }
551
        }
552
    }
553
554
    fn move_node(&mut self, n: NodeId, dir: Dir, vis: &impl Fn(W) -> bool, enter: bool) -> bool {
555
        let mut cur = n;
556
        while let Some((p, i)) = self.position(cur) {
557
            if self.axis(p) == Some(dir.axis()) {
558
                let hidden_lane = self
559
                    .adjacent(p, i, dir)
560
                    .filter(|&j| enter && !self.visible(self.children(p)[j], vis));
561
                if cur != n {
562
                    if let Some(j) = hidden_lane {
563
                        self.join_lane(n, p, j);
564
                    } else {
565
                        let at = if dir.forward() { i + 1 } else { i };
566
                        self.relocate(n, p, at);
567
                    }
568
                    return true;
569
                }
570
                if let Some(j) = self.next_shown(p, i, dir, vis) {
571
                    let sib = self.children(p)[j];
572
                    if enter && self.shown_windows(sib, vis) > 1 {
573
                        self.join_lane(n, p, j);
574
                    } else {
575
                        let children = self.children_mut(p);
576
                        children.swap(i, j);
577
                    }
578
                    return true;
579
                }
580
                if let Some(j) = hidden_lane {
581
                    self.join_lane(n, p, j);
582
                    return true;
583
                }
584
            }
585
            cur = p;
586
        }
587
        if cur == n || self.axis(cur) == Some(dir.axis()) {
588
            return false;
589
        }
590
        let (old, i) = self.position(n).expect("n is below the root");
591
        self.unlink(old, i);
592
        self.normalize(old);
593
        let r = self.root.expect("the rest of the tree survives");
594
        if self.axis(r) == Some(dir.axis()) {
595
            let at = if dir.forward() {
596
                self.children(r).len()
597
            } else {
598
                0
599
            };
600
            self.attach(r, at, n);
601
        } else {
602
            let c = self.new_container(dir.axis());
603
            self.attach(c, 0, r);
604
            let at = if dir.forward() {
605
                self.children(c).len()
606
            } else {
607
                0
608
            };
609
            self.attach(c, at, n);
610
            self.root = Some(c);
611
        }
612
        true
613
    }
614
615
    fn next_shown(&self, p: NodeId, i: usize, dir: Dir, vis: &impl Fn(W) -> bool) -> Option<usize> {
616
        let children = self.children(p);
617
        if dir.forward() {
618
            (i + 1..children.len()).find(|&j| self.visible(children[j], vis))
619
        } else {
620
            (0..i).rev().find(|&j| self.visible(children[j], vis))
621
        }
622
    }
623
624
    fn adjacent(&self, p: NodeId, i: usize, dir: Dir) -> Option<usize> {
625
        let j = if dir.forward() {
626
            i + 1
627
        } else {
628
            i.checked_sub(1)?
629
        };
630
        (j < self.children(p).len()).then_some(j)
631
    }
632
633
    /// Moves `n` to the end of the lane at `p`'s child `j`. A lone window
634
    /// there becomes a lane of its own, perpendicular to `p`.
635
    fn join_lane(&mut self, n: NodeId, p: NodeId, j: usize) {
636
        let lane = self.children(p)[j];
637
        let lane = if self.axis(lane).is_some() {
638
            lane
639
        } else {
640
            let c = self.new_container(self.axis(p).expect("p is a container").other());
641
            self.children_mut(p)[j] = c;
642
            self.nodes[c].parent = Some(p);
643
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
644
                && *expanded == Some(lane)
645
            {
646
                *expanded = Some(c);
647
            }
648
            self.attach(c, 0, lane);
649
            c
650
        };
651
        let end = self.children(lane).len();
652
        self.relocate(n, lane, end);
653
    }
654
655
    fn relocate(&mut self, n: NodeId, p: NodeId, at: usize) {
656
        let (old, i) = self.position(n).expect("relocated nodes have a parent");
657
        let at = if old == p && i < at { at - 1 } else { at };
658
        self.unlink(old, i);
659
        self.attach(p, at, n);
660
        self.normalize(old);
661
    }
662
663
    /// Places `node` among `p`'s children. A container running along `p`'s
664
    /// axis is dissolved into `p` so axes keep alternating.
665
    fn attach(&mut self, p: NodeId, at: usize, node: NodeId) {
666
        if self.axis(node).is_some() && self.axis(node) == self.axis(p) {
667
            let children = self.children(node).to_vec();
668
            self.nodes.remove(node);
669
            for (k, &c) in children.iter().enumerate() {
670
                self.nodes[c].parent = Some(p);
671
                self.children_mut(p).insert(at + k, c);
672
            }
673
        } else {
674
            self.nodes[node].parent = Some(p);
675
            self.children_mut(p).insert(at, node);
676
        }
677
    }
678
679
    fn unlink(&mut self, p: NodeId, i: usize) {
680
        let child = self.unlink_dead(p, i);
681
        self.nodes[child].parent = None;
682
    }
683
684
    fn detach(&mut self, n: NodeId) {
685
        match self.position(n) {
686
            Some((p, i)) => {
687
                self.unlink(p, i);
688
                self.normalize(p);
689
            }
690
            None => self.root = None,
691
        }
692
    }
693
694
    /// Repairs a container that lost a child.
695
    fn normalize(&mut self, c: NodeId) {
696
        if self.children(c).len() >= 2 {
697
            return;
698
        }
699
        let pos = self.position(c);
700
        let was_expanded = pos.is_some_and(|(p, _)| self.expanded(p) == Some(c));
701
        let Some(Node {
702
            kind: Kind::Container { children, .. },
703
            ..
704
        }) = self.nodes.remove(c)
705
        else {
706
            unreachable!("only containers are normalized");
707
        };
708
        let only = children.into_iter().next();
709
        match (only, pos) {
710
            (None, Some((p, i))) => {
711
                self.unlink_dead(p, i);
712
                self.normalize(p);
713
            }
714
            (None, None) => self.root = None,
715
            (Some(only), Some((p, i))) => {
716
                self.unlink_dead(p, i);
717
                let leaf_like = self.axis(only) != self.axis(p);
718
                self.attach(p, i, only);
719
                if was_expanded
720
                    && leaf_like
721
                    && let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
722
                {
723
                    *expanded = Some(only);
724
                }
725
            }
726
            (Some(only), None) => {
727
                self.nodes[only].parent = None;
728
                self.root = Some(only);
729
            }
730
        }
731
    }
732
733
    /// Like `unlink`, for a child whose node is already gone.
734
    fn unlink_dead(&mut self, p: NodeId, i: usize) -> NodeId {
735
        let Kind::Container {
736
            children, expanded, ..
737
        } = &mut self.nodes[p].kind
738
        else {
739
            unreachable!("parents are containers");
740
        };
741
        let child = children.remove(i);
742
        if *expanded == Some(child) {
743
            *expanded = None;
744
        }
745
        child
746
    }
747
748
    fn new_leaf(&mut self, w: W, size: Size) -> NodeId {
749
        let n = self.nodes.insert(Node {
750
            parent: None,
751
            kind: Kind::Leaf(w, size),
752
        });
753
        self.leaves.insert(w, n);
754
        n
755
    }
756
757
    fn new_container(&mut self, axis: Axis) -> NodeId {
758
        self.nodes.insert(Node {
759
            parent: None,
760
            kind: Kind::Container {
761
                axis,
762
                children: Vec::new(),
763
                expanded: None,
764
            },
765
        })
766
    }
767
768
    fn position(&self, n: NodeId) -> Option<(NodeId, usize)> {
769
        let p = self.nodes[n].parent?;
770
        let i = self.children(p).iter().position(|&c| c == n)?;
771
        Some((p, i))
772
    }
773
774
    fn axis(&self, n: NodeId) -> Option<Axis> {
775
        match &self.nodes[n].kind {
776
            Kind::Container { axis, .. } => Some(*axis),
777
            Kind::Leaf(..) => None,
778
        }
779
    }
780
781
    fn expanded(&self, n: NodeId) -> Option<NodeId> {
782
        match &self.nodes[n].kind {
783
            Kind::Container { expanded, .. } => *expanded,
784
            Kind::Leaf(..) => None,
785
        }
786
    }
787
788
    fn children(&self, n: NodeId) -> &[NodeId] {
789
        match &self.nodes[n].kind {
790
            Kind::Container { children, .. } => children,
791
            Kind::Leaf(..) => &[],
792
        }
793
    }
794
795
    fn children_mut(&mut self, n: NodeId) -> &mut Vec<NodeId> {
796
        match &mut self.nodes[n].kind {
797
            Kind::Container { children, .. } => children,
798
            Kind::Leaf(..) => unreachable!("leaves have no children"),
799
        }
800
    }
801
802
    fn visible(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> bool {
803
        match &self.nodes[n].kind {
804
            Kind::Leaf(w, _) => vis(*w),
805
            Kind::Container { children, .. } => children.iter().any(|&c| self.visible(c, vis)),
806
        }
807
    }
808
809
    fn shown_windows(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> usize {
810
        match &self.nodes[n].kind {
811
            Kind::Leaf(w, _) => usize::from(vis(*w)),
812
            Kind::Container { children, .. } => {
813
                children.iter().map(|&c| self.shown_windows(c, vis)).sum()
814
            }
815
        }
816
    }
817
818
    #[cfg(test)]
819
    pub(crate) fn shape(&self) -> String
820
    where
821
        W: std::fmt::Debug,
822
    {
823
        fn go<W: Copy + Eq + Hash + std::fmt::Debug>(t: &Tree<W>, n: NodeId) -> String {
824
            match &t.nodes[n].kind {
825
                Kind::Leaf(w, [x, y]) => format!("{w:?}[{x:.6},{y:.6}]"),
826
                Kind::Container {
827
                    axis,
828
                    children,
829
                    expanded,
830
                } => {
831
                    let inner: Vec<String> = children.iter().map(|&c| go(t, c)).collect();
832
                    let e = expanded.and_then(|e| children.iter().position(|&c| c == e));
833
                    format!("{axis:?}{e:?}({})", inner.join(" "))
834
                }
835
            }
836
        }
837
        self.root.map(|r| go(self, r)).unwrap_or_default()
838
    }
839
840
    #[cfg(test)]
841
    pub(crate) fn check(&self) {
842
        let reachable = match self.root {
843
            Some(r) => {
844
                assert!(self.nodes[r].parent.is_none());
845
                self.check_node(r)
846
            }
847
            None => 0,
848
        };
849
        assert_eq!(reachable, self.nodes.len(), "orphaned nodes");
850
        for (&w, &n) in &self.leaves {
851
            assert!(matches!(self.nodes[n].kind, Kind::Leaf(x, _) if x == w));
852
        }
853
    }
854
855
    #[cfg(test)]
856
    fn check_node(&self, n: NodeId) -> usize {
857
        match &self.nodes[n].kind {
858
            Kind::Leaf(_, size) => {
859
                assert!(
860
                    size.iter().all(|s| *s > 0.0 && s.is_finite()),
861
                    "size {size:?}"
862
                );
863
                1
864
            }
865
            Kind::Container {
866
                axis,
867
                children,
868
                expanded,
869
            } => {
870
                assert!(
871
                    children.len() >= 2,
872
                    "container with {} children",
873
                    children.len()
874
                );
875
                if let Some(e) = expanded {
876
                    assert!(children.contains(e));
877
                }
878
                let mut count = 1;
879
                for &c in children {
880
                    assert_eq!(self.nodes[c].parent, Some(n));
881
                    assert_ne!(self.axis(c), Some(*axis), "axes must alternate");
882
                    count += self.check_node(c);
883
                }
884
                count
885
            }
886
        }
887
    }
888
}
889
890
fn span(r: Rect, axis: Axis) -> (f64, f64) {
891
    match axis {
892
        Axis::Horizontal => (r.x, r.w),
893
        Axis::Vertical => (r.y, r.h),
894
    }
895
}
896
897
fn with_span(r: Rect, axis: Axis, start: f64, len: f64) -> Rect {
898
    match axis {
899
        Axis::Horizontal => Rect::new(start, r.y, len, r.h),
900
        Axis::Vertical => Rect::new(r.x, start, r.w, len),
901
    }
902
}