Skip to main content

kui_core/
ui.rs

1//! [`Ui`]: the frame builder a Rust view declares its tree through.
2//!
3//! A `Ui` borrows a [`Core`] for the length of one frame. It is a thin,
4//! safe facade over the core's flat builder methods (which are also the FFI
5//! surface): every call opens, fills or closes a node, or reads a fact the
6//! last frame established. It never captures app state, so `view(&state)`
7//! and `update(&mut state)` cannot conflict.
8//!
9//! The shape of a view: containers open with [`Ui::with`] (scoped) or
10//! [`Ui::open`]/[`Ui::close`], leaves with [`Ui::leaf`] and [`Ui::text`],
11//! and each node's look and behaviour is a [`NodeSpec`]. Nodes are keyed by
12//! position unless a `_keyed` or `_indexed` form gives them a stable
13//! identity, which anything retained across frames (focus, scrolling, an
14//! edit buffer, a transition) needs.
15//!
16//! ```rust
17//! use kui_core::{Color, Core, NodeSpec, Size, Sizing, TextStyle, widgets};
18//!
19//! let mut core = Core::new();
20//! let mut ui = core.frame(Size::new(400.0, 300.0), 1.0);
21//! let theme = ui.theme();
22//! ui.configure_root(NodeSpec::column().fill().pad(12.0).gap(8.0));
23//!
24//! // A toolbar: a row of buttons, keyed by their labels.
25//! ui.with(NodeSpec::row().gap(6.0), |ui| {
26//!     widgets::button(ui, "Open", "open");
27//!     widgets::button(ui, "Save", "save");
28//! });
29//!
30//! // A panel that grows to fill the rest, with a label in it.
31//! let panel = ui.with_keyed(
32//!     "panel",
33//!     NodeSpec::column().fill().pad(8.0).bg(theme.surface).radius(6.0),
34//!     |ui| {
35//!         ui.text("Ready.", TextStyle::new(14.0).color(theme.muted));
36//!         ui.leaf(NodeSpec::row().size(Sizing::GROW, 1.0).bg(Color::hex(0x80808080)));
37//!     },
38//! );
39//! assert!(!ui.is_hovered(panel)); // nothing has moved the pointer yet
40//! ui.finish();
41//! ```
42//!
43//! [`Ui::finish`] is the one way out of a frame: it runs layout and
44//! emission and leaves the results in [`Core::output`].
45
46use crate::edit::EditOptions;
47use crate::env::Env;
48use crate::geom::{Rect, Size, Vec2};
49use crate::key::Key;
50use crate::line::Stroke;
51use crate::runtime::{Core, SlotFill};
52use crate::slot::{Fill, Slot};
53use crate::spec::{NodeSpec, TextStyle};
54use crate::text::Span;
55use crate::tree::OriginId;
56use crate::value::Value;
57use crate::window::{WindowCommand, WindowConfig, WindowId};
58
59pub struct Ui<'a> {
60    core: &'a mut Core,
61    /// What fills the slots this frame declares (`Core::frame_with`);
62    /// `None` for a frame begun without one, and inside a fill — an
63    /// extension's `slot` declares and fills nothing.
64    filler: Option<&'a mut dyn Fill>,
65}
66
67impl<'a> Ui<'a> {
68    pub(crate) fn new(core: &'a mut Core) -> Self {
69        Self { core, filler: None }
70    }
71
72    /// [`Self::wrap`] with something to fill the slots the frame declares
73    /// — for a frontend that drives `Core` directly and keeps an
74    /// extension list of its own (the C context, a headless Node one), so
75    /// its `slot` and `finish` are this type's rather than a copy of them.
76    pub fn with_filler(core: &'a mut Core, filler: &'a mut dyn Fill) -> Self {
77        Self {
78            core,
79            filler: Some(filler),
80        }
81    }
82
83    /// Escape hatch to the underlying core (e.g. for FFI view callbacks).
84    pub fn core(&mut self) -> &mut Core {
85        self.core
86    }
87
88    /// The inverse escape hatch: wraps a borrowed core mid-frame so foreign
89    /// frontends that drive `Core` directly (FFI, Node) can call `widgets::*`.
90    pub fn wrap(core: &'a mut Core) -> Self {
91        Self { core, filler: None }
92    }
93
94    /// Declares a slot here, with no parameters: whatever fills it draws
95    /// now, as children of the node this view is inside, at this
96    /// position among its siblings. `name` is the full name,
97    /// `namespace/slot` — the namespace the host gave the extension when
98    /// it loaded it, and the slot in the extension's own vocabulary
99    /// (`"fs/panel"`). `"ns/root"` is the fill that follows the host's
100    /// view for an extension listing no slots, and declaring it moves
101    /// that fill here.
102    pub fn slot(&mut self, name: &str) {
103        self.slot_with(name, &crate::slot::NULL_PARAMS);
104    }
105
106    /// `slot` with parameters the extension reads this frame
107    /// (`Slot::params`); a `Value` because it is the type that already
108    /// crosses to an extension. Nothing is retained — pass what is true
109    /// this frame, every frame.
110    ///
111    /// Whether the slot was declared: false for a name this frame already
112    /// declared (which warns, `duplicate-slot`) or outside a frame. True
113    /// whether or not anything filled it — a host with nothing loaded
114    /// still gets a placed, empty node to lay out around.
115    pub fn slot_with(&mut self, name: &str, params: &Value) -> bool {
116        let Some(key) = self.core.begin_slot(name) else {
117            return false;
118        };
119        self.fill_slot(name, key, params);
120        true
121    }
122
123    /// Fills the slot declared at `key`, plainly. Inside a fill being
124    /// kept, the slot is journaled as a slot — to be declared again and
125    /// filled fresh on a replay — and what fills it now is not the kept
126    /// fill's own (ADR 0045).
127    fn fill_slot(&mut self, name: &str, key: Key, params: &Value) {
128        let keeping = self.core.keeping();
129        if keeping {
130            self.core.keep_op(crate::runtime::replay::Op::Slot {
131                name: name.into(),
132                params: params.clone(),
133            });
134            self.core.pause_keeping();
135        }
136        if let Some(filler) = self.filler.as_deref_mut() {
137            filler.fill(name, key, params, &mut Ui::new(self.core));
138        }
139        if keeping {
140            self.core.resume_keeping();
141        }
142    }
143
144    /// [`Self::slot_with`], and what the fill built is *kept* for
145    /// [`Self::slot_replay`] to push again next frame (ADR 0045): every
146    /// node as its door saw it, the slots declared inside, and every fact
147    /// of the frame the fill read. Whether the slot was declared, as
148    /// `slot_with` answers. Inside a fill that is itself being kept this
149    /// is `slot_with`: a kept fill's nested slots are filled fresh on a
150    /// replay, and so are not kept of their own.
151    pub fn slot_kept(&mut self, name: &str, params: &Value) -> bool {
152        let Some(key) = self.core.begin_slot(name) else {
153            return false;
154        };
155        if self.core.keeping() {
156            self.fill_slot(name, key, params);
157        } else {
158            self.fill_and_keep(name, key, params);
159        }
160        true
161    }
162
163    /// The host's claim that nothing it feeds the extension filling
164    /// `name` has changed since the fill was kept (ADR 0045). The core
165    /// checks what it can see — the params, every fact of the frame the
166    /// kept fill read, that the slot is declared where it was — and
167    /// pushes the kept nodes again without asking the extension
168    /// (`SlotFill::Replayed`), or fills and keeps it as `slot_kept`
169    /// would and says why (the other answers). `None` when the slot was
170    /// not declared (a duplicate, or outside a frame). The kept fill's
171    /// nested slots are declared again and filled fresh either way.
172    ///
173    /// What the host vouches for is its own side only: the state the
174    /// extension reads from the host outside kui. A view that reads the
175    /// env's clock or caret phase off a reading handed out whole (Lua's
176    /// `env.now`) is one the host must not replay, since a reading does
177    /// not say which of its fields were used.
178    pub fn slot_replay(&mut self, name: &str, params: &Value) -> Option<SlotFill> {
179        let key = self.core.begin_slot(name)?;
180        if self.core.keeping() {
181            // Nested in a fill being kept: plain, as `slot_kept` is.
182            self.fill_slot(name, key, params);
183            return Some(SlotFill::NotKept);
184        }
185        let (fill, why) = match self.core.take_replayable(name, key, params) {
186            Ok(kept) => {
187                let (namespace, short) = crate::slot::split_name(name);
188                let slot = Slot {
189                    name: short,
190                    namespace,
191                    params,
192                    key,
193                };
194                // Matched out so the filler is a coercion site: the
195                // borrow's object lifetime shortens to the call's.
196                match self.filler.as_deref_mut() {
197                    Some(f) => self.core.replay(name, &slot, kept, Some(f)),
198                    None => self.core.replay(name, &slot, kept, None),
199                }
200                (SlotFill::Replayed, None)
201            }
202            Err((fill, why)) => {
203                self.fill_and_keep(name, key, params);
204                (fill, why)
205            }
206        };
207        self.core.note_slot_fill(name, fill, why);
208        Some(fill)
209    }
210
211    /// Fills the slot declared at `key` and keeps what the fill built —
212    /// unless a fill is already being kept, when it is a plain fill.
213    fn fill_and_keep(&mut self, name: &str, key: Key, params: &Value) {
214        self.core.keep_next_fill(name, key, params);
215        if let Some(filler) = self.filler.as_deref_mut() {
216            filler.fill(name, key, params, &mut Ui::new(self.core));
217        }
218        // Nothing filled it: the ask lapses.
219        self.core.forget_next_fill();
220    }
221
222    /// Whether the full name `name` was declared this frame so far.
223    pub fn slot_declared(&self, name: &str) -> bool {
224        self.core.slot_declared(name)
225    }
226
227    /// Declares a devtools tab an extension fills: `name` is the tab's
228    /// identity, `label` what the strip shows,
229    /// `slot` the full slot name (`"ts/panel"`) the extension names.
230    /// While the tab is the one on show, the panel declares the slot in
231    /// the tab's body and the fill is drawn there; otherwise the slot is
232    /// not declared and the extension is not asked, though its naming
233    /// the slot raises no `unknown-slot`. Made every frame, panel on or
234    /// off. A name declared twice in a frame warns `duplicate-tab`.
235    pub fn devtools_tab(&mut self, name: &str, label: &str, slot: &str) {
236        self.core.devtools_tab_declare(name, label, Some(slot));
237    }
238
239    /// Declares a devtools tab the host draws itself, and draws it
240    /// **only when it is shown**: `f` runs
241    /// when the panel is on, docked in this window, and `name` is the
242    /// tab on show — otherwise this declares and returns, and the tab
243    /// costs nothing. What `f` builds is the host's: its keys, labels
244    /// and origin, its events reaching the host untouched — laid out
245    /// and painted as a layer over the panel's tab body, clipped to it,
246    /// in the dock's focus region. The panel's facts are read through
247    /// `devtools_selected` and its siblings.
248    pub fn devtools_tab_with(&mut self, name: &str, label: &str, f: impl FnOnce(&mut Ui<'_>)) {
249        if !self.core.devtools_tab_declare(name, label, None) {
250            return;
251        }
252        if !self.core.devtools_tab_shown(name) {
253            return;
254        }
255        self.core.devtools_tab_open(name);
256        f(self);
257        self.core.close();
258    }
259
260    /// Whether the host form of tab `name` is shown this frame — what
261    /// `devtools_tab_with` asks before running its closure, for a caller
262    /// that builds the content some other way.
263    pub fn devtools_tab_shown(&self, name: &str) -> bool {
264        self.core.devtools_tab_shown(name)
265    }
266
267    /// The bare declaration either form makes: `slot` for the extension
268    /// form, `None` for a host form whose
269    /// content is built some other way or not at all this frame. Whether
270    /// the declaration stood — false for a name already declared this
271    /// frame (`duplicate-tab`) or outside a frame.
272    pub fn devtools_tab_declare(&mut self, name: &str, label: &str, slot: Option<&str>) -> bool {
273        self.core.devtools_tab_declare(name, label, slot)
274    }
275
276    /// The host form for a binding that decided the laziness on its own
277    /// side (a Node encoder or a Lua converter that already read which
278    /// tab is on show): declares the tab and builds
279    /// `f` as its content **whether or not** the tab is shown here — a
280    /// content whose body the panel did not build anchors to nothing
281    /// and paints nothing, and a name already declared this frame
282    /// (`duplicate-tab`) builds into a node of no size, so the caller's
283    /// stream stays in step either way. `devtools_tab_with` is the door
284    /// for a caller that can skip the work.
285    pub fn devtools_tab_declared(&mut self, name: &str, label: &str, f: impl FnOnce(&mut Ui<'_>)) {
286        if self.core.devtools_tab_declare(name, label, None) {
287            self.core.devtools_tab_open(name);
288        } else {
289            self.core.open(
290                NodeSpec::column()
291                    .width(crate::spec::Sizing::Fixed(0.0))
292                    .height(crate::spec::Sizing::Fixed(0.0))
293                    .clip(),
294            );
295        }
296        f(self);
297        self.core.close();
298    }
299
300    /// The panel's selected node (`Core::devtools_selected`).
301    pub fn devtools_selected(&self) -> Option<Key> {
302        self.core.devtools_selected()
303    }
304
305    /// The panel's hovered tree row (`Core::devtools_hovered`).
306    pub fn devtools_hovered(&self) -> Option<Key> {
307        self.core.devtools_hovered()
308    }
309
310    /// The node the picker is over (`Core::devtools_picked`).
311    pub fn devtools_picked(&self) -> Option<Key> {
312        self.core.devtools_picked()
313    }
314
315    /// Whether the panel's picker is up (`Core::devtools_picking`).
316    pub fn devtools_picking(&self) -> bool {
317        self.core.devtools_picking()
318    }
319
320    /// The tab the panel is on, by name (`Core::devtools_current_tab`).
321    pub fn devtools_current_tab(&self) -> String {
322        self.core.devtools_current_tab()
323    }
324
325    /// Loads `ext` under `namespace` into the list filling this frame's
326    /// slots, and answers with the origin it got. This is how an
327    /// extension hosts an extension of its own: the guest asks mid-frame,
328    /// when it knows what it wants, and the plugin lands in the same list
329    /// as the host's own — one namespace map, one origin per extension,
330    /// however deep the loading went (`crate::slot`).
331    ///
332    /// Fails when the namespace is taken, or empty with an extension that
333    /// names itself nothing, exactly as
334    /// `Extensions::push_as` does, and when this frame was begun without
335    /// a filler (`Core::frame`) or with one that is not a list.
336    pub fn add_extension(
337        &mut self,
338        namespace: &str,
339        ext: Box<dyn crate::runtime::Extension>,
340    ) -> Result<OriginId, String> {
341        // A fill that loads an extension wants its next frame.
342        self.core.taint_kept("it loaded an extension");
343        match self.filler.as_deref_mut() {
344            Some(filler) => filler.add(namespace, ext),
345            None => Err(format!(
346                "cannot load `{namespace}`: this frame declares no slots to fill"
347            )),
348        }
349    }
350
351    /// Runs `f` as the fill of `slot` under `origin`: nodes it opens are
352    /// tagged with the origin, keyed under the slot's key, and closed
353    /// for it if it leaves any open. What a `Fill` implementation calls
354    /// per extension; see `Core::fill`.
355    pub fn fill(&mut self, origin: OriginId, slot: &Slot<'_>, f: impl FnOnce(&mut Ui<'_>)) {
356        self.core.fill(slot, origin, f);
357    }
358
359    /// `fill`, with `filler` answering the slots the fill declares — an
360    /// extension hosting extensions of its own. `Extensions::fill_one`
361    /// passes itself, which is what makes one namespace map do for every
362    /// level; see `crate::slot`.
363    pub fn fill_within(
364        &mut self,
365        origin: OriginId,
366        slot: &Slot<'_>,
367        filler: &mut dyn Fill,
368        f: impl FnOnce(&mut Ui<'_>),
369    ) {
370        self.core.fill_within(slot, origin, Some(filler), f);
371    }
372
373    /// The origin the nodes opened right now are tagged with:
374    /// `OriginId::HOST` in the host's own view, the filling extension's
375    /// inside a fill. What records who declared a slot, and so where the
376    /// replies of whatever fills it go.
377    pub fn origin(&self) -> OriginId {
378        self.core.origin()
379    }
380
381    /// The viewport this frame lays out into: the window, less the
382    /// devtools' dock while the panel is docked (`Core::viewport`).
383    pub fn viewport(&self) -> Size {
384        self.core.viewport()
385    }
386
387    /// The env reading's inputs, the frame's facts included
388    /// (`Core::env_facts`): what a binding's `env` table is filled from.
389    pub fn env_facts(&self) -> crate::schema::EnvFacts {
390        self.core.env_facts()
391    }
392
393    /// Host facts pushed by the frame driver (refresh rate, focus).
394    pub fn env(&self) -> Env {
395        self.core.env
396    }
397
398    /// This frame's palette: the named colours the stock widgets paint
399    /// with, derived from `env.system` unless the app pinned something
400    /// else (see [`crate::theme`]).
401    ///
402    /// By value, because it is [`Copy`] and a view that took a reference
403    /// could not then touch `ui`. `let t = ui.theme();` at the top of a
404    /// widget is the idiom.
405    pub fn theme(&self) -> crate::theme::Theme {
406        *self.core.theme()
407    }
408
409    /// Whether anyone chose the theme's accent, or it is kui's fallback
410    /// blue — see [`Core::has_accent`](crate::runtime::Core::has_accent).
411    pub fn has_accent(&self) -> bool {
412        self.core.has_accent()
413    }
414
415    /// The sizes the stock widgets are built from
416    /// ([`Metrics`](crate::metrics::Metrics)), by value like the theme and
417    /// for the same reason. What a view reads to make its own controls
418    /// agree with the stock ones on a radius and a padding.
419    pub fn metrics(&self) -> crate::metrics::Metrics {
420        *self.core.metrics()
421    }
422
423    /// Declares the tokens this origin references by name (see
424    /// [`crate::tokens`] and
425    /// [`Core::set_tokens`](crate::runtime::Core::set_tokens)). Inside a
426    /// fill the table is the extension's own.
427    pub fn set_tokens(&mut self, tokens: crate::tokens::Tokens) {
428        self.core.set_tokens(tokens);
429    }
430
431    /// What a `$name` resolves to this frame — the running origin's
432    /// table over the host's, the roles in front of both — for a view
433    /// that reads a token by name rather than holding its id.
434    pub fn tokens(&self) -> crate::tokens::TokenLookup<'_> {
435        self.core.token_lookup()
436    }
437
438    /// A colour token by name, this frame's half. A name that resolves
439    /// to nothing, or to a length, raises `unknown-token` and answers
440    /// `None`, so the view leaves the slot at its default
441    /// (`.bg(ui.token_color("peach").unwrap_or(t.surface))`) rather than
442    /// painting a transparent that would hide the node a typo was on.
443    pub fn token_color(&mut self, name: &str) -> Option<crate::color::Color> {
444        match self.core.token_lookup().color(name) {
445            Ok(c) => Some(c),
446            Err(e) => {
447                self.core.warn_unknown_token(&e);
448                None
449            }
450        }
451    }
452
453    /// A length token by name; unknown warns and answers `None`, as above.
454    pub fn token_length(&mut self, name: &str) -> Option<f32> {
455        match self.core.token_lookup().length(name) {
456            Ok(v) => Some(v),
457            Err(e) => {
458                self.core.warn_unknown_token(&e);
459                None
460            }
461        }
462    }
463
464    /// Declares this frame's window title (declare every frame you care;
465    /// the driver diffs and applies changes).
466    pub fn window_title(&mut self, title: &str) {
467        self.core.set_window_title(title);
468    }
469
470    /// Declares that this frame wants the window kept above every other
471    /// app's; see [`crate::Core::set_always_on_top`]. Declare it every
472    /// frame you want it — a frame that does not lowers the window again,
473    /// which is what makes a pin button a toggle — and read whether the
474    /// platform agreed from `env().window.always_on_top`.
475    pub fn always_on_top(&mut self, on_top: bool) {
476        self.core.set_always_on_top(on_top);
477    }
478
479    /// Declares that this frame wants secure keyboard entry while the
480    /// window has the keyboard (a password prompt); see
481    /// [`crate::Core::set_secure_input`]. Declare it every frame the
482    /// prompt is up: a frame that does not turns it off.
483    pub fn secure_input(&mut self, on: bool) {
484        self.core.set_secure_input(on);
485    }
486
487    /// Declares which Option keys act as Alt in this window on macOS, so
488    /// Option-u arrives as the chord `A-u` rather than composing an
489    /// accent; see [`crate::Core::set_option_as_alt`]. Declare it every
490    /// frame: a frame that does not gives the Option keys back to the
491    /// layout.
492    pub fn option_as_alt(&mut self, option_as_alt: crate::OptionAsAlt) {
493        self.core.set_option_as_alt(option_as_alt);
494    }
495
496    /// Declares that this window takes the keyboard as keys, with the
497    /// platform's input method off — no composition, and on a Mac no dead
498    /// keys and no press-and-hold, so a held letter repeats; see
499    /// [`crate::Core::set_ime_off`]. A modal editor's normal mode. Declare
500    /// it every frame: a frame that does not gives the IME back.
501    pub fn ime_off(&mut self, off: bool) {
502        self.core.set_ime_off(off);
503    }
504
505    /// Declares that a window named `name` exists this frame; see
506    /// `Core::declare_window`. It opens on the first frame that declares
507    /// it (`config` is read then and never again), stays open while any
508    /// window's frame keeps declaring it, and closes when none does.
509    /// `view` is then called for it too, with [`Ui::window_name`] saying
510    /// which window is being drawn.
511    pub fn window(&mut self, name: &str, config: WindowConfig) {
512        self.core.declare_window(name, config);
513    }
514
515    /// The name of the window this frame is drawing: `"main"` for the one
516    /// the launcher opened, else the name the declaration that opened it
517    /// used. `env().window.id` is the same window as a number.
518    pub fn window_name(&self) -> std::rc::Rc<str> {
519        self.core.window_name()
520    }
521
522    /// Sets the origin the nodes opened from here on are tagged with; see
523    /// [`Ui::origin`].
524    pub fn set_origin(&mut self, origin: OriginId) {
525        self.core.set_origin(origin);
526    }
527
528    /// The root node's spec for this frame: its direction, padding, gap
529    /// and background. Call it first; the default root is a fit column.
530    pub fn configure_root(&mut self, spec: NodeSpec) {
531        self.core.configure_root(spec);
532    }
533
534    /// The key a child opened under `label` would get here, without
535    /// opening it: read it before the node exists to ask `is_hovered` or
536    /// `is_focused` while building it.
537    pub fn child_key(&self, label: &str) -> Key {
538        self.core.child_key(label)
539    }
540
541    /// The key the `i`th child gets from auto-keying; see `open_indexed`.
542    pub fn child_key_indexed(&self, i: u64) -> Key {
543        self.core.child_key_indexed(i)
544    }
545
546    /// Whether the pointer is over `key`, as of the last input. Only a
547    /// node that tracks hover answers true (one with a click, a drag, a
548    /// hover background or `hoverable`).
549    pub fn is_hovered(&self, key: Key) -> bool {
550        self.core.is_hovered(key)
551    }
552
553    /// Whether the primary button is held on `key`.
554    pub fn is_pressed(&self, key: Key) -> bool {
555        self.core.is_pressed(key)
556    }
557
558    /// Whether files dragged in from the OS are over `key`, for
559    /// drop-dependent *layout*; a colour swap is `drop_bg`.
560    pub fn is_drop_target(&self, key: Key) -> bool {
561        self.core.is_drop_target(key)
562    }
563
564    /// The zone the dragged files are over, if any.
565    pub fn drop_target(&self) -> Option<Key> {
566        self.core.drop_target()
567    }
568
569    /// Whether any member of a hover group (`NodeSpec::hover_group`) is
570    /// hovered; the id comes from `NodeSpec::hover_group_id`.
571    pub fn is_group_hovered(&self, group: u64) -> bool {
572        self.core.is_group_hovered(group)
573    }
574
575    /// Whether any member of a hover group is pressed.
576    pub fn is_group_pressed(&self, group: u64) -> bool {
577        self.core.is_group_pressed(group)
578    }
579
580    /// Physical modifier state (the host also receives it as a
581    /// `{kind="modifiers"}` event whenever it changes).
582    pub fn modifiers(&self) -> crate::input::KeyMods {
583        self.core.modifiers()
584    }
585
586    /// The exit `key` leaves by if this frame stops declaring it (backlog
587    /// F136); see `Core::set_exit`. The view that removes a card thrown
588    /// by a button names the throw in the same frame, with no frame drawn
589    /// first to aim it.
590    pub fn exit_with(&mut self, key: Key, exit: crate::enter::Enter) {
591        self.core.set_exit(key, exit);
592    }
593
594    /// Asks for a frame at `at` on the frame clock (backlog F135); see
595    /// `Core::request_frame_at`. `ui.request_frame_at(ui.now() + 3.0)` is
596    /// a toast's expiry, with no thread and nothing owed in between.
597    pub fn request_frame_at(&mut self, at: f64) {
598        self.core.request_frame_at(at);
599    }
600
601    /// The frame clock in the driver's seconds (backlog F134); see
602    /// `Core::now`. A view's deadlines read from it — a toast's expiry, a
603    /// sequence's beats — so a test's `advance` moves them with the
604    /// core's own easing.
605    pub fn now(&self) -> f64 {
606        self.core.now()
607    }
608
609    /// The caret's blink phase — `true` draws it; see
610    /// `Core::caret_visible`. A custom editor draws its caret node on the
611    /// on phase and skips it on the off, keeping the `caret` row on its
612    /// `line` either way (that row is what the clock is armed on).
613    pub fn caret_visible(&self) -> bool {
614        self.core.caret_visible()
615    }
616
617    /// Asks for one more frame after this one; see `Core::request_frame`.
618    #[track_caller]
619    pub fn request_frame(&mut self) {
620        self.core.request_frame();
621    }
622
623    /// Asks for one more frame on kui's own behalf (a stock widget's, not
624    /// the app's), named `why` in a trace.
625    #[track_caller]
626    pub(crate) fn owe_frame(&mut self, why: &'static str) {
627        self.core.owe_frame(why);
628    }
629
630    /// Measures text the way layout would, without adding a node; see
631    /// `Core::measure_text`. Sizing a column to its widest label, or
632    /// choosing a tier that fits, is arithmetic on these numbers instead
633    /// of hand-tuned constants. The metrics do not scale linearly:
634    /// `measured × zoom` is not `measure(size × zoom)`, because shaping
635    /// rounds per size, so anything that zooms measures at the size it
636    /// draws.
637    pub fn measure_text(
638        &mut self,
639        content: &str,
640        style: &TextStyle,
641        max_w: Option<f32>,
642    ) -> crate::text::TextMetrics {
643        self.core.measure_text(content, style, max_w)
644    }
645
646    /// Where a point lands in the text node `key` drew, as a byte offset
647    /// and a visual line; see `Core::text_hit`. During a build it answers
648    /// from the last frame, which is the layout a click was made against.
649    pub fn text_hit(&self, key: Key, point: Vec2) -> Option<crate::text::TextHit> {
650        self.core.text_hit(key, point)
651    }
652
653    /// The window's selected text — a `selectable` scope's, or the
654    /// focused editor's; see `Core::copy_selection`.
655    pub fn selection_text(&self) -> Option<String> {
656        self.core.copy_selection()
657    }
658
659    /// The text selection's two ends as the drag made them — anchor, then
660    /// focus — each a virtualised row's data index (or none) and a byte;
661    /// see `Core::selection_ends`.
662    pub fn selection_ends(&self) -> Option<(crate::select::RangeEnd, crate::select::RangeEnd)> {
663        self.core.selection_ends()
664    }
665
666    /// The window's selection when it lives in a `cells` grid — its ends
667    /// as absolute lines and columns; see `Core::cell_selection`.
668    ///
669    /// Offered where the text selection offers only [`Self::selection_text`]
670    /// because a grid's ends mean something to the app: they are the
671    /// session's own line numbers, not byte offsets into runs the app never
672    /// laid out.
673    pub fn cell_selection(&self) -> Option<crate::select::CellSelection> {
674        self.core.cell_selection()
675    }
676
677    /// Opens a context menu; see `Core::open_menu`.
678    pub fn open_menu(&mut self, menu: crate::menu::Menu) {
679        self.core.open_menu(menu);
680    }
681
682    /// Closes whatever menu is open; see `Core::close_menu`.
683    pub fn close_menu(&mut self) -> bool {
684        self.core.close_menu()
685    }
686
687    /// Asks for the selection as text; see `Core::request_copy`.
688    pub fn request_copy(&mut self) -> crate::select::CopyRequest {
689        self.core.request_copy()
690    }
691
692    /// Answers a `selectionrange` ask; see `Core::answer_selection_range`.
693    pub fn answer_selection_range(&mut self, text: &str) -> bool {
694        self.core.answer_selection_range(text)
695    }
696
697    /// The selection as HTML; see `Core::selection_html`.
698    pub fn selection_html(&self) -> Option<String> {
699        self.core.selection_html()
700    }
701
702    /// Puts text on the system clipboard; see `Core::set_clipboard`.
703    pub fn set_clipboard(&mut self, text: impl Into<String>, html: Option<String>) {
704        self.core.set_clipboard(text, html);
705    }
706
707    /// Puts a secret on the system clipboard marked concealed and
708    /// transient, the way a password manager does; see
709    /// `Core::set_clipboard_secret`.
710    pub fn set_clipboard_secret(&mut self, text: impl Into<String>) {
711        self.core.set_clipboard_secret(text);
712    }
713
714    /// Asks for the clipboard's text, delivered as a `text` event on the
715    /// focused sink or as typing into the focused editor; see
716    /// `Core::request_paste`.
717    pub fn request_paste(&mut self) {
718        self.core.request_paste();
719    }
720
721    /// Whether a paste asked for is still unanswered; see
722    /// `Core::awaiting_paste`.
723    pub fn awaiting_paste(&self) -> bool {
724        self.core.awaiting_paste()
725    }
726
727    /// Asks the host for a file dialog; the answer is a `files` event to
728    /// whoever's view asked. False when one is already outstanding. See
729    /// `Core::request_files`.
730    #[track_caller]
731    pub fn request_files(&mut self, dialog: crate::dialog::FileDialog) -> bool {
732        self.core.request_files(dialog)
733    }
734
735    /// `Core::awaiting_files`.
736    pub fn awaiting_files(&self) -> bool {
737        self.core.awaiting_files()
738    }
739
740    /// Selects everything in the scope `key` declared; see
741    /// `Core::select_all_in`.
742    pub fn select_all_in(&mut self, key: Key) -> bool {
743        self.core.select_all_in(key)
744    }
745
746    /// Drops the window's selection; see `Core::clear_selection`.
747    pub fn clear_selection(&mut self) -> bool {
748        self.core.clear_selection()
749    }
750
751    /// The caret rect for a byte offset in the text node `key` drew; see
752    /// `Core::caret_rect`.
753    pub fn caret_rect(&self, key: Key, byte: usize) -> Option<Rect> {
754        self.core.caret_rect(key, byte)
755    }
756
757    /// `measure_text` for a rich-text paragraph.
758    pub fn measure_rich_text(
759        &mut self,
760        spans: &[Span<'_>],
761        base: &TextStyle,
762        max_w: Option<f32>,
763    ) -> crate::text::TextMetrics {
764        self.core.measure_rich_text(spans, base, max_w)
765    }
766
767    /// Opens a node under the next auto key; its children follow until
768    /// [`Self::close`]. [`Self::with`] is the scoped form, and the one to
769    /// prefer: an `open` without its `close` is a `node-left-open`
770    /// warning.
771    #[inline]
772    pub fn open(&mut self, spec: NodeSpec) -> Key {
773        self.core.open(spec)
774    }
775
776    /// [`Self::open`] under a label key: stable across frames whatever
777    /// the siblings before it, and what `key_of(label)` finds.
778    #[inline]
779    pub fn open_keyed(&mut self, label: &str, spec: NodeSpec) -> Key {
780        self.core.open_keyed(label, spec)
781    }
782
783    /// Opens a node under a key the caller built rather than a label:
784    /// `ui.child_key("gap").index(id)` is a label and an index with no
785    /// string formatted and no clash with the sibling-index keys
786    /// `open_indexed` gives, and a key kept from an earlier `child_key` —
787    /// read for `is_hovered` first — is opened as it is instead of spelled
788    /// twice. Build it from this parent's `child_key`: two nodes under one
789    /// key in a frame are a `duplicate-key` warning, as two labels are.
790    /// It has no label, so `key_of` does not find it.
791    #[inline]
792    pub fn open_key(&mut self, key: Key, spec: NodeSpec) -> Key {
793        self.core.open_key(key, spec)
794    }
795
796    /// Scoped [`Self::open_key`].
797    pub fn with_key(&mut self, key: Key, spec: NodeSpec, f: impl FnOnce(&mut Ui<'_>)) -> Key {
798        self.open_key(key, spec);
799        f(self);
800        self.close();
801        key
802    }
803
804    /// [`Self::leaf`] under a key the caller built; see [`Self::open_key`].
805    #[inline]
806    pub fn leaf_key(&mut self, key: Key, spec: NodeSpec) -> Key {
807        self.open_key(key, spec);
808        self.close();
809        key
810    }
811
812    /// `open` under a key the caller chose — the panel's own nodes, whose
813    /// keys another node anchors to by name before they exist.
814    #[inline]
815    pub(crate) fn open_with_key(&mut self, key: Key, label: &str, spec: NodeSpec) {
816        self.core.open_with_key_named(key, label, spec)
817    }
818
819    /// `open_keyed` by sibling index: the key auto-keying would have given
820    /// the `i`th child. A virtualizing list opens each row with its data
821    /// index, so a row keeps its identity when the built range slides past
822    /// it. See `Core::open_indexed`.
823    #[inline]
824    pub fn open_indexed(&mut self, i: u64, spec: NodeSpec) -> Key {
825        self.core.open_indexed(i, spec)
826    }
827
828    /// Closes the node the last `open*` opened.
829    #[inline]
830    pub fn close(&mut self) {
831        self.core.close();
832    }
833
834    /// Opens a node, runs `f` for its children and closes it. The usual
835    /// way to declare a container:
836    ///
837    /// ```rust
838    /// # use kui_core::{Core, NodeSpec, Size, TextStyle};
839    /// # let mut core = Core::new();
840    /// # let mut ui = core.frame(Size::new(200.0, 100.0), 1.0);
841    /// ui.with(NodeSpec::row().gap(8.0).pad(4.0), |ui| {
842    ///     ui.text("Name", TextStyle::new(14.0));
843    ///     ui.text("Ada", TextStyle::new(14.0));
844    /// });
845    /// # ui.finish();
846    /// ```
847    pub fn with(&mut self, spec: NodeSpec, f: impl FnOnce(&mut Ui<'_>)) -> Key {
848        let key = self.open(spec);
849        f(self);
850        self.close();
851        key
852    }
853
854    /// Scoped [`Self::open_keyed`].
855    pub fn with_keyed(&mut self, label: &str, spec: NodeSpec, f: impl FnOnce(&mut Ui<'_>)) -> Key {
856        let key = self.open_keyed(label, spec);
857        f(self);
858        self.close();
859        key
860    }
861
862    /// A node with no children: a spacer, a rule, a swatch, a hit area —
863    /// `with(spec, |_| {})` without the empty closure.
864    #[inline]
865    pub fn leaf(&mut self, spec: NodeSpec) -> Key {
866        let key = self.open(spec);
867        self.close();
868        key
869    }
870
871    /// [`Self::leaf`] under a label key.
872    #[inline]
873    pub fn leaf_keyed(&mut self, label: &str, spec: NodeSpec) -> Key {
874        let key = self.open_keyed(label, spec);
875        self.close();
876        key
877    }
878
879    /// [`Self::leaf`] under a data index; see [`Self::open_indexed`].
880    #[inline]
881    pub fn leaf_indexed(&mut self, i: u64, spec: NodeSpec) -> Key {
882        let key = self.open_indexed(i, spec);
883        self.close();
884        key
885    }
886
887    /// Declares how many indexed rows the open node's virtual list has,
888    /// built or not; see [`crate::Core::row_count`].
889    pub fn row_count(&mut self, n: u64) {
890        self.core.row_count(n);
891    }
892
893    /// Scoped `open_indexed`: the `i`th child's auto-key, given to a node
894    /// that is not in the `i`th slot.
895    pub fn with_indexed(&mut self, i: u64, spec: NodeSpec, f: impl FnOnce(&mut Ui<'_>)) -> Key {
896        let key = self.open_indexed(i, spec);
897        f(self);
898        self.close();
899        key
900    }
901
902    /// A paragraph of plain text in one style, wrapped at the width its
903    /// parent gives it. A text has no box of its own (no padding,
904    /// background, key or click); [`Self::text_in`] puts it in one.
905    ///
906    /// ```rust
907    /// # use kui_core::{Color, Core, NodeSpec, Size, TextStyle};
908    /// # let mut core = Core::new();
909    /// # let mut ui = core.frame(Size::new(200.0, 100.0), 1.0);
910    /// ui.text("Plain, in the theme's foreground", TextStyle::new(14.0));
911    /// ui.text("Bold-ish, mono, red", TextStyle::new(13.0).mono().color(Color::hex(0xd43b3bff)));
912    /// let badge = ui.text_in(NodeSpec::row().pad_xy(6.0, 2.0).radius(4.0), "3", TextStyle::new(12.0));
913    /// # let _ = badge;
914    /// # ui.finish();
915    /// ```
916    pub fn text(&mut self, content: &str, style: TextStyle) {
917        self.core.text_node(content, style);
918    }
919
920    /// A box of `spec` holding one text: `with(spec, |ui| ui.text(…))` for
921    /// the label, the cell, the badge that needs a width, a background, a
922    /// click or a role. Returns the box's key.
923    #[inline]
924    pub fn text_in(&mut self, spec: NodeSpec, content: &str, style: TextStyle) -> Key {
925        let key = self.open(spec);
926        self.text(content, style);
927        self.close();
928        key
929    }
930
931    /// [`Self::text_in`] under a label key.
932    #[inline]
933    pub fn text_in_keyed(
934        &mut self,
935        label: &str,
936        spec: NodeSpec,
937        content: &str,
938        style: TextStyle,
939    ) -> Key {
940        let key = self.open_keyed(label, spec);
941        self.text(content, style);
942        self.close();
943        key
944    }
945
946    /// [`Self::text_in`] under a data index; see [`Self::open_indexed`].
947    #[inline]
948    pub fn text_in_indexed(
949        &mut self,
950        i: u64,
951        spec: NodeSpec,
952        content: &str,
953        style: TextStyle,
954    ) -> Key {
955        let key = self.open_indexed(i, spec);
956        self.text(content, style);
957        self.close();
958        key
959    }
960
961    /// A cell grid (a terminal's screen) as one node; see
962    /// [`crate::cells`]. The spec is the node's own.
963    pub fn cells(&mut self, grid: &crate::cells::CellGrid<'_>, spec: NodeSpec) {
964        self.core.cells(grid, spec);
965    }
966
967    /// [`Self::cells`] under a data index; see [`Self::open_indexed`].
968    pub fn cells_indexed(&mut self, i: u64, grid: &crate::cells::CellGrid<'_>, spec: NodeSpec) {
969        self.core.cells_indexed(i, grid, spec);
970    }
971
972    /// [`Self::cells`] under a declared key.
973    pub fn cells_keyed(&mut self, label: &str, grid: &crate::cells::CellGrid<'_>, spec: NodeSpec) {
974        self.core.cells_keyed(label, grid, spec);
975    }
976
977    /// A paragraph of styled spans, shaped and wrapped as one flow.
978    pub fn rich_text(&mut self, spans: &[Span<'_>], base: TextStyle) {
979        self.core.rich_text_node(spans, base);
980    }
981
982    /// A registered image; see `Core::image_node` for sizing semantics.
983    pub fn image(&mut self, id: crate::resources::ImageId, spec: NodeSpec) {
984        self.core.image_node(id, spec);
985    }
986
987    /// [`Self::image`] with its `sampling` and `fit` rows; see
988    /// `Core::image_node_with`.
989    pub fn image_with(
990        &mut self,
991        id: crate::resources::ImageId,
992        opts: crate::resources::ImageOpts,
993        spec: NodeSpec,
994    ) {
995        self.core.image_node_with(id, opts, spec);
996    }
997
998    /// A box a registered WGSL function paints; see `Core::fragment_node`
999    /// for what it is, and `Core::add_fragment` for where the handle comes
1000    /// from. It has no intrinsic size, so give it one.
1001    ///
1002    /// `frag` is the handle, or `handle.with_image(img)` for a function
1003    /// that reads a registered image through `kui_sample(uv)`: a
1004    /// waveform, a heatmap, an image effect.
1005    pub fn fragment(
1006        &mut self,
1007        frag: impl Into<crate::fragment::FragmentRef>,
1008        params: &[f32],
1009        spec: NodeSpec,
1010    ) -> Key {
1011        self.core.fragment_node(frag, params, spec)
1012    }
1013
1014    /// A fragment holding children, which paint over it: a gradient card
1015    /// with a title and buttons on top of it.
1016    pub fn fragment_with(
1017        &mut self,
1018        frag: impl Into<crate::fragment::FragmentRef>,
1019        params: &[f32],
1020        spec: NodeSpec,
1021        f: impl FnOnce(&mut Ui<'_>),
1022    ) -> Key {
1023        let key = self.core.open_fragment(frag, params, spec);
1024        f(self);
1025        self.core.close();
1026        key
1027    }
1028
1029    /// [`Self::fragment`] under a label key, for one that transitions or
1030    /// exits and needs a stable identity across frames.
1031    pub fn fragment_keyed(
1032        &mut self,
1033        label: &str,
1034        frag: impl Into<crate::fragment::FragmentRef>,
1035        params: &[f32],
1036        spec: NodeSpec,
1037    ) -> Key {
1038        self.core.fragment_node_keyed(label, frag, params, spec)
1039    }
1040
1041    /// [`Self::fragment_with`] under a label key.
1042    pub fn fragment_with_keyed(
1043        &mut self,
1044        label: &str,
1045        frag: impl Into<crate::fragment::FragmentRef>,
1046        params: &[f32],
1047        spec: NodeSpec,
1048        f: impl FnOnce(&mut Ui<'_>),
1049    ) -> Key {
1050        let key = self.core.open_fragment_keyed(label, frag, params, spec);
1051        f(self);
1052        self.core.close();
1053        key
1054    }
1055
1056    /// [`Self::fragment`] under a data index; see [`Self::open_indexed`].
1057    pub fn fragment_indexed(
1058        &mut self,
1059        i: u64,
1060        frag: impl Into<crate::fragment::FragmentRef>,
1061        params: &[f32],
1062        spec: NodeSpec,
1063    ) -> Key {
1064        let key = self.core.open_fragment_indexed(i, frag, params, spec);
1065        self.core.close();
1066        key
1067    }
1068
1069    /// [`Self::fragment_with`] under a data index.
1070    pub fn fragment_with_indexed(
1071        &mut self,
1072        i: u64,
1073        frag: impl Into<crate::fragment::FragmentRef>,
1074        params: &[f32],
1075        spec: NodeSpec,
1076        f: impl FnOnce(&mut Ui<'_>),
1077    ) -> Key {
1078        let key = self.core.open_fragment_indexed(i, frag, params, spec);
1079        f(self);
1080        self.core.close();
1081        key
1082    }
1083
1084    /// A round-capped segment from `from` to `to`, in the parent's box
1085    /// space; see `Core::line_node` for what it is and is not.
1086    #[inline]
1087    pub fn line(&mut self, from: Vec2, to: Vec2, stroke: Stroke, spec: NodeSpec) {
1088        self.core.line_node(&[from, to], stroke, spec);
1089    }
1090
1091    /// [`Self::line`] under a label key.
1092    pub fn line_keyed(
1093        &mut self,
1094        label: &str,
1095        from: Vec2,
1096        to: Vec2,
1097        stroke: Stroke,
1098        spec: NodeSpec,
1099    ) {
1100        self.core.line_node_keyed(label, &[from, to], stroke, spec);
1101    }
1102
1103    /// [`Self::line`] under a data index; see [`Self::open_indexed`].
1104    pub fn line_indexed(&mut self, i: u64, from: Vec2, to: Vec2, stroke: Stroke, spec: NodeSpec) {
1105        self.core.line_node_indexed(i, &[from, to], stroke, spec);
1106    }
1107
1108    /// A stroke through `points`: a polyline, or a smooth curve through
1109    /// them with [`Stroke::curve`]; see `Core::line_node`.
1110    #[inline]
1111    pub fn polyline(&mut self, points: &[Vec2], stroke: Stroke, spec: NodeSpec) {
1112        self.core.line_node(points, stroke, spec);
1113    }
1114
1115    /// [`Self::polyline`] under a data index; see [`Self::open_indexed`].
1116    pub fn polyline_indexed(&mut self, i: u64, points: &[Vec2], stroke: Stroke, spec: NodeSpec) {
1117        self.core.line_node_indexed(i, points, stroke, spec);
1118    }
1119
1120    /// [`Self::polyline`] under a label key.
1121    pub fn polyline_keyed(&mut self, label: &str, points: &[Vec2], stroke: Stroke, spec: NodeSpec) {
1122        self.core.line_node_keyed(label, points, stroke, spec);
1123    }
1124
1125    /// A filled polygon through `points` in the parent's box space, the
1126    /// fill in `spec`'s `bg`; see `Core::polygon_node` for what it is and
1127    /// is not.
1128    pub fn polygon(&mut self, points: &[Vec2], spec: NodeSpec) {
1129        self.core.polygon_node(points, spec);
1130    }
1131
1132    /// [`Self::polygon`] under a label key.
1133    pub fn polygon_keyed(&mut self, label: &str, points: &[Vec2], spec: NodeSpec) {
1134        self.core.polygon_node_keyed(label, points, spec);
1135    }
1136
1137    /// [`Self::polygon`] under a data index; see [`Self::open_indexed`].
1138    pub fn polygon_indexed(&mut self, i: u64, points: &[Vec2], spec: NodeSpec) {
1139        self.core.polygon_node_indexed(i, points, spec);
1140    }
1141
1142    /// A path — any outline — filled with `spec`'s `bg` and stroked by
1143    /// the path's own stroke; see `Core::path_node` for what it is and
1144    /// is not.
1145    pub fn path(&mut self, path: &crate::path::Path, spec: NodeSpec) {
1146        self.core.path_node(path, spec);
1147    }
1148
1149    /// [`Self::path`] under a label key.
1150    pub fn path_keyed(&mut self, label: &str, path: &crate::path::Path, spec: NodeSpec) {
1151        self.core.path_node_keyed(label, path, spec);
1152    }
1153
1154    /// [`Self::path`] under a data index; see [`Self::open_indexed`].
1155    pub fn path_indexed(&mut self, i: u64, path: &crate::path::Path, spec: NodeSpec) {
1156        self.core.path_node_indexed(i, path, spec);
1157    }
1158
1159    /// [`Self::path`] from SVG path data; data that does not parse raises
1160    /// `path-malformed` and draws nothing. See `Core::path_d_node`.
1161    pub fn path_d(
1162        &mut self,
1163        d: &str,
1164        rule: crate::path::FillRule,
1165        stroke: Option<Stroke>,
1166        turn: Option<crate::path::Turn>,
1167        spec: NodeSpec,
1168    ) {
1169        self.core.path_d_node(d, rule, stroke, turn, spec);
1170    }
1171
1172    /// [`Self::path_d`] under a label key.
1173    pub fn path_d_keyed(
1174        &mut self,
1175        label: &str,
1176        d: &str,
1177        rule: crate::path::FillRule,
1178        stroke: Option<Stroke>,
1179        turn: Option<crate::path::Turn>,
1180        spec: NodeSpec,
1181    ) {
1182        self.core
1183            .path_d_node_keyed(label, d, rule, stroke, turn, spec);
1184    }
1185
1186    /// An `audio` node: a playback retained for as long as the view keeps
1187    /// declaring it; see `Core::audio_node`.
1188    pub fn audio(&mut self, spec: crate::audio::AudioSpec) -> Key {
1189        self.core.audio_node(spec)
1190    }
1191
1192    /// `audio` with a label-derived key; see `Core::audio_node_keyed`.
1193    pub fn audio_keyed(&mut self, label: &str, spec: crate::audio::AudioSpec) -> Key {
1194        self.core.audio_node_keyed(label, spec)
1195    }
1196
1197    /// Starts a playback from a view; see `Core::play`. Views run every
1198    /// frame, so gate it on state that changes once (or use `audio`).
1199    pub fn play(
1200        &mut self,
1201        sound: crate::resources::SoundId,
1202        opts: crate::audio::PlayOptions,
1203    ) -> crate::audio::PlaybackId {
1204        self.core.play(sound, opts)
1205    }
1206
1207    /// An editable text node; state retained by key. See `Core::text_edit`.
1208    pub fn text_edit(
1209        &mut self,
1210        label: &str,
1211        initial: &str,
1212        opts: &EditOptions,
1213        spec: NodeSpec,
1214    ) -> Key {
1215        self.core.text_edit(label, initial, opts, spec)
1216    }
1217
1218    /// Whether `key` holds keyboard focus — any node: an editor, a key
1219    /// sink, a button Tab landed on (see `Core::focus`).
1220    pub fn is_focused(&self, key: Key) -> bool {
1221        self.core.is_focused(key)
1222    }
1223
1224    /// The node holding keyboard focus, if any.
1225    pub fn focused(&self) -> Option<Key> {
1226        self.core.focus()
1227    }
1228
1229    /// Whether focus got where it is by keyboard or assistive technology
1230    /// (a Tab press, a reader's request) rather than a click — when a
1231    /// view that styles its own focus should show it.
1232    pub fn focus_visible(&self) -> bool {
1233        self.core.focus_visible()
1234    }
1235
1236    /// The key of the node opened under the key label `label` — in this
1237    /// frame so far, then in the last finished one. The key label is the
1238    /// name the view opened the node under (`with_keyed`, a `key` prop),
1239    /// not the accessible name its `label` row gives a reader, which
1240    /// `Core::key_named` looks up. For a caller that holds only the label
1241    /// and cannot spell the path (`child_key` is the same question asked
1242    /// from the parent); see `Core::key_of`.
1243    pub fn key_of(&mut self, label: &str) -> Option<Key> {
1244        self.core.key_of(label)
1245    }
1246
1247    /// Moves keyboard focus to `key` now (an editor, an `on_key` sink, a
1248    /// control, a `focusable` node); see `Core::set_focus`.
1249    pub fn focus(&mut self, key: Key) {
1250        self.core.set_focus(Some(key));
1251    }
1252
1253    /// Drops keyboard focus.
1254    pub fn blur(&mut self) {
1255        self.core.set_focus(None);
1256    }
1257
1258    /// Moves focus to the next focusable node in tree order, wrapping —
1259    /// what Tab does. A key sink that binds Tab itself calls this to hand
1260    /// the keyboard on.
1261    ///
1262    /// Deferred, unlike the rest of this handle: a `Ui` only exists while a
1263    /// frame is being built, and `begin_frame` cleared the tree the Tab
1264    /// ring is made of, so stepping now would walk an empty ring. The step
1265    /// is applied at `finish`, against the frame this call is part of — so
1266    /// a view that declares three rows and asks to step lands on one of
1267    /// them, without waiting a frame for them to exist. Outside a frame
1268    /// (a driver handling a key press) `Core::focus_next` steps at once.
1269    #[track_caller]
1270    pub fn focus_next(&mut self) {
1271        self.core.request_focus_step(true);
1272    }
1273
1274    /// Shift-Tab: the previous focusable node. Deferred to `finish` for the
1275    /// reason [`Ui::focus_next`] gives.
1276    #[track_caller]
1277    pub fn focus_prev(&mut self) {
1278        self.core.request_focus_step(false);
1279    }
1280
1281    /// Enters a focus region (the node `key` names, declared
1282    /// `focus_region`), or the main ring for `None`: focus lands on what
1283    /// that ring
1284    /// last held if the node is still there, else its `initial_focus`,
1285    /// else its first stop, and shows. Deferred to `finish` like
1286    /// [`Ui::focus_next`], so a view may name the region it is declaring
1287    /// right now — the dock this frame toggles on. A key the frame does
1288    /// not declare as a region raises `focus-region-without-node`.
1289    #[track_caller]
1290    pub fn focus_region(&mut self, key: Option<Key>) {
1291        self.core.focus_region(key);
1292    }
1293
1294    /// The focus region in effect — the node whose ring Tab walks — or
1295    /// `None` for the main ring. What a chord that toggles between a dock
1296    /// and the app reads to know which way it is going.
1297    pub fn region(&self) -> Option<Key> {
1298        self.core.region()
1299    }
1300
1301    /// An editor's current text, by its key; `None` for a key no editor
1302    /// holds.
1303    pub fn edit_text(&self, key: Key) -> Option<String> {
1304        self.core.edit_text(key)
1305    }
1306
1307    /// Replaces an editor's text, caret at the end (`Core::set_edit_text`).
1308    /// Returns whether it reached an editor now, or was held for the
1309    /// frame that declares the key.
1310    pub fn set_edit_text(&mut self, key: Key, text: &str) -> bool {
1311        self.core.set_edit_text(key, text)
1312    }
1313
1314    /// The same by the label the view declares, for a caller with no key
1315    /// yet: an `update` opening a field the editor has not fired an
1316    /// event from (`Core::set_edit_text_by_label`).
1317    pub fn set_edit_text_by_label(&mut self, label: &str, text: &str) -> bool {
1318        self.core.set_edit_text_by_label(label, text)
1319    }
1320
1321    /// Says something once, with no node behind it (`Core::announce`).
1322    /// Takes effect at once, unlike `focus_next`: the queue is not made of
1323    /// a finished tree.
1324    ///
1325    /// A view runs every frame, so a call made from here needs a guard the
1326    /// app clears; the core reports the unguarded case as
1327    /// `announcement-repeated`. A region whose message is on screen is the
1328    /// `live` prop instead.
1329    pub fn announce(&mut self, text: &str, live: crate::access::Live) {
1330        self.core.announce(text, live);
1331    }
1332
1333    /// Scrolls whatever contains `key` so the node shows — "scroll to the
1334    /// selected row", without the container geometry the app cannot see.
1335    /// Resolved when this frame finishes laying out, so a row the view is
1336    /// declaring right now reveals fine; a key the frame does not declare,
1337    /// or one nothing scrollable contains, is a no-op. See `Core::reveal`.
1338    #[track_caller]
1339    pub fn reveal(&mut self, key: Key) {
1340        self.core.reveal(key);
1341    }
1342
1343    /// The handle for an installed or loaded font family by name (what
1344    /// `family = "Name"` resolves to in the declarative bindings), so a
1345    /// Rust view names a face without reaching for the core. `None` when
1346    /// no face matches. Idempotent.
1347    pub fn system_font(&mut self, name: &str) -> Option<crate::resources::FontId> {
1348        self.core.add_system_font(name)
1349    }
1350
1351    /// [`Self::reveal`] by label, resolved when this frame finishes; see
1352    /// `Core::reveal_label`.
1353    #[track_caller]
1354    pub fn reveal_label(&mut self, label: &str) {
1355        self.core.reveal_label(label);
1356    }
1357
1358    /// `set_scroll` by label, resolved before this frame lays out; see
1359    /// `Core::set_scroll_label`.
1360    #[track_caller]
1361    pub fn set_scroll_label(&mut self, label: &str, offset: Vec2) {
1362        self.core.set_scroll_label(label, offset);
1363    }
1364
1365    /// A scroll container's retained offset, clamped as of the last
1366    /// layout — the number to stash in a model and hand back to
1367    /// `set_scroll` later. Zero for a node that never scrolled.
1368    pub fn scroll_offset(&self, key: Key) -> Vec2 {
1369        self.core.scroll_offset(key)
1370    }
1371
1372    /// Sets that offset, the way the wheel would: `Vec2::ZERO` jumps to
1373    /// the top, a large value to the end (the next layout clamps it).
1374    #[track_caller]
1375    pub fn set_scroll(&mut self, key: Key, offset: Vec2) {
1376        self.core.set_scroll(key, offset);
1377    }
1378
1379    /// Moves a container's scroll state by the content that moved under
1380    /// it (`drawn` for the drawn place and an eased leg's start, `target`
1381    /// for the offset) with no ease asked or ended: a variable-height
1382    /// list's height correction. See `Core::shift_scroll`.
1383    pub fn shift_scroll(&mut self, key: Key, drawn: Vec2, target: Vec2) {
1384        self.core.shift_scroll(key, drawn, target);
1385    }
1386
1387    /// What the last layout resolved for a scroll container — its box, its
1388    /// content size and the clamped offset — so a view can build only the
1389    /// rows that fit and two spacers instead of ten thousand rows. `None`
1390    /// until a layout has resolved `key` as a container. It describes the
1391    /// previous frame; see `Core::scroll_geometry`, or
1392    /// `widgets::uniform_list` for the uniform-row case.
1393    pub fn scroll_geometry(&self, key: Key) -> Option<crate::scroll::ScrollGeometry> {
1394        self.core.scroll_geometry(key)
1395    }
1396
1397    /// The rect the last frame laid an `on_layout` node out at; see
1398    /// `Core::layout_of`.
1399    pub fn layout_of(&self, key: Key) -> Option<Rect> {
1400        self.core.layout_of(key)
1401    }
1402
1403    /// Declares this node focused: it takes keyboard focus when the
1404    /// declaration *starts* (the first frame it is made), and a Tab press
1405    /// afterwards is not clobbered by the view repeating it. An `on_key`
1406    /// sink then gets presses in `on_event` as `{kind="key", code, ctrl,
1407    /// alt, shift, super, text, repeat, tag}`. To move focus at any time,
1408    /// `focus(key)`.
1409    pub fn take_key_focus(&mut self, key: Key) {
1410        self.core.set_key_focus(Some(key));
1411    }
1412
1413    /// The node holding keyboard focus (the same as `focused`).
1414    pub fn key_focus(&self) -> Option<Key> {
1415        self.core.key_focus()
1416    }
1417
1418    /// Asks the frame driver to apply a window command (close from a
1419    /// keymap, minimize from a command line).
1420    pub fn window_command(&mut self, cmd: WindowCommand) {
1421        self.core.push_window_command(cmd);
1422    }
1423
1424    /// Asks the driver to resize a window (logical px) — a request applied
1425    /// on the driver's next pump and ignored headlessly, not a declaration:
1426    /// the user owns a window's size once it exists. `ui.env().window.id`
1427    /// is the window this view is drawing. See `Core::set_window_size`.
1428    pub fn set_window_size(&mut self, window: WindowId, size: Size) {
1429        self.core.set_window_size(window, size);
1430    }
1431
1432    /// Asks the driver to give a window keyboard focus; queued the same
1433    /// way. See `Core::focus_window`.
1434    pub fn focus_window(&mut self, window: WindowId) {
1435        self.core.focus_window(window);
1436    }
1437
1438    /// Runs layout and emission; results land in `Core::output()`. A frame
1439    /// begun with a filler lets it finish first: the `"root"` fill, unless
1440    /// the view declared it, and the `unknown-slot` check. An open context
1441    /// menu is drawn after both, which is what makes it the frame's modal
1442    /// scope and its topmost float.
1443    pub fn finish(self) {
1444        let Ui { core, filler } = self;
1445        // Not in the devtools' own window: nothing the host or an
1446        // extension declares there is built.
1447        if let Some(filler) = filler {
1448            if !core.devtools_window() {
1449                // A declared tab's extension fill first — a layer
1450                // anchored to a body the panel builds below, so the
1451                // filler's own `unknown-slot` check sees the slot
1452                // declared — then the root fills.
1453                core.devtools_fill_mount(filler);
1454                filler.finish(&mut Ui::new(core));
1455            }
1456            // The panel, after the fills and before the menu: the menu is
1457            // the last thing declared and so the topmost float.
1458            core.devtools_finish();
1459            if core.devtools_window() {
1460                // The panel's own window: the extension form's fill lands
1461                // here too, when the pane gave the frame a filler.
1462                core.devtools_fill_mount(filler);
1463            }
1464        } else {
1465            core.devtools_finish();
1466        }
1467        Core::build_menu(&mut Ui::new(core));
1468        core.finish_frame();
1469    }
1470}