Skip to main content

kui_core/runtime/
fills.rs

1//! Slots on the core's side:
2//! declaring one (`begin_slot`), and the bounded, namespaced fill an
3//! extension draws into (`fill`). The loop over extensions is
4//! `crate::slot`'s; what is here is what only the core can do, because
5//! it owns the node stack and the keys.
6
7use super::*;
8use crate::slot::Slot;
9
10impl Core {
11    /// Declares a slot under its full name at the cursor and returns its
12    /// key — `parent.str(name)`, recorded for `key_of` — or `None` when it
13    /// cannot be declared: outside a frame, or a second time in one
14    /// frame, which is the `duplicate-slot` warning.
15    ///
16    /// An extension may declare one too, and its key nests under the slot
17    /// the extension is itself filling, like any of its nodes. Names stay
18    /// frame-wide because namespaces are: there is one extension called
19    /// `todos` however deep the thing that loaded it sat, so `todos/panel`
20    /// is one slot and declaring it twice is the same warning wherever
21    /// the two declarations came from.
22    pub fn begin_slot(&mut self, name: &str) -> Option<Key> {
23        if self.tree.is_empty() {
24            return None;
25        }
26        if self.slot_labels.find(name).next().is_some() {
27            self.diag.raise(crate::diag::duplicate_slot(name));
28            return None;
29        }
30        let key = self.parent_key().str(name);
31        self.slot_labels.push(key, name, self.origin);
32        self.key_labels.push(key, name, self.origin);
33        Some(key)
34    }
35
36    /// Whether the full name `name` was declared this frame so far — or
37    /// is the slot of a devtools tab declared this frame, which counts
38    /// whether or not the panel mounted it, so a plugin whose only slot
39    /// is a tab is quiet with the panel off.
40    pub fn slot_declared(&self, name: &str) -> bool {
41        self.slot_labels.find(name).next().is_some() || self.devtools_tab_slot(name)
42    }
43
44    /// Runs `f` as the fill of `slot` under `origin`: every node it opens
45    /// is tagged `origin`, keyed as a child of `slot.key` (an extension's keys depend on the slot's
46    /// full name, which the host's namespace makes its own, and on
47    /// nothing the host built around them), counted from zero, and
48    /// closed for it if it returns with any open (decision 5, with the
49    /// `unbalanced-extension` warning). The host's origin, counter and
50    /// namespace are what they were when `f` returns, so the host's next
51    /// child is keyed as if the fill had not happened.
52    pub fn fill(&mut self, slot: &Slot<'_>, origin: OriginId, f: impl FnOnce(&mut Ui<'_>)) {
53        self.fill_within(slot, origin, None, f);
54    }
55
56    /// `fill`, with `filler` answering the slots the fill itself declares
57    /// — what `Extensions::fill_one` hands in, so an extension can host
58    /// extensions of its own (see `crate::slot`). `None` is plain `fill`:
59    /// nothing answers, so a slot declared inside draws nothing.
60    pub fn fill_within(
61        &mut self,
62        slot: &Slot<'_>,
63        origin: OriginId,
64        filler: Option<&mut dyn crate::slot::Fill>,
65        f: impl FnOnce(&mut Ui<'_>),
66    ) {
67        if self.tree.is_empty() {
68            return;
69        }
70        let depth = self.stack.len();
71        let saved_counter = self.counters.last().copied().unwrap_or(0);
72        if let Some(c) = self.counters.last_mut() {
73            *c = 0;
74        }
75        let saved_origin = self.origin;
76        let saved_ns = (self.ns_depth, self.ns_key);
77        self.origin = origin;
78        self.ns_depth = depth;
79        self.ns_key = slot.key;
80        let first = self.tree.len() as u32;
81
82        match filler {
83            Some(filler) => f(&mut Ui::with_filler(self, filler)),
84            None => f(&mut Ui::new(self)),
85        }
86        // After the fills inside it, so the innermost is found first.
87        self.tree
88            .fills
89            .push((slot.key, first, self.tree.len() as u32));
90
91        if self.stack.len() > depth {
92            let open = self.stack.len() - depth;
93            self.diag.raise(crate::diag::unbalanced_extension(
94                &slot.full_name(),
95                slot.key,
96                open,
97            ));
98            self.stack.truncate(depth);
99            self.counters.truncate(depth);
100        }
101        if let Some(c) = self.counters.last_mut() {
102            *c = saved_counter;
103        }
104        self.origin = saved_origin;
105        (self.ns_depth, self.ns_key) = saved_ns;
106    }
107}