atagen

monolith

public
Star0
Watch0
b2274115d1c6841c5e1c429f27c61a4528dc26bd
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/layout/src/tree.rsRust1097 lines36.2 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, and an extended window moves
226
    /// its group as a rigid block.
227
    pub fn move_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
228
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
229
            return false;
230
        };
231
        let block = self.group(w, &vis).unwrap_or(n);
232
        self.until_seen(&vis, |t| {
233
            let moved = t.move_node(block, dir, &vis, block == n);
234
            t.reveal(n, moved)
235
        })
236
    }
237
238
    /// Moves the group or container holding `w` as a block, merging it into
239
    /// the next lane in `dir` like `merge_window` when `merge` is set. A
240
    /// window sitting directly in the root is its own block.
241
    pub fn move_container(&mut self, w: W, dir: Dir, merge: bool, vis: impl Fn(W) -> bool) -> bool {
242
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
243
            return false;
244
        };
245
        let group = self.group(w, &vis);
246
        self.until_seen(&vis, |t| {
247
            let block = group.unwrap_or_else(|| {
248
                t.nodes[n]
249
                    .parent
250
                    .filter(|&p| Some(p) != t.root)
251
                    .unwrap_or(n)
252
            });
253
            if merge {
254
                t.merge_node(n, block, dir, &vis)
255
            } else {
256
                let moved = t.move_node(block, dir, &vis, false);
257
                t.reveal(n, moved)
258
            }
259
        })
260
    }
261
262
    /// Moves a window to the end of the next visible lane in `dir` among its
263
    /// siblings. A lone window there becomes a stack with it. A window with no
264
    /// sibling lane that way leaves its stack as `move_window` would, so it
265
    /// takes one press to step out and another to merge. An extended window
266
    /// takes its group along.
267
    pub fn merge_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
268
        let Some(&n) = self.leaves.get(&w).filter(|_| vis(w)) else {
269
            return false;
270
        };
271
        let block = self.group(w, &vis).unwrap_or(n);
272
        self.until_seen(&vis, |t| t.merge_node(n, block, dir, &vis))
273
    }
274
275
    fn merge_node(&mut self, leaf: NodeId, n: NodeId, dir: Dir, vis: &impl Fn(W) -> bool) -> bool {
276
        if let Some((p, i)) = self.position(n)
277
            && self.axis(p) == Some(dir.axis())
278
            && let Some(j) = self.next_shown(p, i, dir, vis)
279
        {
280
            self.join_lane(n, p, j);
281
            return self.reveal(leaf, true);
282
        }
283
        let moved = self.move_node(n, dir, vis, true);
284
        self.reveal(leaf, moved)
285
    }
286
287
    /// The outermost container `w` is extended in, the block it moves as.
288
    fn group(&self, w: W, vis: &impl Fn(W) -> bool) -> Option<NodeId> {
289
        self.shown_path(w, vis)
290
            .into_iter()
291
            .take_while(|&(p, c)| self.expanded(p) == Some(c))
292
            .last()
293
            .map(|(p, _)| p)
294
    }
295
296
    /// Whether `w` is extended over windows it shares a container with.
297
    pub fn grouped(&self, w: W, vis: impl Fn(W) -> bool) -> bool {
298
        self.group(w, &vis).is_some()
299
    }
300
301
    /// The shown windows in the block `w` moves as, `w` alone when it is not
302
    /// extended.
303
    pub fn group_windows(&self, w: W, vis: impl Fn(W) -> bool) -> Vec<W> {
304
        let Some(g) = self.group(w, &vis) else {
305
            return vec![w];
306
        };
307
        let mut out = Vec::new();
308
        self.shown_leaves(g, &vis, &mut out);
309
        out
310
    }
311
312
    /// Whether a visible window extended over `w` takes all its room.
313
    pub fn eclipsed(&self, w: W, vis: impl Fn(W) -> bool) -> bool {
314
        let Some(&leaf) = self.leaves.get(&w) else {
315
            return false;
316
        };
317
        let mut cur = leaf;
318
        while let Some(p) = self.nodes[cur].parent {
319
            if self
320
                .expanded(p)
321
                .is_some_and(|e| e != cur && self.visible(e, &vis))
322
            {
323
                return true;
324
            }
325
            cur = p;
326
        }
327
        false
328
    }
