atagen

monolith

public
Star0
Watch0
91957f0ae29ec78a6601845bbf64b44d4cdfcb8e
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git

Blame: crates/layout/src/tree.rs

9baaafa4b167atagen2026-10-16 10:04 UTC1
use monolith_planner::Rect;
9baaafa4b167atagen2026-10-16 10:04 UTC2
use slotmap::{SlotMap, new_key_type};
9baaafa4b167atagen2026-10-16 10:04 UTC3
use std::collections::HashMap;
9baaafa4b167atagen2026-10-16 10:04 UTC4
use std::hash::Hash;
9baaafa4b167atagen2026-10-16 10:04 UTC5
9baaafa4b167atagen2026-10-16 10:04 UTC6
new_key_type! { pub struct NodeId; }
9baaafa4b167atagen2026-10-16 10:04 UTC7
9baaafa4b167atagen2026-10-16 10:04 UTC8
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
b22c0511d5afatagen2026-10-17 03:48 UTC9
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
b22c0511d5afatagen2026-10-17 03:48 UTC10
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
9baaafa4b167atagen2026-10-16 10:04 UTC11
pub enum Axis {
9baaafa4b167atagen2026-10-16 10:04 UTC12
    Horizontal,
9baaafa4b167atagen2026-10-16 10:04 UTC13
    Vertical,
9baaafa4b167atagen2026-10-16 10:04 UTC14
}
9baaafa4b167atagen2026-10-16 10:04 UTC15
9baaafa4b167atagen2026-10-16 10:04 UTC16
impl Axis {
9baaafa4b167atagen2026-10-16 10:04 UTC17
    pub fn other(self) -> Self {
9baaafa4b167atagen2026-10-16 10:04 UTC18
        match self {
9baaafa4b167atagen2026-10-16 10:04 UTC19
            Self::Horizontal => Self::Vertical,
9baaafa4b167atagen2026-10-16 10:04 UTC20
            Self::Vertical => Self::Horizontal,
9baaafa4b167atagen2026-10-16 10:04 UTC21
        }
9baaafa4b167atagen2026-10-16 10:04 UTC22
    }
9baaafa4b167atagen2026-10-16 10:04 UTC23
}
9baaafa4b167atagen2026-10-16 10:04 UTC24
9baaafa4b167atagen2026-10-16 10:04 UTC25
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
b22c0511d5afatagen2026-10-17 03:48 UTC26
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
b22c0511d5afatagen2026-10-17 03:48 UTC27
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
9baaafa4b167atagen2026-10-16 10:04 UTC28
pub enum Dir {
9baaafa4b167atagen2026-10-16 10:04 UTC29
    Left,
9baaafa4b167atagen2026-10-16 10:04 UTC30
    Right,
9baaafa4b167atagen2026-10-16 10:04 UTC31
    Up,
9baaafa4b167atagen2026-10-16 10:04 UTC32
    Down,
9baaafa4b167atagen2026-10-16 10:04 UTC33
}
9baaafa4b167atagen2026-10-16 10:04 UTC34
9baaafa4b167atagen2026-10-16 10:04 UTC35
impl Dir {
9baaafa4b167atagen2026-10-16 10:04 UTC36
    pub fn axis(self) -> Axis {
9baaafa4b167atagen2026-10-16 10:04 UTC37
        match self {
9baaafa4b167atagen2026-10-16 10:04 UTC38
            Self::Left | Self::Right => Axis::Horizontal,
9baaafa4b167atagen2026-10-16 10:04 UTC39
            Self::Up | Self::Down => Axis::Vertical,
9baaafa4b167atagen2026-10-16 10:04 UTC40
        }
9baaafa4b167atagen2026-10-16 10:04 UTC41
    }
9baaafa4b167atagen2026-10-16 10:04 UTC42
9baaafa4b167atagen2026-10-16 10:04 UTC43
    pub fn forward(self) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC44
        matches!(self, Self::Right | Self::Down)
9baaafa4b167atagen2026-10-16 10:04 UTC45
    }
9baaafa4b167atagen2026-10-16 10:04 UTC46
}
9baaafa4b167atagen2026-10-16 10:04 UTC47
9baaafa4b167atagen2026-10-16 10:04 UTC48
const MIN_SHARE: f64 = 0.05;
9baaafa4b167atagen2026-10-16 10:04 UTC49
9baaafa4b167atagen2026-10-16 10:04 UTC50
#[derive(Clone, Debug)]
9baaafa4b167atagen2026-10-16 10:04 UTC51
struct Child {
9baaafa4b167atagen2026-10-16 10:04 UTC52
    node: NodeId,
9baaafa4b167atagen2026-10-16 10:04 UTC53
    weight: f64,
9baaafa4b167atagen2026-10-16 10:04 UTC54
}
9baaafa4b167atagen2026-10-16 10:04 UTC55
9baaafa4b167atagen2026-10-16 10:04 UTC56
#[derive(Clone, Debug)]
9baaafa4b167atagen2026-10-16 10:04 UTC57
enum Kind<W> {
9baaafa4b167atagen2026-10-16 10:04 UTC58
    Leaf(W),
9baaafa4b167atagen2026-10-16 10:04 UTC59
    Container {
9baaafa4b167atagen2026-10-16 10:04 UTC60
        axis: Axis,
9baaafa4b167atagen2026-10-16 10:04 UTC61
        children: Vec<Child>,
9baaafa4b167atagen2026-10-16 10:04 UTC62
        expanded: Option<NodeId>,
9baaafa4b167atagen2026-10-16 10:04 UTC63
    },
9baaafa4b167atagen2026-10-16 10:04 UTC64
}
9baaafa4b167atagen2026-10-16 10:04 UTC65
9baaafa4b167atagen2026-10-16 10:04 UTC66
#[derive(Clone, Debug)]
9baaafa4b167atagen2026-10-16 10:04 UTC67
struct Node<W> {
9baaafa4b167atagen2026-10-16 10:04 UTC68
    parent: Option<NodeId>,
9baaafa4b167atagen2026-10-16 10:04 UTC69
    kind: Kind<W>,
9baaafa4b167atagen2026-10-16 10:04 UTC70
}
9baaafa4b167atagen2026-10-16 10:04 UTC71
9baaafa4b167atagen2026-10-16 10:04 UTC72
/// One output's tiling tree. Every tiled window of every tag lives here, the
9baaafa4b167atagen2026-10-16 10:04 UTC73
/// caller's visibility filter decides which ones take space.
9baaafa4b167atagen2026-10-16 10:04 UTC74
///
9baaafa4b167atagen2026-10-16 10:04 UTC75
/// Children run on the axis opposite their parent. Containers hold at least
9baaafa4b167atagen2026-10-16 10:04 UTC76
/// two children, hidden ones included, and a container left with one child
9baaafa4b167atagen2026-10-16 10:04 UTC77
/// is replaced by it.
9baaafa4b167atagen2026-10-16 10:04 UTC78
#[derive(Clone, Debug)]
9baaafa4b167atagen2026-10-16 10:04 UTC79
pub struct Tree<W> {
9baaafa4b167atagen2026-10-16 10:04 UTC80
    nodes: SlotMap<NodeId, Node<W>>,
9baaafa4b167atagen2026-10-16 10:04 UTC81
    root: Option<NodeId>,
9baaafa4b167atagen2026-10-16 10:04 UTC82
    leaves: HashMap<W, NodeId>,
9baaafa4b167atagen2026-10-16 10:04 UTC83
    stack: Axis,
9baaafa4b167atagen2026-10-16 10:04 UTC84
}
9baaafa4b167atagen2026-10-16 10:04 UTC85
9baaafa4b167atagen2026-10-16 10:04 UTC86
impl<W: Copy + Eq + Hash> Default for Tree<W> {
9baaafa4b167atagen2026-10-16 10:04 UTC87
    fn default() -> Self {
9baaafa4b167atagen2026-10-16 10:04 UTC88
        Self {
9baaafa4b167atagen2026-10-16 10:04 UTC89
            nodes: SlotMap::with_key(),
9baaafa4b167atagen2026-10-16 10:04 UTC90
            root: None,
9baaafa4b167atagen2026-10-16 10:04 UTC91
            leaves: HashMap::new(),
9baaafa4b167atagen2026-10-16 10:04 UTC92
            stack: Axis::Vertical,
9baaafa4b167atagen2026-10-16 10:04 UTC93
        }
9baaafa4b167atagen2026-10-16 10:04 UTC94
    }
9baaafa4b167atagen2026-10-16 10:04 UTC95
}
9baaafa4b167atagen2026-10-16 10:04 UTC96
9baaafa4b167atagen2026-10-16 10:04 UTC97
impl<W: Copy + Eq + Hash> Tree<W> {
9baaafa4b167atagen2026-10-16 10:04 UTC98
    /// The axis tag rows stack along.
9baaafa4b167atagen2026-10-16 10:04 UTC99
    pub fn stack_axis(&self) -> Axis {
9baaafa4b167atagen2026-10-16 10:04 UTC100
        self.stack
9baaafa4b167atagen2026-10-16 10:04 UTC101
    }
9baaafa4b167atagen2026-10-16 10:04 UTC102
9baaafa4b167atagen2026-10-16 10:04 UTC103
    pub fn contains(&self, w: W) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC104
        self.leaves.contains_key(&w)
9baaafa4b167atagen2026-10-16 10:04 UTC105
    }