329
330
    /// Repeats `step` until the visible layout changes, or undoes it all when
331
    /// it never does. Steps around hidden windows otherwise ate keypresses
332
    /// and rearranged windows the user could not see.
333
    fn until_seen(
334
        &mut self,
335
        vis: &impl Fn(W) -> bool,
336
        mut step: impl FnMut(&mut Self) -> bool,
337
    ) -> bool {
338
        let seen = |t: &Self| -> Vec<(W, Rect)> {
339
            t.arrange(Rect::new(0.0, 0.0, 1000.0, 1000.0), 0.0, vis)
340
                .into_iter()
341
                .filter(|p| vis(p.0))
342
                .collect()
343
        };
344
        let same = |a: &[(W, Rect)], b: &[(W, Rect)]| {
345
            a.len() == b.len()
346
                && a.iter().all(|(v, r)| {
347
                    b.iter().any(|(w, s)| {
348
                        v == w
349
                            && [r.x - s.x, r.y - s.y, r.w - s.w, r.h - s.h]
350
                                .iter()
351
                                .all(|d| d.abs() < 1e-6)
352
                    })
353
                })
354
        };
355
        let before = self.clone();
356
        let start = seen(self);
357
        for _ in 0..=before.nodes.len() {
358
            if !step(self) {
359
                break;
360
            }
361
            if !same(&start, &seen(self)) {
362
                return true;
363
            }
364
        }
365
        *self = before;
366
        false
367
    }
368
369
    /// Undoes any expansion along `leaf`'s ancestry that favours another
370
    /// child, once it has `moved` or arrived. An expanded container gives its
371
    /// other children no room, so a window moved into one vanished while
372
    /// staying focused.
373
    fn reveal(&mut self, leaf: NodeId, moved: bool) -> bool {
374
        let mut cur = leaf;
375
        while moved && let Some(p) = self.nodes[cur].parent {
376
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
377
                && expanded.is_some_and(|e| e != cur)
378
            {
379
                *expanded = None;
380
            }
381
            cur = p;
382
        }
383
        moved
384
    }
385
386
    /// Whether every container above `w` is expanded towards it.
387
    pub fn maximized(&self, w: W, vis: impl Fn(W) -> bool) -> bool {
388
        let path = self.shown_path(w, &vis);
389
        !path.is_empty() && path.iter().all(|&(p, c)| self.expanded(p) == Some(c))
390
    }
391
392
    /// `w`'s ancestry as (container, child) pairs, leaving out containers
393
    /// where the child has no visible sibling. Those look like nothing on
394
    /// screen, so expanding there would do nothing the user could see.
395
    fn shown_path(&self, w: W, vis: &impl Fn(W) -> bool) -> Vec<(NodeId, NodeId)> {
396
        let Some(&leaf) = self.leaves.get(&w) else {
397
            return Vec::new();
398
        };
399
        let mut path = Vec::new();
400
        let mut cur = leaf;
401
        while let Some(p) = self.nodes[cur].parent {
402
            let shared = self
403
                .children(p)
404
                .iter()
405
                .any(|&c| c != cur && self.visible(c, vis));
406
            if shared {
407
                path.push((p, cur));
408
            }
409
            cur = p;
410
        }
411
        path
412
    }
413
414
    /// Transposes the whole tree.
415
    pub fn flip(&mut self) {
416
        self.stack = self.stack.other();
417
        for node in self.nodes.values_mut() {
418
            match &mut node.kind {
419
                Kind::Container { axis, .. } => *axis = axis.other(),
420
                Kind::Leaf(_, size) => size.reverse(),
421
            }
422
        }
423
    }
424
425
    /// Toggles expansion for `count` levels of `w`'s visible ancestry,
426
    /// starting `skip` levels up. Level 0 expands the window inside the
427
    /// nearest container where it has a visible sibling.
428
    pub fn toggle_expand(
429
        &mut self,
430
        w: W,
431
        skip: usize,
432
        count: usize,
433
        vis: impl Fn(W) -> bool,
434
    ) -> bool {
435
        let path: Vec<_> = self
436
            .shown_path(w, &vis)
437
            .into_iter()
438
            .skip(skip)
439
            .take(count)
440
            .collect();
441
        if path.is_empty() {
442
            return false;
443
        }
444
        let all = path.iter().all(|&(p, c)| self.expanded(p) == Some(c));
445
        for (p, c) in path {
446
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind {
447
                *expanded = (!all).then_some(c);
448
            }
449
        }
450
        true
451
    }
452
453
    /// Grows `w` by `delta`, a fraction of the visible length of the nearest
454
    /// container along `axis` where it has a visible sibling. Hidden siblings
455
    /// keep their sizes, and with them their share.
456
    pub fn resize(&mut self, w: W, axis: Axis, delta: f64, vis: impl Fn(W) -> bool) -> bool {
457
        let Some(&leaf) = self.leaves.get(&w) else {
458
            return false;
459
        };
460
        let mut cur = leaf;
461
        while let Some(p) = self.nodes[cur].parent {
462
            if self.axis(p) == Some(axis) {
463
                let shown: Vec<(NodeId, f64)> = self
464
                    .children(p)
465
                    .iter()
466
                    .filter(|&&c| self.visible(c, &vis))
467
                    .map(|&c| (c, self.extent(c, axis, &vis)))
468
                    .collect();
469
                if shown.len() >= 2 {
470
                    let sum: f64 = shown.iter().map(|s| s.1).sum();
471
                    let old = self.extent(cur, axis, &vis);
472
                    let max = 1.0 - MIN_SHARE * (shown.len() - 1) as f64;
473
                    let new = (old / sum + delta).clamp(MIN_SHARE, max) * sum;
474
                    let scale = (sum - new) / (sum - old);
475
                    for (c, _) in shown {
476
                        self.scale(c, axis, if c == cur { new / old } else { scale });
477
                    }
478
                    return true;
479
                }
480
            }
481
            cur = p;
482
        }
483
        false
484
    }
485
486
    /// Gives every visible child of the nearest container where `w` has a
487
    /// visible sibling an equal share along that container's axis.
488
    pub fn balance(&mut self, w: W, vis: impl Fn(W) -> bool) -> bool {
489
        let Some(&(p, _)) = self.shown_path(w, &vis).first() else {
490
            return false;
491
        };
492
        let Some(axis) = self.axis(p) else {
493
            return false;
494
        };
495
        let shown: Vec<(NodeId, f64)> = self
496
            .children(p)
497
            .iter()
498
            .filter(|&&c| self.visible(c, &vis))
499
            .map(|&c| (c, self.extent(c, axis, &vis)))
500
            .collect();
501
        let mean = shown.iter().map(|s| s.1).sum::<f64>() / shown.len() as f64;
502
        for (c, e) in shown {
503
            if e > 0.0 {
504
                self.scale(c, axis, mean / e);
505
            }
506
        }
507
        true
508
    }
509
510
    /// The lane a window's split on side `dir` lives in, as the child holding
511
    /// the window, its parent and the index of the visible sibling across
512
    /// the split.
513
    fn split_across(
514
        &self,
515
        w: W,
516
        dir: Dir,
517
        vis: &impl Fn(W) -> bool,
518
    ) -> Option<(NodeId, NodeId, usize)> {
519
        let mut cur = *self.leaves.get(&w)?;
520
        if !self.visible(cur, vis) {
521
            return None;
522
        }
523
        while let Some((p, i)) = self.position(cur) {
524
            if self.axis(p) == Some(dir.axis())
525
                && let Some(j) = self.next_shown(p, i, dir, vis)
526
            {
527
                return Some((cur, p, j));
528
            }
529
            cur = p;
530
        }
531
        None
532
    }
533
534
    /// Whether the split on side `dir` of `w` has a visible window across it.
535
    pub fn has_split(&self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
536
        self.split_across(w, dir, &vis).is_some()
537
    }
538
539
    /// Moves the split on side `dir` of `w` by `px` along that side's axis,
540
    /// positive toward the right or bottom. Only the two children meeting at
541
    /// the split change, so the split follows the pointer.