9baaafa4b167atagen2026-10-16 10:04 UTC106
9baaafa4b167atagen2026-10-16 10:04 UTC107
    pub fn is_empty(&self) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC108
        self.root.is_none()
9baaafa4b167atagen2026-10-16 10:04 UTC109
    }
9baaafa4b167atagen2026-10-16 10:04 UTC110
9baaafa4b167atagen2026-10-16 10:04 UTC111
    pub fn windows(&self) -> impl Iterator<Item = W> + '_ {
9baaafa4b167atagen2026-10-16 10:04 UTC112
        self.leaves.keys().copied()
9baaafa4b167atagen2026-10-16 10:04 UTC113
    }
9baaafa4b167atagen2026-10-16 10:04 UTC114
9baaafa4b167atagen2026-10-16 10:04 UTC115
    /// Inserts `w` as the next sibling of `anchor`, or as a new row if
9baaafa4b167atagen2026-10-16 10:04 UTC116
    /// `anchor` is not in the tree.
9baaafa4b167atagen2026-10-16 10:04 UTC117
    pub fn insert_after(&mut self, w: W, anchor: W) {
9baaafa4b167atagen2026-10-16 10:04 UTC118
        let Some(&a) = self.leaves.get(&anchor) else {
9baaafa4b167atagen2026-10-16 10:04 UTC119
            return self.insert_row(w);
9baaafa4b167atagen2026-10-16 10:04 UTC120
        };
9baaafa4b167atagen2026-10-16 10:04 UTC121
        let n = self.new_leaf(w);
9baaafa4b167atagen2026-10-16 10:04 UTC122
        match self.position(a) {
9baaafa4b167atagen2026-10-16 10:04 UTC123
            Some((p, i)) if Some(p) == self.root && self.axis(p) == Some(self.stack) => {
9baaafa4b167atagen2026-10-16 10:04 UTC124
                let weight = self.unlink(p, i).weight;
9baaafa4b167atagen2026-10-16 10:04 UTC125
                let c = self.new_container(self.stack.other());
9baaafa4b167atagen2026-10-16 10:04 UTC126
                self.attach(c, 0, a, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC127
                self.attach(c, 1, n, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC128
                self.attach(p, i, c, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC129
            }
9baaafa4b167atagen2026-10-16 10:04 UTC130
            Some((p, i)) => {
9baaafa4b167atagen2026-10-16 10:04 UTC131
                let weight = self.mean_weight(p);
9baaafa4b167atagen2026-10-16 10:04 UTC132
                self.attach(p, i + 1, n, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC133
            }
9baaafa4b167atagen2026-10-16 10:04 UTC134
            None => {
9baaafa4b167atagen2026-10-16 10:04 UTC135
                let c = self.new_container(self.stack.other());
9baaafa4b167atagen2026-10-16 10:04 UTC136
                self.attach(c, 0, a, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC137
                self.attach(c, 1, n, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC138
                self.root = Some(c);
9baaafa4b167atagen2026-10-16 10:04 UTC139
            }
9baaafa4b167atagen2026-10-16 10:04 UTC140
        }
9baaafa4b167atagen2026-10-16 10:04 UTC141
    }
9baaafa4b167atagen2026-10-16 10:04 UTC142
9baaafa4b167atagen2026-10-16 10:04 UTC143
    /// Appends `w` as a row of its own along the stacking axis.
9baaafa4b167atagen2026-10-16 10:04 UTC144
    pub fn insert_row(&mut self, w: W) {
9baaafa4b167atagen2026-10-16 10:04 UTC145
        let n = self.new_leaf(w);
9baaafa4b167atagen2026-10-16 10:04 UTC146
        match self.root {
9baaafa4b167atagen2026-10-16 10:04 UTC147
            None => self.root = Some(n),
9baaafa4b167atagen2026-10-16 10:04 UTC148
            Some(r) if self.axis(r) == Some(self.stack) => {
9baaafa4b167atagen2026-10-16 10:04 UTC149
                let weight = self.mean_weight(r);
9baaafa4b167atagen2026-10-16 10:04 UTC150
                let end = self.children(r).len();
9baaafa4b167atagen2026-10-16 10:04 UTC151
                self.attach(r, end, n, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC152
            }
9baaafa4b167atagen2026-10-16 10:04 UTC153
            Some(r) => {
9baaafa4b167atagen2026-10-16 10:04 UTC154
                let c = self.new_container(self.stack);
9baaafa4b167atagen2026-10-16 10:04 UTC155
                self.attach(c, 0, r, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC156
                self.attach(c, 1, n, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC157
                self.root = Some(c);
9baaafa4b167atagen2026-10-16 10:04 UTC158
            }
9baaafa4b167atagen2026-10-16 10:04 UTC159
        }
9baaafa4b167atagen2026-10-16 10:04 UTC160
    }
9baaafa4b167atagen2026-10-16 10:04 UTC161
9baaafa4b167atagen2026-10-16 10:04 UTC162
    pub fn remove(&mut self, w: W) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC163
        let Some(n) = self.leaves.remove(&w) else {
9baaafa4b167atagen2026-10-16 10:04 UTC164
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC165
        };
9baaafa4b167atagen2026-10-16 10:04 UTC166
        self.detach(n);
9baaafa4b167atagen2026-10-16 10:04 UTC167
        self.nodes.remove(n);
9baaafa4b167atagen2026-10-16 10:04 UTC168
        true
9baaafa4b167atagen2026-10-16 10:04 UTC169
    }
9baaafa4b167atagen2026-10-16 10:04 UTC170
9baaafa4b167atagen2026-10-16 10:04 UTC171
    pub fn retain(&mut self, mut keep: impl FnMut(W) -> bool) {
9baaafa4b167atagen2026-10-16 10:04 UTC172
        let gone: Vec<W> = self.windows().filter(|&w| !keep(w)).collect();
9baaafa4b167atagen2026-10-16 10:04 UTC173
        for w in gone {
9baaafa4b167atagen2026-10-16 10:04 UTC174
            self.remove(w);
9baaafa4b167atagen2026-10-16 10:04 UTC175
        }
9baaafa4b167atagen2026-10-16 10:04 UTC176
    }
9baaafa4b167atagen2026-10-16 10:04 UTC177
9baaafa4b167atagen2026-10-16 10:04 UTC178
    /// Moves a window one step in `dir`. Leaves swap slots with the next
9baaafa4b167atagen2026-10-16 10:04 UTC179
    /// visible sibling, enter a sibling container, or step out beside their
9baaafa4b167atagen2026-10-16 10:04 UTC180
    /// container. Hidden windows never move.
9baaafa4b167atagen2026-10-16 10:04 UTC181
    pub fn move_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC182
        let Some(&n) = self.leaves.get(&w) else {
9baaafa4b167atagen2026-10-16 10:04 UTC183
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC184
        };
9baaafa4b167atagen2026-10-16 10:04 UTC185
        self.move_node(n, dir, &vis, true)
9baaafa4b167atagen2026-10-16 10:04 UTC186
    }
9baaafa4b167atagen2026-10-16 10:04 UTC187
9baaafa4b167atagen2026-10-16 10:04 UTC188
    /// Moves the container holding `w` as a rigid block. A window sitting
9baaafa4b167atagen2026-10-16 10:04 UTC189
    /// directly in the root is its own block.
4444c779eb48atagen2026-10-16 12:07 UTC190
    pub fn move_container(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC191
        let Some(&n) = self.leaves.get(&w) else {
9baaafa4b167atagen2026-10-16 10:04 UTC192
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC193
        };
9baaafa4b167atagen2026-10-16 10:04 UTC194
        let block = self.nodes[n]
9baaafa4b167atagen2026-10-16 10:04 UTC195
            .parent
9baaafa4b167atagen2026-10-16 10:04 UTC196
            .filter(|&p| Some(p) != self.root)
9baaafa4b167atagen2026-10-16 10:04 UTC197
            .unwrap_or(n);
9baaafa4b167atagen2026-10-16 10:04 UTC198
        self.move_node(block, dir, &vis, false)
9baaafa4b167atagen2026-10-16 10:04 UTC199
    }
9baaafa4b167atagen2026-10-16 10:04 UTC200
4444c779eb48atagen2026-10-16 12:07 UTC201
    /// Moves a window to the end of the next visible lane in `dir`, stepping
4444c779eb48atagen2026-10-16 12:07 UTC202
    /// up a level when its container has none that way. A lone window there
91957f0ae29eatagen2026-10-17 09:24 UTC203
    /// becomes a stack with it. With no lane anywhere that way, it leaves its
91957f0ae29eatagen2026-10-17 09:24 UTC204
    /// stack as `move_window` would.
4444c779eb48atagen2026-10-16 12:07 UTC205
    pub fn merge_window(&mut self, w: W, dir: Dir, vis: impl Fn(W) -> bool) -> bool {
4444c779eb48atagen2026-10-16 12:07 UTC206
        let Some(&n) = self.leaves.get(&w) else {
4444c779eb48atagen2026-10-16 12:07 UTC207
            return false;
4444c779eb48atagen2026-10-16 12:07 UTC208
        };
4444c779eb48atagen2026-10-16 12:07 UTC209
        let mut cur = n;
4444c779eb48atagen2026-10-16 12:07 UTC210
        while let Some((p, i)) = self.position(cur) {
4444c779eb48atagen2026-10-16 12:07 UTC211
            if self.axis(p) == Some(dir.axis())
4444c779eb48atagen2026-10-16 12:07 UTC212
                && let Some(j) = self.next_shown(p, i, dir, &vis)
4444c779eb48atagen2026-10-16 12:07 UTC213
            {
4444c779eb48atagen2026-10-16 12:07 UTC214
                self.join_lane(n, p, j);
4444c779eb48atagen2026-10-16 12:07 UTC215
                return true;
4444c779eb48atagen2026-10-16 12:07 UTC216
            }
4444c779eb48atagen2026-10-16 12:07 UTC217
            cur = p;
4444c779eb48atagen2026-10-16 12:07 UTC218
        }
91957f0ae29eatagen2026-10-17 09:24 UTC219
        self.move_node(n, dir, &vis, true)
4444c779eb48atagen2026-10-16 12:07 UTC220
    }
4444c779eb48atagen2026-10-16 12:07 UTC221
4444c779eb48atagen2026-10-16 12:07 UTC222
    /// Whether every container above `w` is expanded towards it.
4444c779eb48atagen2026-10-16 12:07 UTC223
    pub fn maximized(&self, w: W) -> bool {
4444c779eb48atagen2026-10-16 12:07 UTC224
        let Some(&leaf) = self.leaves.get(&w) else {
4444c779eb48atagen2026-10-16 12:07 UTC225
            return false;
4444c779eb48atagen2026-10-16 12:07 UTC226
        };
4444c779eb48atagen2026-10-16 12:07 UTC227
        let mut cur = leaf;
4444c779eb48atagen2026-10-16 12:07 UTC228
        let mut any = false;
4444c779eb48atagen2026-10-16 12:07 UTC229
        while let Some(p) = self.nodes[cur].parent {
4444c779eb48atagen2026-10-16 12:07 UTC230
            if self.expanded(p) != Some(cur) {
4444c779eb48atagen2026-10-16 12:07 UTC231
                return false;
4444c779eb48atagen2026-10-16 12:07 UTC232
            }
4444c779eb48atagen2026-10-16 12:07 UTC233
            any = true;
4444c779eb48atagen2026-10-16 12:07 UTC234
            cur = p;
4444c779eb48atagen2026-10-16 12:07 UTC235
        }
4444c779eb48atagen2026-10-16 12:07 UTC236
        any
4444c779eb48atagen2026-10-16 12:07 UTC237
    }
4444c779eb48atagen2026-10-16 12:07 UTC238
9baaafa4b167atagen2026-10-16 10:04 UTC239
    /// Transposes the whole tree.
9baaafa4b167atagen2026-10-16 10:04 UTC240
    pub fn flip(&mut self) {
9baaafa4b167atagen2026-10-16 10:04 UTC241
        self.stack = self.stack.other();
9baaafa4b167atagen2026-10-16 10:04 UTC242
        for node in self.nodes.values_mut() {
9baaafa4b167atagen2026-10-16 10:04 UTC243
            if let Kind::Container { axis, .. } = &mut node.kind {
9baaafa4b167atagen2026-10-16 10:04 UTC244
                *axis = axis.other();
9baaafa4b167atagen2026-10-16 10:04 UTC245
            }
9baaafa4b167atagen2026-10-16 10:04 UTC246
        }
9baaafa4b167atagen2026-10-16 10:04 UTC247
    }
9baaafa4b167atagen2026-10-16 10:04 UTC248
9baaafa4b167atagen2026-10-16 10:04 UTC249
    /// Toggles expansion for `count` levels of `w`'s ancestry, starting
9baaafa4b167atagen2026-10-16 10:04 UTC250
    /// `skip` levels up. Level 0 expands the window inside its container.
9baaafa4b167atagen2026-10-16 10:04 UTC251
    pub fn toggle_expand(&mut self, w: W, skip: usize, count: usize) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC252
        let Some(&leaf) = self.leaves.get(&w) else {
9baaafa4b167atagen2026-10-16 10:04 UTC253
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC254
        };
9baaafa4b167atagen2026-10-16 10:04 UTC255
        let mut path = Vec::new();
9baaafa4b167atagen2026-10-16 10:04 UTC256
        let mut cur = leaf;
9baaafa4b167atagen2026-10-16 10:04 UTC257
        while let Some(p) = self.nodes[cur].parent {
9baaafa4b167atagen2026-10-16 10:04 UTC258
            path.push((p, cur));
9baaafa4b167atagen2026-10-16 10:04 UTC259
            cur = p;
9baaafa4b167atagen2026-10-16 10:04 UTC260
        }
9baaafa4b167atagen2026-10-16 10:04 UTC261
        let path: Vec<_> = path.into_iter().skip(skip).take(count).collect();
9baaafa4b167atagen2026-10-16 10:04 UTC262
        if path.is_empty() {
9baaafa4b167atagen2026-10-16 10:04 UTC263
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC264
        }
9baaafa4b167atagen2026-10-16 10:04 UTC265
        let all = path.iter().all(|&(p, c)| self.expanded(p) == Some(c));
9baaafa4b167atagen2026-10-16 10:04 UTC266
        for (p, c) in path {
9baaafa4b167atagen2026-10-16 10:04 UTC267
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC268
                *expanded = (!all).then_some(c);
9baaafa4b167atagen2026-10-16 10:04 UTC269
            }
9baaafa4b167atagen2026-10-16 10:04 UTC270
        }
9baaafa4b167atagen2026-10-16 10:04 UTC271
        true
9baaafa4b167atagen2026-10-16 10:04 UTC272
    }
9baaafa4b167atagen2026-10-16 10:04 UTC273
9baaafa4b167atagen2026-10-16 10:04 UTC274
    /// Grows `w` by `delta`, a fraction of the visible length of the nearest
9baaafa4b167atagen2026-10-16 10:04 UTC275
    /// container along `axis` where it has a visible sibling. Hidden siblings
9baaafa4b167atagen2026-10-16 10:04 UTC276
    /// keep their weights, and with them their share.
9baaafa4b167atagen2026-10-16 10:04 UTC277
    pub fn resize(&mut self, w: W, axis: Axis, delta: f64, vis: impl Fn(W) -> bool) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC278
        let Some(&leaf) = self.leaves.get(&w) else {
9baaafa4b167atagen2026-10-16 10:04 UTC279
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC280
        };
9baaafa4b167atagen2026-10-16 10:04 UTC281
        let mut cur = leaf;
9baaafa4b167atagen2026-10-16 10:04 UTC282
        while let Some((p, i)) = self.position(cur) {
9baaafa4b167atagen2026-10-16 10:04 UTC283
            if self.axis(p) == Some(axis) {
9baaafa4b167atagen2026-10-16 10:04 UTC284
                let shown: Vec<usize> = (0..self.children(p).len())
9baaafa4b167atagen2026-10-16 10:04 UTC285
                    .filter(|&j| self.visible(self.children(p)[j].node, &vis))
9baaafa4b167atagen2026-10-16 10:04 UTC286
                    .collect();
9baaafa4b167atagen2026-10-16 10:04 UTC287
                if shown.len() >= 2 {
9baaafa4b167atagen2026-10-16 10:04 UTC288
                    let children = self.children_mut(p);
9baaafa4b167atagen2026-10-16 10:04 UTC289
                    let sum: f64 = shown.iter().map(|&j| children[j].weight).sum();
9baaafa4b167atagen2026-10-16 10:04 UTC290
                    let old = children[i].weight;
9baaafa4b167atagen2026-10-16 10:04 UTC291
                    let max = 1.0 - MIN_SHARE * (shown.len() - 1) as f64;
9baaafa4b167atagen2026-10-16 10:04 UTC292
                    let new = (old / sum + delta).clamp(MIN_SHARE, max) * sum;
9baaafa4b167atagen2026-10-16 10:04 UTC293
                    let scale = (sum - new) / (sum - old);
9baaafa4b167atagen2026-10-16 10:04 UTC294
                    for j in shown {
9baaafa4b167atagen2026-10-16 10:04 UTC295
                        children[j].weight = if j == i {
9baaafa4b167atagen2026-10-16 10:04 UTC296
                            new
9baaafa4b167atagen2026-10-16 10:04 UTC297
                        } else {
9baaafa4b167atagen2026-10-16 10:04 UTC298
                            children[j].weight * scale
9baaafa4b167atagen2026-10-16 10:04 UTC299
                        };
9baaafa4b167atagen2026-10-16 10:04 UTC300
                    }
9baaafa4b167atagen2026-10-16 10:04 UTC301
                    return true;
9baaafa4b167atagen2026-10-16 10:04 UTC302
                }
9baaafa4b167atagen2026-10-16 10:04 UTC303
            }
9baaafa4b167atagen2026-10-16 10:04 UTC304
            cur = p;
9baaafa4b167atagen2026-10-16 10:04 UTC305
        }
9baaafa4b167atagen2026-10-16 10:04 UTC306
        false
9baaafa4b167atagen2026-10-16 10:04 UTC307
    }
9baaafa4b167atagen2026-10-16 10:04 UTC308
9baaafa4b167atagen2026-10-16 10:04 UTC309
    /// Lays the tree out in `area`. Hidden windows come back as zero-size
9baaafa4b167atagen2026-10-16 10:04 UTC310
    /// rects on the boundary where they would reappear.
9baaafa4b167atagen2026-10-16 10:04 UTC311
    pub fn arrange(&self, area: Rect, gap: f64, vis: impl Fn(W) -> bool) -> Vec<(W, Rect)> {
9baaafa4b167atagen2026-10-16 10:04 UTC312
        let mut out = Vec::with_capacity(self.leaves.len());
9baaafa4b167atagen2026-10-16 10:04 UTC313
        if let Some(r) = self.root {
1c8e1b4009f5atagen2026-10-16 23:19 UTC314
            let area = if self.visible(r, &vis) {
1c8e1b4009f5atagen2026-10-16 23:19 UTC315
                area
1c8e1b4009f5atagen2026-10-16 23:19 UTC316
            } else {
1c8e1b4009f5atagen2026-10-16 23:19 UTC317
                Rect::new(area.x + area.w / 2.0, area.y, 0.0, area.h)
1c8e1b4009f5atagen2026-10-16 23:19 UTC318
            };
9baaafa4b167atagen2026-10-16 10:04 UTC319
            self.place(r, area, gap, &vis, &mut out);
9baaafa4b167atagen2026-10-16 10:04 UTC320
        }
9baaafa4b167atagen2026-10-16 10:04 UTC321
        out
9baaafa4b167atagen2026-10-16 10:04 UTC322
    }
9baaafa4b167atagen2026-10-16 10:04 UTC323
9baaafa4b167atagen2026-10-16 10:04 UTC324
    fn place(
9baaafa4b167atagen2026-10-16 10:04 UTC325
        &self,
9baaafa4b167atagen2026-10-16 10:04 UTC326
        n: NodeId,
9baaafa4b167atagen2026-10-16 10:04 UTC327
        r: Rect,
9baaafa4b167atagen2026-10-16 10:04 UTC328
        gap: f64,
9baaafa4b167atagen2026-10-16 10:04 UTC329
        vis: &impl Fn(W) -> bool,
9baaafa4b167atagen2026-10-16 10:04 UTC330
        out: &mut Vec<(W, Rect)>,
9baaafa4b167atagen2026-10-16 10:04 UTC331
    ) {
9baaafa4b167atagen2026-10-16 10:04 UTC332
        let (axis, children, expanded) = match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC333
            Kind::Leaf(w) => return out.push((*w, r)),
9baaafa4b167atagen2026-10-16 10:04 UTC334
            Kind::Container {
9baaafa4b167atagen2026-10-16 10:04 UTC335
                axis,
9baaafa4b167atagen2026-10-16 10:04 UTC336
                children,
9baaafa4b167atagen2026-10-16 10:04 UTC337
                expanded,
9baaafa4b167atagen2026-10-16 10:04 UTC338
            } => (*axis, children, *expanded),
9baaafa4b167atagen2026-10-16 10:04 UTC339
        };
9baaafa4b167atagen2026-10-16 10:04 UTC340
        let shown: Vec<bool> = children.iter().map(|c| self.visible(c.node, vis)).collect();
9baaafa4b167atagen2026-10-16 10:04 UTC341
        let (start, len) = span(r, axis);
9baaafa4b167atagen2026-10-16 10:04 UTC342
        if let Some(e) = expanded.and_then(|e| children.iter().position(|c| c.node == e))
9baaafa4b167atagen2026-10-16 10:04 UTC343
            && shown[e]
9baaafa4b167atagen2026-10-16 10:04 UTC344
        {
9baaafa4b167atagen2026-10-16 10:04 UTC345
            for (i, c) in children.iter().enumerate() {
9baaafa4b167atagen2026-10-16 10:04 UTC346
                let sub = match i.cmp(&e) {
9baaafa4b167atagen2026-10-16 10:04 UTC347
                    std::cmp::Ordering::Equal => r,
9baaafa4b167atagen2026-10-16 10:04 UTC348
                    std::cmp::Ordering::Less => with_span(r, axis, start, 0.0),
9baaafa4b167atagen2026-10-16 10:04 UTC349
                    std::cmp::Ordering::Greater => with_span(r, axis, start + len, 0.0),
9baaafa4b167atagen2026-10-16 10:04 UTC350
                };
9baaafa4b167atagen2026-10-16 10:04 UTC351
                self.place(c.node, sub, gap, vis, out);
9baaafa4b167atagen2026-10-16 10:04 UTC352
            }
9baaafa4b167atagen2026-10-16 10:04 UTC353
            return;
9baaafa4b167atagen2026-10-16 10:04 UTC354
        }
9baaafa4b167atagen2026-10-16 10:04 UTC355
        let count = shown.iter().filter(|s| **s).count();
9baaafa4b167atagen2026-10-16 10:04 UTC356
        let total: f64 = children
9baaafa4b167atagen2026-10-16 10:04 UTC357
            .iter()
9baaafa4b167atagen2026-10-16 10:04 UTC358
            .zip(&shown)
9baaafa4b167atagen2026-10-16 10:04 UTC359
            .filter(|(_, s)| **s)
9baaafa4b167atagen2026-10-16 10:04 UTC360
            .map(|(c, _)| c.weight)
9baaafa4b167atagen2026-10-16 10:04 UTC361
            .sum();
9baaafa4b167atagen2026-10-16 10:04 UTC362
        let gaps = count.saturating_sub(1) as f64;
9baaafa4b167atagen2026-10-16 10:04 UTC363
        let gap = if gaps > 0.0 { gap.min(len / gaps) } else { gap };
9baaafa4b167atagen2026-10-16 10:04 UTC364
        let avail = len - gap * gaps;
9baaafa4b167atagen2026-10-16 10:04 UTC365
        let last = shown.iter().rposition(|s| *s);
9baaafa4b167atagen2026-10-16 10:04 UTC366
        let mut pos = start;
9baaafa4b167atagen2026-10-16 10:04 UTC367
        let mut seen = false;
9baaafa4b167atagen2026-10-16 10:04 UTC368
        for (i, c) in children.iter().enumerate() {
9baaafa4b167atagen2026-10-16 10:04 UTC369
            if shown[i] {
9baaafa4b167atagen2026-10-16 10:04 UTC370
                if seen {
9baaafa4b167atagen2026-10-16 10:04 UTC371
                    pos += gap;
9baaafa4b167atagen2026-10-16 10:04 UTC372
                }
9baaafa4b167atagen2026-10-16 10:04 UTC373
                let l = avail * c.weight / total;
9baaafa4b167atagen2026-10-16 10:04 UTC374
                self.place(c.node, with_span(r, axis, pos, l), gap, vis, out);
9baaafa4b167atagen2026-10-16 10:04 UTC375
                pos += l;
9baaafa4b167atagen2026-10-16 10:04 UTC376
                seen = true;
9baaafa4b167atagen2026-10-16 10:04 UTC377
            } else {
9baaafa4b167atagen2026-10-16 10:04 UTC378
                let between = seen && last.is_some_and(|l| l > i);
9baaafa4b167atagen2026-10-16 10:04 UTC379
                let at = if between { pos + gap / 2.0 } else { pos };
9baaafa4b167atagen2026-10-16 10:04 UTC380
                self.place(c.node, with_span(r, axis, at, 0.0), gap, vis, out);
9baaafa4b167atagen2026-10-16 10:04 UTC381
            }
9baaafa4b167atagen2026-10-16 10:04 UTC382
        }
9baaafa4b167atagen2026-10-16 10:04 UTC383
    }
9baaafa4b167atagen2026-10-16 10:04 UTC384
9baaafa4b167atagen2026-10-16 10:04 UTC385
    fn move_node(&mut self, n: NodeId, dir: Dir, vis: &impl Fn(W) -> bool, enter: bool) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC386
        let mut cur = n;
9baaafa4b167atagen2026-10-16 10:04 UTC387
        while let Some((p, i)) = self.position(cur) {
9baaafa4b167atagen2026-10-16 10:04 UTC388
            if self.axis(p) == Some(dir.axis()) {
60f00dd4f2beatagen2026-10-16 11:50 UTC389
                let hidden_lane = self
60f00dd4f2beatagen2026-10-16 11:50 UTC390
                    .adjacent(p, i, dir)
60f00dd4f2beatagen2026-10-16 11:50 UTC391
                    .filter(|&j| enter && !self.visible(self.children(p)[j].node, vis));
9baaafa4b167atagen2026-10-16 10:04 UTC392
                if cur != n {
60f00dd4f2beatagen2026-10-16 11:50 UTC393
                    if let Some(j) = hidden_lane {
60f00dd4f2beatagen2026-10-16 11:50 UTC394
                        self.join_lane(n, p, j);
60f00dd4f2beatagen2026-10-16 11:50 UTC395
                    } else {
60f00dd4f2beatagen2026-10-16 11:50 UTC396
                        let at = if dir.forward() { i + 1 } else { i };
60f00dd4f2beatagen2026-10-16 11:50 UTC397
                        self.relocate(n, p, at);
60f00dd4f2beatagen2026-10-16 11:50 UTC398
                    }
9baaafa4b167atagen2026-10-16 10:04 UTC399
                    return true;
9baaafa4b167atagen2026-10-16 10:04 UTC400
                }
9baaafa4b167atagen2026-10-16 10:04 UTC401
                if let Some(j) = self.next_shown(p, i, dir, vis) {
9baaafa4b167atagen2026-10-16 10:04 UTC402
                    let sib = self.children(p)[j].node;
9baaafa4b167atagen2026-10-16 10:04 UTC403
                    if enter && self.axis(sib).is_some() {
9baaafa4b167atagen2026-10-16 10:04 UTC404
                        let end = self.children(sib).len();
9baaafa4b167atagen2026-10-16 10:04 UTC405
                        self.relocate(n, sib, end);
9baaafa4b167atagen2026-10-16 10:04 UTC406
                    } else {
9baaafa4b167atagen2026-10-16 10:04 UTC407
                        let children = self.children_mut(p);
9baaafa4b167atagen2026-10-16 10:04 UTC408
                        children[i].node = sib;
9baaafa4b167atagen2026-10-16 10:04 UTC409
                        children[j].node = n;
9baaafa4b167atagen2026-10-16 10:04 UTC410
                    }
9baaafa4b167atagen2026-10-16 10:04 UTC411
                    return true;
9baaafa4b167atagen2026-10-16 10:04 UTC412
                }
60f00dd4f2beatagen2026-10-16 11:50 UTC413
                if let Some(j) = hidden_lane {
60f00dd4f2beatagen2026-10-16 11:50 UTC414
                    self.join_lane(n, p, j);
60f00dd4f2beatagen2026-10-16 11:50 UTC415
                    return true;
60f00dd4f2beatagen2026-10-16 11:50 UTC416
                }
9baaafa4b167atagen2026-10-16 10:04 UTC417
            }
9baaafa4b167atagen2026-10-16 10:04 UTC418
            cur = p;
9baaafa4b167atagen2026-10-16 10:04 UTC419
        }
9baaafa4b167atagen2026-10-16 10:04 UTC420
        if cur == n || self.axis(cur) == Some(dir.axis()) {
9baaafa4b167atagen2026-10-16 10:04 UTC421
            return false;
9baaafa4b167atagen2026-10-16 10:04 UTC422
        }
9baaafa4b167atagen2026-10-16 10:04 UTC423
        let (old, i) = self.position(n).expect("n is below the root");
9baaafa4b167atagen2026-10-16 10:04 UTC424
        self.unlink(old, i);
9baaafa4b167atagen2026-10-16 10:04 UTC425
        self.normalize(old);
9baaafa4b167atagen2026-10-16 10:04 UTC426
        let r = self.root.expect("the rest of the tree survives");
9baaafa4b167atagen2026-10-16 10:04 UTC427
        if self.axis(r) == Some(dir.axis()) {
9baaafa4b167atagen2026-10-16 10:04 UTC428
            let weight = self.mean_weight(r);
9baaafa4b167atagen2026-10-16 10:04 UTC429
            let at = if dir.forward() {
9baaafa4b167atagen2026-10-16 10:04 UTC430
                self.children(r).len()
9baaafa4b167atagen2026-10-16 10:04 UTC431
            } else {
9baaafa4b167atagen2026-10-16 10:04 UTC432
                0
9baaafa4b167atagen2026-10-16 10:04 UTC433
            };
9baaafa4b167atagen2026-10-16 10:04 UTC434
            self.attach(r, at, n, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC435
        } else {
9baaafa4b167atagen2026-10-16 10:04 UTC436
            let c = self.new_container(dir.axis());
9baaafa4b167atagen2026-10-16 10:04 UTC437
            self.attach(c, 0, r, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC438
            let at = if dir.forward() {
9baaafa4b167atagen2026-10-16 10:04 UTC439
                self.children(c).len()
9baaafa4b167atagen2026-10-16 10:04 UTC440
            } else {
9baaafa4b167atagen2026-10-16 10:04 UTC441
                0
9baaafa4b167atagen2026-10-16 10:04 UTC442
            };
9baaafa4b167atagen2026-10-16 10:04 UTC443
            self.attach(c, at, n, 1.0);
9baaafa4b167atagen2026-10-16 10:04 UTC444
            self.root = Some(c);
9baaafa4b167atagen2026-10-16 10:04 UTC445
        }
9baaafa4b167atagen2026-10-16 10:04 UTC446
        true
9baaafa4b167atagen2026-10-16 10:04 UTC447
    }
9baaafa4b167atagen2026-10-16 10:04 UTC448
9baaafa4b167atagen2026-10-16 10:04 UTC449
    fn next_shown(&self, p: NodeId, i: usize, dir: Dir, vis: &impl Fn(W) -> bool) -> Option<usize> {
9baaafa4b167atagen2026-10-16 10:04 UTC450
        let children = self.children(p);
9baaafa4b167atagen2026-10-16 10:04 UTC451
        if dir.forward() {
9baaafa4b167atagen2026-10-16 10:04 UTC452
            (i + 1..children.len()).find(|&j| self.visible(children[j].node, vis))
9baaafa4b167atagen2026-10-16 10:04 UTC453
        } else {
9baaafa4b167atagen2026-10-16 10:04 UTC454
            (0..i).rev().find(|&j| self.visible(children[j].node, vis))
9baaafa4b167atagen2026-10-16 10:04 UTC455
        }
9baaafa4b167atagen2026-10-16 10:04 UTC456
    }
9baaafa4b167atagen2026-10-16 10:04 UTC457
60f00dd4f2beatagen2026-10-16 11:50 UTC458
    fn adjacent(&self, p: NodeId, i: usize, dir: Dir) -> Option<usize> {
60f00dd4f2beatagen2026-10-16 11:50 UTC459
        let j = if dir.forward() {
60f00dd4f2beatagen2026-10-16 11:50 UTC460
            i + 1
60f00dd4f2beatagen2026-10-16 11:50 UTC461
        } else {
60f00dd4f2beatagen2026-10-16 11:50 UTC462
            i.checked_sub(1)?
60f00dd4f2beatagen2026-10-16 11:50 UTC463
        };
60f00dd4f2beatagen2026-10-16 11:50 UTC464
        (j < self.children(p).len()).then_some(j)
60f00dd4f2beatagen2026-10-16 11:50 UTC465
    }
60f00dd4f2beatagen2026-10-16 11:50 UTC466
4444c779eb48atagen2026-10-16 12:07 UTC467
    /// Moves `n` to the end of the lane at `p`'s child `j`. A lone window
4444c779eb48atagen2026-10-16 12:07 UTC468
    /// there becomes a lane of its own, perpendicular to `p`.
60f00dd4f2beatagen2026-10-16 11:50 UTC469
    fn join_lane(&mut self, n: NodeId, p: NodeId, j: usize) {
60f00dd4f2beatagen2026-10-16 11:50 UTC470
        let lane = self.children(p)[j].node;
60f00dd4f2beatagen2026-10-16 11:50 UTC471
        let lane = if self.axis(lane).is_some() {
60f00dd4f2beatagen2026-10-16 11:50 UTC472
            lane
60f00dd4f2beatagen2026-10-16 11:50 UTC473
        } else {
60f00dd4f2beatagen2026-10-16 11:50 UTC474
            let c = self.new_container(self.axis(p).expect("p is a container").other());
60f00dd4f2beatagen2026-10-16 11:50 UTC475
            self.children_mut(p)[j].node = c;
60f00dd4f2beatagen2026-10-16 11:50 UTC476
            self.nodes[c].parent = Some(p);
60f00dd4f2beatagen2026-10-16 11:50 UTC477
            if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
60f00dd4f2beatagen2026-10-16 11:50 UTC478
                && *expanded == Some(lane)
60f00dd4f2beatagen2026-10-16 11:50 UTC479
            {
60f00dd4f2beatagen2026-10-16 11:50 UTC480
                *expanded = Some(c);
60f00dd4f2beatagen2026-10-16 11:50 UTC481
            }
60f00dd4f2beatagen2026-10-16 11:50 UTC482
            self.attach(c, 0, lane, 1.0);
60f00dd4f2beatagen2026-10-16 11:50 UTC483
            c
60f00dd4f2beatagen2026-10-16 11:50 UTC484
        };
60f00dd4f2beatagen2026-10-16 11:50 UTC485
        let end = self.children(lane).len();
60f00dd4f2beatagen2026-10-16 11:50 UTC486
        self.relocate(n, lane, end);
60f00dd4f2beatagen2026-10-16 11:50 UTC487
    }
60f00dd4f2beatagen2026-10-16 11:50 UTC488
9baaafa4b167atagen2026-10-16 10:04 UTC489
    fn relocate(&mut self, n: NodeId, p: NodeId, at: usize) {
9baaafa4b167atagen2026-10-16 10:04 UTC490
        let (old, i) = self.position(n).expect("relocated nodes have a parent");
9baaafa4b167atagen2026-10-16 10:04 UTC491
        let weight = self.mean_weight(p);
9baaafa4b167atagen2026-10-16 10:04 UTC492
        let at = if old == p && i < at { at - 1 } else { at };
9baaafa4b167atagen2026-10-16 10:04 UTC493
        self.unlink(old, i);
9baaafa4b167atagen2026-10-16 10:04 UTC494
        self.attach(p, at, n, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC495
        self.normalize(old);
9baaafa4b167atagen2026-10-16 10:04 UTC496
    }
9baaafa4b167atagen2026-10-16 10:04 UTC497
9baaafa4b167atagen2026-10-16 10:04 UTC498
    /// Places `node` among `p`'s children. A container running along `p`'s
9baaafa4b167atagen2026-10-16 10:04 UTC499
    /// axis is dissolved into `p` so axes keep alternating.
9baaafa4b167atagen2026-10-16 10:04 UTC500
    fn attach(&mut self, p: NodeId, at: usize, node: NodeId, weight: f64) {
9baaafa4b167atagen2026-10-16 10:04 UTC501
        if self.axis(node) == self.axis(p) {
9baaafa4b167atagen2026-10-16 10:04 UTC502
            let Some(Node {
9baaafa4b167atagen2026-10-16 10:04 UTC503
                kind: Kind::Container { children, .. },
9baaafa4b167atagen2026-10-16 10:04 UTC504
                ..
9baaafa4b167atagen2026-10-16 10:04 UTC505
            }) = self.nodes.remove(node)
9baaafa4b167atagen2026-10-16 10:04 UTC506
            else {
9baaafa4b167atagen2026-10-16 10:04 UTC507
                unreachable!("only containers have an axis");
9baaafa4b167atagen2026-10-16 10:04 UTC508
            };
9baaafa4b167atagen2026-10-16 10:04 UTC509
            let total: f64 = children.iter().map(|c| c.weight).sum();
9baaafa4b167atagen2026-10-16 10:04 UTC510
            for (k, c) in children.into_iter().enumerate() {
9baaafa4b167atagen2026-10-16 10:04 UTC511
                self.nodes[c.node].parent = Some(p);
9baaafa4b167atagen2026-10-16 10:04 UTC512
                let weight = weight * c.weight / total;
9baaafa4b167atagen2026-10-16 10:04 UTC513
                self.children_mut(p).insert(
9baaafa4b167atagen2026-10-16 10:04 UTC514
                    at + k,
9baaafa4b167atagen2026-10-16 10:04 UTC515
                    Child {
9baaafa4b167atagen2026-10-16 10:04 UTC516
                        node: c.node,
9baaafa4b167atagen2026-10-16 10:04 UTC517
                        weight,
9baaafa4b167atagen2026-10-16 10:04 UTC518
                    },
9baaafa4b167atagen2026-10-16 10:04 UTC519
                );
9baaafa4b167atagen2026-10-16 10:04 UTC520
            }
9baaafa4b167atagen2026-10-16 10:04 UTC521
        } else {
9baaafa4b167atagen2026-10-16 10:04 UTC522
            self.nodes[node].parent = Some(p);
9baaafa4b167atagen2026-10-16 10:04 UTC523
            self.children_mut(p).insert(at, Child { node, weight });
9baaafa4b167atagen2026-10-16 10:04 UTC524
        }
9baaafa4b167atagen2026-10-16 10:04 UTC525
    }
9baaafa4b167atagen2026-10-16 10:04 UTC526
9baaafa4b167atagen2026-10-16 10:04 UTC527
    fn unlink(&mut self, p: NodeId, i: usize) -> Child {
9baaafa4b167atagen2026-10-16 10:04 UTC528
        let Kind::Container {
9baaafa4b167atagen2026-10-16 10:04 UTC529
            children, expanded, ..
9baaafa4b167atagen2026-10-16 10:04 UTC530
        } = &mut self.nodes[p].kind
9baaafa4b167atagen2026-10-16 10:04 UTC531
        else {
9baaafa4b167atagen2026-10-16 10:04 UTC532
            unreachable!("parents are containers");
9baaafa4b167atagen2026-10-16 10:04 UTC533
        };
9baaafa4b167atagen2026-10-16 10:04 UTC534
        let child = children.remove(i);
9baaafa4b167atagen2026-10-16 10:04 UTC535
        if *expanded == Some(child.node) {
9baaafa4b167atagen2026-10-16 10:04 UTC536
            *expanded = None;
9baaafa4b167atagen2026-10-16 10:04 UTC537
        }
9baaafa4b167atagen2026-10-16 10:04 UTC538
        self.nodes[child.node].parent = None;
9baaafa4b167atagen2026-10-16 10:04 UTC539
        child
9baaafa4b167atagen2026-10-16 10:04 UTC540
    }
9baaafa4b167atagen2026-10-16 10:04 UTC541
9baaafa4b167atagen2026-10-16 10:04 UTC542
    fn detach(&mut self, n: NodeId) {
9baaafa4b167atagen2026-10-16 10:04 UTC543
        match self.position(n) {
9baaafa4b167atagen2026-10-16 10:04 UTC544
            Some((p, i)) => {
9baaafa4b167atagen2026-10-16 10:04 UTC545
                self.unlink(p, i);
9baaafa4b167atagen2026-10-16 10:04 UTC546
                self.normalize(p);
9baaafa4b167atagen2026-10-16 10:04 UTC547
            }
9baaafa4b167atagen2026-10-16 10:04 UTC548
            None => self.root = None,
9baaafa4b167atagen2026-10-16 10:04 UTC549
        }
9baaafa4b167atagen2026-10-16 10:04 UTC550
    }
9baaafa4b167atagen2026-10-16 10:04 UTC551
9baaafa4b167atagen2026-10-16 10:04 UTC552
    /// Repairs a container that lost a child.
9baaafa4b167atagen2026-10-16 10:04 UTC553
    fn normalize(&mut self, c: NodeId) {
9baaafa4b167atagen2026-10-16 10:04 UTC554
        if self.children(c).len() >= 2 {
9baaafa4b167atagen2026-10-16 10:04 UTC555
            return;
9baaafa4b167atagen2026-10-16 10:04 UTC556
        }
9baaafa4b167atagen2026-10-16 10:04 UTC557
        let pos = self.position(c);
9baaafa4b167atagen2026-10-16 10:04 UTC558
        let was_expanded = pos.is_some_and(|(p, _)| self.expanded(p) == Some(c));
9baaafa4b167atagen2026-10-16 10:04 UTC559
        let Some(Node {
9baaafa4b167atagen2026-10-16 10:04 UTC560
            kind: Kind::Container { children, .. },
9baaafa4b167atagen2026-10-16 10:04 UTC561
            ..
9baaafa4b167atagen2026-10-16 10:04 UTC562
        }) = self.nodes.remove(c)
9baaafa4b167atagen2026-10-16 10:04 UTC563
        else {
9baaafa4b167atagen2026-10-16 10:04 UTC564
            unreachable!("only containers are normalized");
9baaafa4b167atagen2026-10-16 10:04 UTC565
        };
9baaafa4b167atagen2026-10-16 10:04 UTC566
        let only = children.into_iter().next();
9baaafa4b167atagen2026-10-16 10:04 UTC567
        match (only, pos) {
9baaafa4b167atagen2026-10-16 10:04 UTC568
            (None, Some((p, i))) => {
9baaafa4b167atagen2026-10-16 10:04 UTC569
                self.unlink_dead(p, i);
9baaafa4b167atagen2026-10-16 10:04 UTC570
                self.normalize(p);
9baaafa4b167atagen2026-10-16 10:04 UTC571
            }
9baaafa4b167atagen2026-10-16 10:04 UTC572
            (None, None) => self.root = None,
9baaafa4b167atagen2026-10-16 10:04 UTC573
            (Some(only), Some((p, i))) => {
9baaafa4b167atagen2026-10-16 10:04 UTC574
                let weight = self.unlink_dead(p, i).weight;
9baaafa4b167atagen2026-10-16 10:04 UTC575
                let leaf_like = self.axis(only.node) != self.axis(p);
9baaafa4b167atagen2026-10-16 10:04 UTC576
                self.attach(p, i, only.node, weight);
9baaafa4b167atagen2026-10-16 10:04 UTC577
                if was_expanded
9baaafa4b167atagen2026-10-16 10:04 UTC578
                    && leaf_like
9baaafa4b167atagen2026-10-16 10:04 UTC579
                    && let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
9baaafa4b167atagen2026-10-16 10:04 UTC580
                {
9baaafa4b167atagen2026-10-16 10:04 UTC581
                    *expanded = Some(only.node);
9baaafa4b167atagen2026-10-16 10:04 UTC582
                }
9baaafa4b167atagen2026-10-16 10:04 UTC583
            }
9baaafa4b167atagen2026-10-16 10:04 UTC584
            (Some(only), None) => {
9baaafa4b167atagen2026-10-16 10:04 UTC585
                self.nodes[only.node].parent = None;
9baaafa4b167atagen2026-10-16 10:04 UTC586
                self.root = Some(only.node);
9baaafa4b167atagen2026-10-16 10:04 UTC587
            }
9baaafa4b167atagen2026-10-16 10:04 UTC588
        }
9baaafa4b167atagen2026-10-16 10:04 UTC589
    }
9baaafa4b167atagen2026-10-16 10:04 UTC590
9baaafa4b167atagen2026-10-16 10:04 UTC591
    /// Like `unlink`, for a child whose node is already gone.
9baaafa4b167atagen2026-10-16 10:04 UTC592
    fn unlink_dead(&mut self, p: NodeId, i: usize) -> Child {
9baaafa4b167atagen2026-10-16 10:04 UTC593
        let Kind::Container {
9baaafa4b167atagen2026-10-16 10:04 UTC594
            children, expanded, ..
9baaafa4b167atagen2026-10-16 10:04 UTC595
        } = &mut self.nodes[p].kind
9baaafa4b167atagen2026-10-16 10:04 UTC596
        else {
9baaafa4b167atagen2026-10-16 10:04 UTC597
            unreachable!("parents are containers");
9baaafa4b167atagen2026-10-16 10:04 UTC598
        };
9baaafa4b167atagen2026-10-16 10:04 UTC599
        let child = children.remove(i);
9baaafa4b167atagen2026-10-16 10:04 UTC600
        if *expanded == Some(child.node) {
9baaafa4b167atagen2026-10-16 10:04 UTC601
            *expanded = None;
9baaafa4b167atagen2026-10-16 10:04 UTC602
        }
9baaafa4b167atagen2026-10-16 10:04 UTC603
        child
9baaafa4b167atagen2026-10-16 10:04 UTC604
    }
9baaafa4b167atagen2026-10-16 10:04 UTC605
9baaafa4b167atagen2026-10-16 10:04 UTC606
    fn new_leaf(&mut self, w: W) -> NodeId {
9baaafa4b167atagen2026-10-16 10:04 UTC607
        let n = self.nodes.insert(Node {
9baaafa4b167atagen2026-10-16 10:04 UTC608
            parent: None,
9baaafa4b167atagen2026-10-16 10:04 UTC609
            kind: Kind::Leaf(w),
9baaafa4b167atagen2026-10-16 10:04 UTC610
        });
9baaafa4b167atagen2026-10-16 10:04 UTC611
        self.leaves.insert(w, n);
9baaafa4b167atagen2026-10-16 10:04 UTC612
        n
9baaafa4b167atagen2026-10-16 10:04 UTC613
    }
9baaafa4b167atagen2026-10-16 10:04 UTC614
9baaafa4b167atagen2026-10-16 10:04 UTC615
    fn new_container(&mut self, axis: Axis) -> NodeId {
9baaafa4b167atagen2026-10-16 10:04 UTC616
        self.nodes.insert(Node {
9baaafa4b167atagen2026-10-16 10:04 UTC617
            parent: None,
9baaafa4b167atagen2026-10-16 10:04 UTC618
            kind: Kind::Container {
9baaafa4b167atagen2026-10-16 10:04 UTC619
                axis,
9baaafa4b167atagen2026-10-16 10:04 UTC620
                children: Vec::new(),
9baaafa4b167atagen2026-10-16 10:04 UTC621
                expanded: None,
9baaafa4b167atagen2026-10-16 10:04 UTC622
            },
9baaafa4b167atagen2026-10-16 10:04 UTC623
        })
9baaafa4b167atagen2026-10-16 10:04 UTC624
    }
9baaafa4b167atagen2026-10-16 10:04 UTC625
9baaafa4b167atagen2026-10-16 10:04 UTC626
    fn position(&self, n: NodeId) -> Option<(NodeId, usize)> {
9baaafa4b167atagen2026-10-16 10:04 UTC627
        let p = self.nodes[n].parent?;
9baaafa4b167atagen2026-10-16 10:04 UTC628
        let i = self.children(p).iter().position(|c| c.node == n)?;
9baaafa4b167atagen2026-10-16 10:04 UTC629
        Some((p, i))
9baaafa4b167atagen2026-10-16 10:04 UTC630
    }
9baaafa4b167atagen2026-10-16 10:04 UTC631
9baaafa4b167atagen2026-10-16 10:04 UTC632
    fn axis(&self, n: NodeId) -> Option<Axis> {
9baaafa4b167atagen2026-10-16 10:04 UTC633
        match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC634
            Kind::Container { axis, .. } => Some(*axis),
9baaafa4b167atagen2026-10-16 10:04 UTC635
            Kind::Leaf(_) => None,
9baaafa4b167atagen2026-10-16 10:04 UTC636
        }
9baaafa4b167atagen2026-10-16 10:04 UTC637
    }
9baaafa4b167atagen2026-10-16 10:04 UTC638
9baaafa4b167atagen2026-10-16 10:04 UTC639
    fn expanded(&self, n: NodeId) -> Option<NodeId> {
9baaafa4b167atagen2026-10-16 10:04 UTC640
        match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC641
            Kind::Container { expanded, .. } => *expanded,
9baaafa4b167atagen2026-10-16 10:04 UTC642
            Kind::Leaf(_) => None,
9baaafa4b167atagen2026-10-16 10:04 UTC643
        }
9baaafa4b167atagen2026-10-16 10:04 UTC644
    }
9baaafa4b167atagen2026-10-16 10:04 UTC645
9baaafa4b167atagen2026-10-16 10:04 UTC646
    fn children(&self, n: NodeId) -> &[Child] {
9baaafa4b167atagen2026-10-16 10:04 UTC647
        match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC648
            Kind::Container { children, .. } => children,
9baaafa4b167atagen2026-10-16 10:04 UTC649
            Kind::Leaf(_) => &[],
9baaafa4b167atagen2026-10-16 10:04 UTC650
        }
9baaafa4b167atagen2026-10-16 10:04 UTC651
    }
9baaafa4b167atagen2026-10-16 10:04 UTC652
9baaafa4b167atagen2026-10-16 10:04 UTC653
    fn children_mut(&mut self, n: NodeId) -> &mut Vec<Child> {
9baaafa4b167atagen2026-10-16 10:04 UTC654
        match &mut self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC655
            Kind::Container { children, .. } => children,
9baaafa4b167atagen2026-10-16 10:04 UTC656
            Kind::Leaf(_) => unreachable!("leaves have no children"),
9baaafa4b167atagen2026-10-16 10:04 UTC657
        }
9baaafa4b167atagen2026-10-16 10:04 UTC658
    }
9baaafa4b167atagen2026-10-16 10:04 UTC659
9baaafa4b167atagen2026-10-16 10:04 UTC660
    fn mean_weight(&self, p: NodeId) -> f64 {
9baaafa4b167atagen2026-10-16 10:04 UTC661
        let children = self.children(p);
9baaafa4b167atagen2026-10-16 10:04 UTC662
        if children.is_empty() {
9baaafa4b167atagen2026-10-16 10:04 UTC663
            1.0
9baaafa4b167atagen2026-10-16 10:04 UTC664
        } else {
9baaafa4b167atagen2026-10-16 10:04 UTC665
            children.iter().map(|c| c.weight).sum::<f64>() / children.len() as f64
9baaafa4b167atagen2026-10-16 10:04 UTC666
        }
9baaafa4b167atagen2026-10-16 10:04 UTC667
    }
9baaafa4b167atagen2026-10-16 10:04 UTC668
9baaafa4b167atagen2026-10-16 10:04 UTC669
    fn visible(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> bool {
9baaafa4b167atagen2026-10-16 10:04 UTC670
        match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC671
            Kind::Leaf(w) => vis(*w),
9baaafa4b167atagen2026-10-16 10:04 UTC672
            Kind::Container { children, .. } => children.iter().any(|c| self.visible(c.node, vis)),
9baaafa4b167atagen2026-10-16 10:04 UTC673
        }
9baaafa4b167atagen2026-10-16 10:04 UTC674
    }
9baaafa4b167atagen2026-10-16 10:04 UTC675
9baaafa4b167atagen2026-10-16 10:04 UTC676
    #[cfg(test)]
9baaafa4b167atagen2026-10-16 10:04 UTC677
    pub(crate) fn check(&self) {
9baaafa4b167atagen2026-10-16 10:04 UTC678
        let reachable = match self.root {
9baaafa4b167atagen2026-10-16 10:04 UTC679
            Some(r) => {
9baaafa4b167atagen2026-10-16 10:04 UTC680
                assert!(self.nodes[r].parent.is_none());
9baaafa4b167atagen2026-10-16 10:04 UTC681
                self.check_node(r)
9baaafa4b167atagen2026-10-16 10:04 UTC682
            }
9baaafa4b167atagen2026-10-16 10:04 UTC683
            None => 0,
9baaafa4b167atagen2026-10-16 10:04 UTC684
        };
9baaafa4b167atagen2026-10-16 10:04 UTC685
        assert_eq!(reachable, self.nodes.len(), "orphaned nodes");
9baaafa4b167atagen2026-10-16 10:04 UTC686
        for (&w, &n) in &self.leaves {
9baaafa4b167atagen2026-10-16 10:04 UTC687
            assert!(matches!(self.nodes[n].kind, Kind::Leaf(x) if x == w));
9baaafa4b167atagen2026-10-16 10:04 UTC688
        }
9baaafa4b167atagen2026-10-16 10:04 UTC689
    }
9baaafa4b167atagen2026-10-16 10:04 UTC690
9baaafa4b167atagen2026-10-16 10:04 UTC691
    #[cfg(test)]
9baaafa4b167atagen2026-10-16 10:04 UTC692
    fn check_node(&self, n: NodeId) -> usize {
9baaafa4b167atagen2026-10-16 10:04 UTC693
        match &self.nodes[n].kind {
9baaafa4b167atagen2026-10-16 10:04 UTC694
            Kind::Leaf(_) => 1,
9baaafa4b167atagen2026-10-16 10:04 UTC695
            Kind::Container {
9baaafa4b167atagen2026-10-16 10:04 UTC696
                axis,
9baaafa4b167atagen2026-10-16 10:04 UTC697
                children,
9baaafa4b167atagen2026-10-16 10:04 UTC698
                expanded,
9baaafa4b167atagen2026-10-16 10:04 UTC699
            } => {
9baaafa4b167atagen2026-10-16 10:04 UTC700
                assert!(
9baaafa4b167atagen2026-10-16 10:04 UTC701
                    children.len() >= 2,
9baaafa4b167atagen2026-10-16 10:04 UTC702
                    "container with {} children",
9baaafa4b167atagen2026-10-16 10:04 UTC703
                    children.len()
9baaafa4b167atagen2026-10-16 10:04 UTC704
                );
9baaafa4b167atagen2026-10-16 10:04 UTC705
                if let Some(e) = expanded {
9baaafa4b167atagen2026-10-16 10:04 UTC706
                    assert!(children.iter().any(|c| c.node == *e));
9baaafa4b167atagen2026-10-16 10:04 UTC707
                }
9baaafa4b167atagen2026-10-16 10:04 UTC708
                let mut count = 1;
9baaafa4b167atagen2026-10-16 10:04 UTC709
                for c in children {
9baaafa4b167atagen2026-10-16 10:04 UTC710
                    assert!(c.weight > 0.0 && c.weight.is_finite());
9baaafa4b167atagen2026-10-16 10:04 UTC711
                    assert_eq!(self.nodes[c.node].parent, Some(n));
9baaafa4b167atagen2026-10-16 10:04 UTC712
                    assert_ne!(self.axis(c.node), Some(*axis), "axes must alternate");
9baaafa4b167atagen2026-10-16 10:04 UTC713
                    count += self.check_node(c.node);
9baaafa4b167atagen2026-10-16 10:04 UTC714
                }
9baaafa4b167atagen2026-10-16 10:04 UTC715
                count
9baaafa4b167atagen2026-10-16 10:04 UTC716
            }
9baaafa4b167atagen2026-10-16 10:04 UTC717
        }
9baaafa4b167atagen2026-10-16 10:04 UTC718
    }
9baaafa4b167atagen2026-10-16 10:04 UTC719
}
9baaafa4b167atagen2026-10-16 10:04 UTC720
9baaafa4b167atagen2026-10-16 10:04 UTC721
fn span(r: Rect, axis: Axis) -> (f64, f64) {
9baaafa4b167atagen2026-10-16 10:04 UTC722
    match axis {
9baaafa4b167atagen2026-10-16 10:04 UTC723
        Axis::Horizontal => (r.x, r.w),
9baaafa4b167atagen2026-10-16 10:04 UTC724
        Axis::Vertical => (r.y, r.h),
9baaafa4b167atagen2026-10-16 10:04 UTC725
    }
9baaafa4b167atagen2026-10-16 10:04 UTC726
}
9baaafa4b167atagen2026-10-16 10:04 UTC727
9baaafa4b167atagen2026-10-16 10:04 UTC728
fn with_span(r: Rect, axis: Axis, start: f64, len: f64) -> Rect {
9baaafa4b167atagen2026-10-16 10:04 UTC729
    match axis {
9baaafa4b167atagen2026-10-16 10:04 UTC730
        Axis::Horizontal => Rect::new(start, r.y, len, r.h),
9baaafa4b167atagen2026-10-16 10:04 UTC731
        Axis::Vertical => Rect::new(r.x, start, r.w, len),
9baaafa4b167atagen2026-10-16 10:04 UTC732
    }
9baaafa4b167atagen2026-10-16 10:04 UTC733
}