542
    pub fn move_split(
543
        &mut self,
544
        w: W,
545
        dir: Dir,
546
        px: f64,
547
        area: Rect,
548
        gap: f64,
549
        vis: impl Fn(W) -> bool,
550
    ) -> bool {
551
        let Some((cur, p, j)) = self.split_across(w, dir, &vis) else {
552
            return false;
553
        };
554
        let axis = dir.axis();
555
        let other = self.children(p)[j];
556
        let (first, second) = if dir.forward() {
557
            (cur, other)
558
        } else {
559
            (other, cur)
560
        };
561
        let mut leaves = Vec::new();
562
        self.shown_leaves(first, &vis, &mut leaves);
563
        let (start, end) = self
564
            .arrange(area, gap, &vis)
565
            .iter()
566
            .filter(|(l, _)| leaves.contains(l))
567
            .map(|(_, r)| span(*r, axis))
568
            .fold((f64::MAX, f64::MIN), |(s, e), (rs, rl)| {
569
                (s.min(rs), e.max(rs + rl))
570
            });
571
        let ef = self.extent(first, axis, &vis);
572
        let es = self.extent(second, axis, &vis);
573
        if end <= start || ef <= 0.0 || es <= 0.0 {
574
            return true;
575
        }
576
        let sum: f64 = self
577
            .children(p)
578
            .iter()
579
            .filter(|&&c| self.visible(c, &vis))
580
            .map(|&c| self.extent(c, axis, &vis))
581
            .sum();
582
        let min = MIN_SHARE * sum;
583
        let du = (px * ef / (end - start)).clamp(-(ef - min).max(0.0), (es - min).max(0.0));
584
        self.scale(first, axis, (ef + du) / ef);
585
        self.scale(second, axis, (es - du) / es);
586
        true
587
    }
588
589
    fn shown_leaves(&self, n: NodeId, vis: &impl Fn(W) -> bool, out: &mut Vec<W>) {
590
        match &self.nodes[n].kind {
591
            Kind::Leaf(w, _) => {
592
                if vis(*w) {
593
                    out.push(*w);
594
                }
595
            }
596
            Kind::Container { children, .. } => {
597
                for &c in children {
598
                    self.shown_leaves(c, vis, out);
599
                }
600
            }
601
        }
602
    }
603
604
    /// Scales every window under `n` along `axis`, hidden ones too, so they
605
    /// keep their proportions for when they are shown again.
606
    fn scale(&mut self, n: NodeId, axis: Axis, by: f64) {
607
        match &mut self.nodes[n].kind {
608
            Kind::Leaf(_, size) => size[axis.index()] *= by,
609
            Kind::Container { children, .. } => {
610
                for c in children.clone() {
611
                    self.scale(c, axis, by);
612
                }
613
            }
614
        }
615
    }
616
617
    /// How much room `n` asks for along `axis` among its siblings. A
618
    /// container asks for the mean of what its visible children ask for, so
619
    /// windows of other tags sharing a lane change nothing on screen, and a
620
    /// window carries its own size wherever it moves.
621
    fn extent(&self, n: NodeId, axis: Axis, vis: &impl Fn(W) -> bool) -> f64 {
622
        match &self.nodes[n].kind {
623
            Kind::Leaf(_, size) => size[axis.index()],
624
            Kind::Container { children, .. } => {
625
                let shown: Vec<f64> = children
626
                    .iter()
627
                    .filter(|&&c| self.visible(c, vis))
628
                    .map(|&c| self.extent(c, axis, vis))
629
                    .collect();
630
                if shown.is_empty() {
631
                    children
632
                        .iter()
633
                        .map(|&c| self.extent(c, axis, vis))
634
                        .sum::<f64>()
635
                        / children.len() as f64
636
                } else {
637
                    shown.iter().sum::<f64>() / shown.len() as f64
638
                }
639
            }
640
        }
641
    }
642
643
    /// The size a window placed in `n`'s stead would take, ignoring
644
    /// visibility since new windows land on any tag.
645
    fn size(&self, n: NodeId) -> Size {
646
        let all = |_: W| true;
647
        [
648
            self.extent(n, Axis::Horizontal, &all),
649
            self.extent(n, Axis::Vertical, &all),
650
        ]
651
    }
652
653
    /// Lays the tree out in `area`. Hidden windows come back as zero-size
654
    /// rects on the boundary where they would reappear.
655
    pub fn arrange(&self, area: Rect, gap: f64, vis: impl Fn(W) -> bool) -> Vec<(W, Rect)> {
656
        let mut out = Vec::with_capacity(self.leaves.len());
657
        if let Some(r) = self.root {
658
            let area = if self.visible(r, &vis) {
659
                area
660
            } else if area.w >= area.h {
661
                Rect::new(area.right(), area.y, 0.0, area.h)
662
            } else {
663
                Rect::new(area.x, area.bottom(), area.w, 0.0)
664
            };
665
            self.place(r, area, gap, &vis, &mut out);
666
        }
667
        out
668
    }
669
670
    fn place(
671
        &self,
672
        n: NodeId,
673
        r: Rect,
674
        gap: f64,
675
        vis: &impl Fn(W) -> bool,
676
        out: &mut Vec<(W, Rect)>,
677
    ) {
678
        let (axis, children, expanded) = match &self.nodes[n].kind {
679
            Kind::Leaf(w, _) => return out.push((*w, r)),
680
            Kind::Container {
681
                axis,
682
                children,
683
                expanded,
684
            } => (*axis, children, *expanded),
685
        };
686
        let shown: Vec<bool> = children.iter().map(|&c| self.visible(c, vis)).collect();
687
        let (start, len) = span(r, axis);
688
        if let Some(e) = expanded.and_then(|e| children.iter().position(|&c| c == e))
689
            && shown[e]
690
        {
691
            for (i, &c) in children.iter().enumerate() {
692
                let sub = match i.cmp(&e) {
693
                    std::cmp::Ordering::Equal => r,
694
                    std::cmp::Ordering::Less => with_span(r, axis, start, 0.0),
695
                    std::cmp::Ordering::Greater => with_span(r, axis, start + len, 0.0),
696
                };
697
                self.place(c, sub, gap, vis, out);
698
            }
699
            return;
700
        }
701
        let count = shown.iter().filter(|s| **s).count();
702
        let extents: Vec<f64> = children
703
            .iter()
704
            .zip(&shown)
705
            .map(|(&c, &s)| if s { self.extent(c, axis, vis) } else { 0.0 })
706
            .collect();
707
        let total: f64 = extents.iter().sum();
708
        let gaps = count.saturating_sub(1) as f64;
709
        let gap = if gaps > 0.0 { gap.min(len / gaps) } else { gap };
710
        let avail = len - gap * gaps;
711
        let last = shown.iter().rposition(|s| *s);
712
        let mut pos = start;
713
        let mut seen = false;
714
        for (i, &c) in children.iter().enumerate() {
715
            if shown[i] {
716
                if seen {
717
                    pos += gap;
718
                }
719
                let l = avail * extents[i] / total;
720
                self.place(c, with_span(r, axis, pos, l), gap, vis, out);
721
                pos += l;
722
                seen = true;
723
            } else {
724
                let between = seen && last.is_some_and(|l| l > i);
725
                let at = if between { pos + gap / 2.0 } else { pos };
726
                self.place(c, with_span(r, axis, at, 0.0), gap, vis, out);
727
            }
728
        }
729
    }
730
731
    fn move_node(&mut self, n: NodeId, dir: Dir, vis: &impl Fn(W) -> bool, enter: bool) -> bool {
732
        let mut cur = n;
733
        while let Some((p, i)) = self.position(cur) {
734
            if self.axis(p) == Some(dir.axis()) {
735
                let hidden_lane = self
736
                    .adjacent(p, i, dir)
737
                    .filter(|&j| enter && !self.visible(self.children(p)[j], vis));
738
                if cur != n {
739
                    if let Some(j) = hidden_lane {
740
                        self.join_lane(n, p, j);
741
                    } else {
742
                        let at = if dir.forward() { i + 1 } else { i };
743
                        self.relocate(n, p, at);
744
                    }
745
                    return true;
746
                }
747
                if let Some(j) = self.next_shown(p, i, dir, vis) {
748
                    let sib = self.children(p)[j];
749
                    if enter && self.shown_windows(sib, vis) > 1 {
750
                        self.join_lane(n, p, j);
751
                    } else {
752
                        let children = self.children_mut(p);
753
                        children.swap(i, j);
754
                    }
755
                    return true;
756
                }
757
                if let Some(j) = hidden_lane {
758
                    self.join_lane(n, p, j);
759
                    return true;
760
                }
761
            }
762
            cur = p;
763
        }
764
        if cur == n || self.axis(cur) == Some(dir.axis()) {
765
            return false;
766
        }
767
        let (old, i) = self.position(n).expect("n is below the root");
768
        self.unlink(old, i);
769
        self.normalize(old);
770
        let r = self.root.expect("the rest of the tree survives");
771
        if self.axis(r) == Some(dir.axis()) {
772
            let at = if dir.forward() {
773
                self.children(r).len()
774
            } else {
775
                0
776
            };
777
            self.attach(r, at, n);
778
        } else {
779
            let c = self.new_container(dir.axis());
780
            self.attach(c, 0, r);
781
            let at = if dir.forward() {
782
                self.children(c).len()
783
            } else {
784
                0
785
            };
786
            self.attach(c, at, n);
787
            self.root = Some(c);
788
        }
789
        true
790
    }
791
792
    fn next_shown(&self, p: NodeId, i: usize, dir: Dir, vis: &impl Fn(W) -> bool) -> Option<usize> {
793
        let children = self.children(p);
794
        if dir.forward() {
795
            (i + 1..children.len()).find(|&j| self.visible(children[j], vis))
796
        } else {
797
            (0..i).rev().find(|&j| self.visible(children[j], vis))
798
        }
799
    }
800
801
    fn adjacent(&self, p: NodeId, i: usize, dir: Dir) -> Option<usize> {
802
        let j = if dir.forward() {
803
            i + 1
804
        } else {
805
            i.checked_sub(1)?
806
        };
807
        (j < self.children(p).len()).then_some(j)
808
    }
809
810
    /// Moves `n` to the end of the lane at `p`'s child `j`. A lone window
811
    /// there becomes a lane of its own, perpendicular to `p`.
812
    fn join_lane(&mut self, n: NodeId, p: NodeId, j: usize) {
813
        let lane = self.children(p)[j];
814
        let lane = if self.axis(lane).is_some() {
815
            lane
816
        } else {
817
            let c = self.new_container(self.axis(p).expect("p is a container").other());
818
            self.children_mut(p)[j] = c;
819
            self.nodes[c].parent = Some(p);
820
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
821
                && *expanded == Some(lane)
822
            {
823
                *expanded = Some(c);
824
            }
825
            self.attach(c, 0, lane);
826
            c
827
        };
828
        let end = self.children(lane).len();
829
        self.relocate(n, lane, end);
830
    }
831
832
    fn relocate(&mut self, n: NodeId, p: NodeId, at: usize) {
833
        let (old, i) = self.position(n).expect("relocated nodes have a parent");
834
        let at = if old == p && i < at { at - 1 } else { at };
835
        self.unlink(old, i);
836
        self.attach(p, at, n);
837
        self.normalize(old);
838
    }
839
840
    /// Places `node` among `p`'s children. A container running along `p`'s
841
    /// axis is dissolved into `p` so axes keep alternating, unless it holds an
842
    /// extended window, whose group is turned across instead to survive.
843
    fn attach(&mut self, p: NodeId, at: usize, node: NodeId) {
844
        if self.axis(node).is_some() && self.axis(node) == self.axis(p) {
845
            if self.expanded(node).is_some() {
846
                self.transpose(node);
847
                self.nodes[node].parent = Some(p);
848
                self.children_mut(p).insert(at, node);
849
                return;
850
            }
851
            let children = self.children(node).to_vec();
852
            self.nodes.remove(node);
853
            for (k, &c) in children.iter().enumerate() {
854
                self.nodes[c].parent = Some(p);
855
                self.children_mut(p).insert(at + k, c);
856
            }
857
        } else {
858
            self.nodes[node].parent = Some(p);
859
            self.children_mut(p).insert(at, node);
860
        }
861
    }
862
863
    fn unlink(&mut self, p: NodeId, i: usize) {
864
        let child = self.unlink_dead(p, i);
865
        self.nodes[child].parent = None;
866
    }
867
868
    fn detach(&mut self, n: NodeId) {
869
        match self.position(n) {
870
            Some((p, i)) => {
871
                self.unlink(p, i);
872
                self.normalize(p);
873
            }
874
            None => self.root = None,
875
        }
876
    }
877
878
    fn transpose(&mut self, n: NodeId) {
879
        match &mut self.nodes[n].kind {
880
            Kind::Container { axis, children, .. } => {
881
                *axis = axis.other();
882
                for c in children.clone() {
883
                    self.transpose(c);
884
                }
885
            }
886
            Kind::Leaf(_, size) => size.reverse(),
887
        }
888
    }
889
890
    /// Repairs a container that lost a child.
891
    fn normalize(&mut self, c: NodeId) {
892
        if self.children(c).len() >= 2 {
893
            return;
894
        }
895
        let pos = self.position(c);
896
        let was_expanded = pos.is_some_and(|(p, _)| self.expanded(p) == Some(c));
897
        let Some(Node {
898
            kind: Kind::Container { children, .. },
899
            ..
900
        }) = self.nodes.remove(c)
901
        else {
902
            unreachable!("only containers are normalized");
903
        };
904
        let only = children.into_iter().next();
905
        match (only, pos) {
906
            (None, Some((p, i))) => {
907
                self.unlink_dead(p, i);
908
                self.normalize(p);
909
            }
910
            (None, None) => self.root = None,
911
            (Some(only), Some((p, i))) => {
912
                self.unlink_dead(p, i);
913
                self.attach(p, i, only);
914
                if was_expanded
915
                    && self.nodes.contains_key(only)
916
                    && let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
917
                {
918
                    *expanded = Some(only);
919
                }
920
            }
921
            (Some(only), None) => {
922
                self.nodes[only].parent = None;
923
                self.root = Some(only);
924
            }
925
        }
926
    }
927
928
    /// Like `unlink`, for a child whose node is already gone.
929
    fn unlink_dead(&mut self, p: NodeId, i: usize) -> NodeId {
930
        let Kind::Container {
931
            children, expanded, ..
932
        } = &mut self.nodes[p].kind
933
        else {
934
            unreachable!("parents are containers");
935
        };
936
        let child = children.remove(i);
937
        if *expanded == Some(child) {
938
            *expanded = None;
939
        }
940
        child
941
    }
942
943
    fn new_leaf(&mut self, w: W, size: Size) -> NodeId {
944
        let n = self.nodes.insert(Node {
945
            parent: None,
946
            kind: Kind::Leaf(w, size),
947
        });
948
        self.leaves.insert(w, n);
949
        n
950
    }
951
952
    fn new_container(&mut self, axis: Axis) -> NodeId {
953
        self.nodes.insert(Node {
954
            parent: None,
955
            kind: Kind::Container {
956
                axis,
957
                children: Vec::new(),
958
                expanded: None,
959
            },
960
        })
961
    }
962
963
    fn position(&self, n: NodeId) -> Option<(NodeId, usize)> {
964
        let p = self.nodes[n].parent?;
965
        let i = self.children(p).iter().position(|&c| c == n)?;
966
        Some((p, i))
967
    }
968
969
    fn axis(&self, n: NodeId) -> Option<Axis> {
970
        match &self.nodes[n].kind {
971
            Kind::Container { axis, .. } => Some(*axis),
972
            Kind::Leaf(..) => None,
973
        }
974
    }
975
976
    fn expanded(&self, n: NodeId) -> Option<NodeId> {
977
        match &self.nodes[n].kind {
978
            Kind::Container { expanded, .. } => *expanded,
979
            Kind::Leaf(..) => None,
980
        }
981
    }
982
983
    fn children(&self, n: NodeId) -> &[NodeId] {
984
        match &self.nodes[n].kind {
985
            Kind::Container { children, .. } => children,
986
            Kind::Leaf(..) => &[],
987
        }
988
    }
989
990
    fn children_mut(&mut self, n: NodeId) -> &mut Vec<NodeId> {
991
        match &mut self.nodes[n].kind {
992
            Kind::Container { children, .. } => children,
993
            Kind::Leaf(..) => unreachable!("leaves have no children"),
994
        }
995
    }
996
997
    fn visible(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> bool {
998
        match &self.nodes[n].kind {
999
            Kind::Leaf(w, _) => vis(*w),
1000
            Kind::Container { children, .. } => children.iter().any(|&c| self.visible(c, vis)),
1001
        }
1002
    }
1003
1004
    fn shown_windows(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> usize {
1005
        match &self.nodes[n].kind {
1006
            Kind::Leaf(w, _) => usize::from(vis(*w)),
1007
            Kind::Container { children, .. } => {
1008
                children.iter().map(|&c| self.shown_windows(c, vis)).sum()
1009
            }
1010
        }
1011
    }
1012
1013
    #[cfg(test)]
1014
    pub(crate) fn shape(&self) -> String
1015
    where
1016
        W: std::fmt::Debug,
1017
    {
1018
        fn go<W: Copy + Eq + Hash + std::fmt::Debug>(t: &Tree<W>, n: NodeId) -> String {
1019
            match &t.nodes[n].kind {
1020
                Kind::Leaf(w, [x, y]) => format!("{w:?}[{x:.6},{y:.6}]"),
1021
                Kind::Container {
1022
                    axis,
1023
                    children,
1024
                    expanded,
1025
                } => {
1026
                    let inner: Vec<String> = children.iter().map(|&c| go(t, c)).collect();
1027
                    let e = expanded.and_then(|e| children.iter().position(|&c| c == e));
1028
                    format!("{axis:?}{e:?}({})", inner.join(" "))
1029
                }
1030
            }
1031
        }
1032
        self.root.map(|r| go(self, r)).unwrap_or_default()
1033
    }
1034
1035
    #[cfg(test)]
1036
    pub(crate) fn check(&self) {
1037
        let reachable = match self.root {
1038
            Some(r) => {
1039
                assert!(self.nodes[r].parent.is_none());
1040
                self.check_node(r)
1041
            }
1042
            None => 0,
1043
        };
1044
        assert_eq!(reachable, self.nodes.len(), "orphaned nodes");
1045
        for (&w, &n) in &self.leaves {
1046
            assert!(matches!(self.nodes[n].kind, Kind::Leaf(x, _) if x == w));
1047
        }
1048
    }
1049
1050
    #[cfg(test)]
1051
    fn check_node(&self, n: NodeId) -> usize {
1052
        match &self.nodes[n].kind {
1053
            Kind::Leaf(_, size) => {
1054
                assert!(
1055
                    size.iter().all(|s| *s > 0.0 && s.is_finite()),
1056
                    "size {size:?}"
1057
                );
1058
                1
1059
            }
1060
            Kind::Container {
1061
                axis,
1062
                children,
1063
                expanded,
1064
            } => {
1065
                assert!(
1066
                    children.len() >= 2,
1067
                    "container with {} children",
1068
                    children.len()
1069
                );
1070
                if let Some(e) = expanded {
1071
                    assert!(children.contains(e));
1072
                }
1073
                let mut count = 1;
1074
                for &c in children {
1075
                    assert_eq!(self.nodes[c].parent, Some(n));
1076
                    assert_ne!(self.axis(c), Some(*axis), "axes must alternate");
1077
                    count += self.check_node(c);
1078
                }
1079
                count
1080
            }
1081
        }
1082
    }
1083
}
1084
1085
fn span(r: Rect, axis: Axis) -> (f64, f64) {
1086
    match axis {
1087
        Axis::Horizontal => (r.x, r.w),
1088
        Axis::Vertical => (r.y, r.h),
1089
    }
1090
}
1091
1092
fn with_span(r: Rect, axis: Axis, start: f64, len: f64) -> Rect {
1093
    match axis {
1094
        Axis::Horizontal => Rect::new(start, r.y, len, r.h),
1095
        Axis::Vertical => Rect::new(r.x, start, r.w, len),
1096
    }
1097
}