Skip to main content

slt/context/widgets_interactive/
events.rs

1use super::*;
2
3impl Context {
4    /// Render a help bar showing keybinding hints.
5    ///
6    /// `bindings` is a slice of `(key, action)` pairs. Keys are rendered in the
7    /// theme's primary color; actions in the dim text color. Pairs are separated
8    /// by a `·` character.
9    pub fn help(&mut self, bindings: &[(&str, &str)]) -> Response {
10        if bindings.is_empty() {
11            return Response::none();
12        }
13
14        self.skip_interaction_slot();
15        let help_gap = self.theme.spacing.sm();
16        self.commands
17            .push(Command::BeginContainer(Box::new(BeginContainerArgs {
18                direction: Direction::Row,
19                gap: help_gap as i32,
20                align: Align::Start,
21                align_self: None,
22                justify: Justify::Start,
23                border: None,
24                border_sides: BorderSides::all(),
25                border_style: Style::new().fg(self.theme.border),
26                bg_color: None,
27                padding: Padding::default(),
28                margin: Margin::default(),
29                constraints: Constraints::default(),
30                title: None,
31                grow: 0,
32                group_name: None,
33            })));
34        for (idx, (key, action)) in bindings.iter().enumerate() {
35            if idx > 0 {
36                self.styled("·", Style::new().fg(self.theme.text_dim));
37            }
38            self.styled(*key, Style::new().bold().fg(self.theme.primary));
39            self.styled(*action, Style::new().fg(self.theme.text_dim));
40        }
41        self.commands.push(Command::EndContainer);
42        self.rollback.last_text_idx = None;
43
44        Response::none()
45    }
46
47    /// Render a help bar with custom key/description colors.
48    pub fn help_colored(
49        &mut self,
50        bindings: &[(&str, &str)],
51        key_color: Color,
52        text_color: Color,
53    ) -> Response {
54        if bindings.is_empty() {
55            return Response::none();
56        }
57
58        self.skip_interaction_slot();
59        let help_gap = self.theme.spacing.sm();
60        self.commands
61            .push(Command::BeginContainer(Box::new(BeginContainerArgs {
62                direction: Direction::Row,
63                gap: help_gap as i32,
64                align: Align::Start,
65                align_self: None,
66                justify: Justify::Start,
67                border: None,
68                border_sides: BorderSides::all(),
69                border_style: Style::new().fg(self.theme.border),
70                bg_color: None,
71                padding: Padding::default(),
72                margin: Margin::default(),
73                constraints: Constraints::default(),
74                title: None,
75                grow: 0,
76                group_name: None,
77            })));
78        for (idx, (key, action)) in bindings.iter().enumerate() {
79            if idx > 0 {
80                self.styled("·", Style::new().fg(text_color));
81            }
82            self.styled(*key, Style::new().bold().fg(key_color));
83            self.styled(*action, Style::new().fg(text_color));
84        }
85        self.commands.push(Command::EndContainer);
86        self.rollback.last_text_idx = None;
87
88        Response::none()
89    }
90
91    // ── events ───────────────────────────────────────────────────────
92
93    /// Check if a character key was pressed this frame.
94    ///
95    /// Returns `true` if the key event has not been consumed by another widget.
96    pub fn key(&self, c: char) -> bool {
97        if (self.rollback.modal_active || self.prev_modal_active)
98            && self.rollback.overlay_depth == 0
99        {
100            return false;
101        }
102        self.events.iter().enumerate().any(|(i, e)| {
103            !self.consumed[i]
104                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Press && k.code == KeyCode::Char(c))
105        })
106    }
107
108    /// Check if a specific key code was pressed this frame.
109    ///
110    /// Returns `true` if the key event has not been consumed by another widget.
111    /// Blocked when a modal/overlay is active and the caller is outside the overlay.
112    /// Use [`raw_key_code`](Self::raw_key_code) for global shortcuts that must work
113    /// regardless of modal/overlay state.
114    pub fn key_code(&self, code: KeyCode) -> bool {
115        if (self.rollback.modal_active || self.prev_modal_active)
116            && self.rollback.overlay_depth == 0
117        {
118            return false;
119        }
120        self.events.iter().enumerate().any(|(i, e)| {
121            !self.consumed[i]
122                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Press && k.code == code)
123        })
124    }
125
126    /// Check if a specific key code was pressed this frame, ignoring modal/overlay state.
127    ///
128    /// Unlike [`key_code`](Self::key_code), this method bypasses the modal/overlay guard
129    /// so it works even when a modal or overlay is active. Use this for global shortcuts
130    /// (e.g. Esc to close a modal, Ctrl+Q to quit) that must always be reachable.
131    ///
132    /// Returns `true` if the key event has not been consumed by another widget.
133    pub fn raw_key_code(&self, code: KeyCode) -> bool {
134        self.events.iter().enumerate().any(|(i, e)| {
135            !self.consumed[i]
136                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Press && k.code == code)
137        })
138    }
139
140    /// Check if a character key was released this frame.
141    ///
142    /// Returns `true` if the key release event has not been consumed by another widget.
143    pub fn key_release(&self, c: char) -> bool {
144        if (self.rollback.modal_active || self.prev_modal_active)
145            && self.rollback.overlay_depth == 0
146        {
147            return false;
148        }
149        self.events.iter().enumerate().any(|(i, e)| {
150            !self.consumed[i]
151                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Release && k.code == KeyCode::Char(c))
152        })
153    }
154
155    /// Check if a specific key code was released this frame.
156    ///
157    /// Returns `true` if the key release event has not been consumed by another widget.
158    pub fn key_code_release(&self, code: KeyCode) -> bool {
159        if (self.rollback.modal_active || self.prev_modal_active)
160            && self.rollback.overlay_depth == 0
161        {
162            return false;
163        }
164        self.events.iter().enumerate().any(|(i, e)| {
165            !self.consumed[i]
166                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Release && k.code == code)
167        })
168    }
169
170    /// Check for a character key press and consume the event, preventing other
171    /// handlers from seeing it.
172    ///
173    /// Returns `true` if the key was found unconsumed and is now consumed.
174    /// Unlike [`key()`](Self::key) which peeks without consuming, this claims
175    /// exclusive ownership of the event.
176    ///
177    /// Call **after** widgets if you want widgets to have priority over your
178    /// handler, or **before** widgets to intercept first.
179    pub fn consume_key(&mut self, c: char) -> bool {
180        if (self.rollback.modal_active || self.prev_modal_active)
181            && self.rollback.overlay_depth == 0
182        {
183            return false;
184        }
185        let index = self.available_key_presses().find_map(|(i, key)| {
186            if key.code == KeyCode::Char(c) {
187                Some(i)
188            } else {
189                None
190            }
191        });
192        if let Some(index) = index {
193            self.consume_indices([index]);
194            true
195        } else {
196            false
197        }
198    }
199
200    /// Check for a special key press and consume the event, preventing other
201    /// handlers from seeing it.
202    ///
203    /// Returns `true` if the key was found unconsumed and is now consumed.
204    /// Unlike [`key_code()`](Self::key_code) which peeks without consuming,
205    /// this claims exclusive ownership of the event.
206    ///
207    /// Call **after** widgets if you want widgets to have priority over your
208    /// handler, or **before** widgets to intercept first.
209    pub fn consume_key_code(&mut self, code: KeyCode) -> bool {
210        if (self.rollback.modal_active || self.prev_modal_active)
211            && self.rollback.overlay_depth == 0
212        {
213            return false;
214        }
215        let index = self
216            .available_key_presses()
217            .find_map(|(i, key)| if key.code == code { Some(i) } else { None });
218        if let Some(index) = index {
219            self.consume_indices([index]);
220            true
221        } else {
222            false
223        }
224    }
225
226    /// Check if a character key with specific modifiers was pressed this frame.
227    ///
228    /// Returns `true` if the key event has not been consumed by another widget.
229    pub fn key_mod(&self, c: char, modifiers: KeyModifiers) -> bool {
230        if (self.rollback.modal_active || self.prev_modal_active)
231            && self.rollback.overlay_depth == 0
232        {
233            return false;
234        }
235        self.events.iter().enumerate().any(|(i, e)| {
236            !self.consumed[i]
237                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Press && k.code == KeyCode::Char(c) && k.modifiers.contains(modifiers))
238        })
239    }
240
241    /// Like [`key_mod`](Self::key_mod) but bypasses the modal/overlay guard.
242    pub fn raw_key_mod(&self, c: char, modifiers: KeyModifiers) -> bool {
243        self.events.iter().enumerate().any(|(i, e)| {
244            !self.consumed[i]
245                && matches!(e, Event::Key(k) if k.kind == KeyEventKind::Press && k.code == KeyCode::Char(c) && k.modifiers.contains(modifiers))
246        })
247    }
248
249    /// Return the position of a left mouse button down event this frame, if any.
250    ///
251    /// Returns `None` if no unconsumed mouse-down event occurred.
252    pub fn mouse_down(&self) -> Option<(u32, u32)> {
253        if (self.rollback.modal_active || self.prev_modal_active)
254            && self.rollback.overlay_depth == 0
255        {
256            return None;
257        }
258        self.events.iter().enumerate().find_map(|(i, event)| {
259            if self.consumed[i] {
260                return None;
261            }
262            if let Event::Mouse(mouse) = event
263                && matches!(mouse.kind, MouseKind::Down(MouseButton::Left))
264            {
265                return Some((mouse.x, mouse.y));
266            }
267            None
268        })
269    }
270
271    /// Return the position of a left mouse button drag event this frame, if any.
272    ///
273    /// Returns `None` if no unconsumed drag event occurred. Drag events fire
274    /// while the left button is held and the cursor moves.
275    pub fn mouse_drag(&self) -> Option<(u32, u32)> {
276        if (self.rollback.modal_active || self.prev_modal_active)
277            && self.rollback.overlay_depth == 0
278        {
279            return None;
280        }
281        self.events.iter().enumerate().find_map(|(i, event)| {
282            if self.consumed[i] {
283                return None;
284            }
285            if let Event::Mouse(mouse) = event
286                && matches!(mouse.kind, MouseKind::Drag(MouseButton::Left))
287            {
288                return Some((mouse.x, mouse.y));
289            }
290            None
291        })
292    }
293
294    /// Return the position of a left mouse button release event this frame, if any.
295    ///
296    /// Returns `None` if no unconsumed mouse-up event occurred.
297    pub fn mouse_up(&self) -> Option<(u32, u32)> {
298        if (self.rollback.modal_active || self.prev_modal_active)
299            && self.rollback.overlay_depth == 0
300        {
301            return None;
302        }
303        self.events.iter().enumerate().find_map(|(i, event)| {
304            if self.consumed[i] {
305                return None;
306            }
307            if let Event::Mouse(mouse) = event
308                && matches!(mouse.kind, MouseKind::Up(MouseButton::Left))
309            {
310                return Some((mouse.x, mouse.y));
311            }
312            None
313        })
314    }
315
316    /// Return the position of a mouse button down event for the specified button.
317    ///
318    /// This is a generalized version of [`mouse_down`](Self::mouse_down) that
319    /// accepts any [`MouseButton`].
320    pub fn mouse_down_button(&self, button: MouseButton) -> Option<(u32, u32)> {
321        if (self.rollback.modal_active || self.prev_modal_active)
322            && self.rollback.overlay_depth == 0
323        {
324            return None;
325        }
326        self.events.iter().enumerate().find_map(|(i, event)| {
327            if self.consumed[i] {
328                return None;
329            }
330            if let Event::Mouse(mouse) = event
331                && matches!(&mouse.kind, MouseKind::Down(b) if *b == button)
332            {
333                return Some((mouse.x, mouse.y));
334            }
335            None
336        })
337    }
338
339    /// Return the position of a mouse drag event for the specified button.
340    pub fn mouse_drag_button(&self, button: MouseButton) -> Option<(u32, u32)> {
341        if (self.rollback.modal_active || self.prev_modal_active)
342            && self.rollback.overlay_depth == 0
343        {
344            return None;
345        }
346        self.events.iter().enumerate().find_map(|(i, event)| {
347            if self.consumed[i] {
348                return None;
349            }
350            if let Event::Mouse(mouse) = event
351                && matches!(&mouse.kind, MouseKind::Drag(b) if *b == button)
352            {
353                return Some((mouse.x, mouse.y));
354            }
355            None
356        })
357    }
358
359    /// Return the position of a mouse button release event for the specified button.
360    pub fn mouse_up_button(&self, button: MouseButton) -> Option<(u32, u32)> {
361        if (self.rollback.modal_active || self.prev_modal_active)
362            && self.rollback.overlay_depth == 0
363        {
364            return None;
365        }
366        self.events.iter().enumerate().find_map(|(i, event)| {
367            if self.consumed[i] {
368                return None;
369            }
370            if let Event::Mouse(mouse) = event
371                && matches!(&mouse.kind, MouseKind::Up(b) if *b == button)
372            {
373                return Some((mouse.x, mouse.y));
374            }
375            None
376        })
377    }
378
379    /// Return the current mouse cursor position, if known.
380    ///
381    /// The position is updated on every mouse move or click event. Returns
382    /// `None` until the first mouse event is received.
383    pub fn mouse_pos(&self) -> Option<(u32, u32)> {
384        self.mouse_pos
385    }
386
387    /// Return the first unconsumed paste event text, if any.
388    pub fn paste(&self) -> Option<&str> {
389        if (self.rollback.modal_active || self.prev_modal_active)
390            && self.rollback.overlay_depth == 0
391        {
392            return None;
393        }
394        self.events.iter().enumerate().find_map(|(i, event)| {
395            if self.consumed[i] {
396                return None;
397            }
398            if let Event::Paste(text) = event {
399                return Some(text.as_str());
400            }
401            None
402        })
403    }
404
405    /// Check if an unconsumed scroll-up event occurred this frame.
406    pub fn scroll_up(&self) -> bool {
407        if (self.rollback.modal_active || self.prev_modal_active)
408            && self.rollback.overlay_depth == 0
409        {
410            return false;
411        }
412        self.events.iter().enumerate().any(|(i, event)| {
413            !self.consumed[i]
414                && matches!(event, Event::Mouse(mouse) if matches!(mouse.kind, MouseKind::ScrollUp))
415        })
416    }
417
418    /// Check if an unconsumed scroll-down event occurred this frame.
419    pub fn scroll_down(&self) -> bool {
420        if (self.rollback.modal_active || self.prev_modal_active)
421            && self.rollback.overlay_depth == 0
422        {
423            return false;
424        }
425        self.events.iter().enumerate().any(|(i, event)| {
426            !self.consumed[i]
427                && matches!(event, Event::Mouse(mouse) if matches!(mouse.kind, MouseKind::ScrollDown))
428        })
429    }
430
431    /// Check if an unconsumed scroll-left event occurred this frame.
432    pub fn scroll_left(&self) -> bool {
433        if (self.rollback.modal_active || self.prev_modal_active)
434            && self.rollback.overlay_depth == 0
435        {
436            return false;
437        }
438        self.events.iter().enumerate().any(|(i, event)| {
439            !self.consumed[i]
440                && matches!(event, Event::Mouse(mouse) if matches!(mouse.kind, MouseKind::ScrollLeft))
441        })
442    }
443
444    /// Check if an unconsumed scroll-right event occurred this frame.
445    pub fn scroll_right(&self) -> bool {
446        if (self.rollback.modal_active || self.prev_modal_active)
447            && self.rollback.overlay_depth == 0
448        {
449            return false;
450        }
451        self.events.iter().enumerate().any(|(i, event)| {
452            !self.consumed[i]
453                && matches!(event, Event::Mouse(mouse) if matches!(mouse.kind, MouseKind::ScrollRight))
454        })
455    }
456
457    /// Iterate over unconsumed events this frame, respecting the modal guard.
458    ///
459    /// Returns an empty iterator when a modal is active and the caller is not
460    /// inside an overlay. Use [`raw_events`](Self::raw_events) to bypass the
461    /// modal guard (e.g., for global hotkeys).
462    ///
463    /// # Example
464    ///
465    /// ```no_run
466    /// # slt::run(|ui: &mut slt::Context| {
467    /// for event in ui.events() {
468    ///     if let slt::Event::Mouse(mouse) = event {
469    ///         if matches!(mouse.kind, slt::MouseKind::Down(slt::MouseButton::Right)) {
470    ///             // handle right-click
471    ///         }
472    ///     }
473    /// }
474    /// # });
475    /// ```
476    pub fn events(&self) -> impl Iterator<Item = &Event> {
477        let blocked = (self.rollback.modal_active || self.prev_modal_active)
478            && self.rollback.overlay_depth == 0;
479        self.events.iter().enumerate().filter_map(move |(i, e)| {
480            if blocked || self.consumed[i] {
481                None
482            } else {
483                Some(e)
484            }
485        })
486    }
487
488    /// Iterate over all unconsumed events, bypassing the modal guard.
489    ///
490    /// Use this for global shortcuts that must work even when a modal or
491    /// overlay is active. Prefer [`events`](Self::events) for normal use.
492    pub fn raw_events(&self) -> impl Iterator<Item = &Event> + '_ {
493        self.events
494            .iter()
495            .enumerate()
496            .filter_map(|(i, e)| if self.consumed[i] { None } else { Some(e) })
497    }
498
499    /// Signal the run loop to exit after this frame.
500    pub fn quit(&mut self) {
501        self.should_quit = true;
502    }
503
504    /// Copy text to the system clipboard via OSC 52.
505    ///
506    /// Works transparently over SSH connections. The text is queued and
507    /// written to the terminal after the current frame renders.
508    ///
509    /// Requires a terminal that supports OSC 52 (most modern terminals:
510    /// Ghostty, kitty, WezTerm, iTerm2, Windows Terminal).
511    pub fn copy_to_clipboard(&mut self, text: impl Into<String>) {
512        self.clipboard_text = Some(text.into());
513    }
514
515    /// Get the current theme.
516    pub fn theme(&self) -> &Theme {
517        &self.theme
518    }
519
520    /// Resolve a [`ThemeColor`] token against the current theme.
521    pub fn color(&self, token: ThemeColor) -> Color {
522        self.theme.resolve(token)
523    }
524
525    /// Get the current spacing scale from the theme.
526    pub fn spacing(&self) -> Spacing {
527        self.theme.spacing
528    }
529
530    /// Change the theme for subsequent rendering.
531    ///
532    /// All widgets rendered after this call will use the new theme's colors.
533    pub fn set_theme(&mut self, theme: Theme) {
534        self.theme = theme;
535    }
536
537    /// Check if dark mode is active.
538    pub fn is_dark_mode(&self) -> bool {
539        self.rollback.dark_mode
540    }
541
542    /// Set dark mode. When true, dark_* style variants are applied.
543    pub fn set_dark_mode(&mut self, dark: bool) {
544        self.rollback.dark_mode = dark;
545    }
546
547    // ── info ─────────────────────────────────────────────────────────
548
549    /// Get the terminal width in cells.
550    pub fn width(&self) -> u32 {
551        self.area_width
552    }
553
554    /// Get the current terminal width breakpoint.
555    ///
556    /// Returns a [`Breakpoint`] based on the terminal width:
557    /// - `Xs`: < 40 columns
558    /// - `Sm`: 40-79 columns
559    /// - `Md`: 80-119 columns
560    /// - `Lg`: 120-159 columns
561    /// - `Xl`: >= 160 columns
562    ///
563    /// Use this for responsive layouts that adapt to terminal size:
564    /// ```no_run
565    /// # use slt::{Breakpoint, Context};
566    /// # slt::run(|ui: &mut Context| {
567    /// match ui.breakpoint() {
568    ///     Breakpoint::Xs | Breakpoint::Sm => {
569    ///         ui.col(|ui| { ui.text("Stacked layout"); });
570    ///     }
571    ///     _ => {
572    ///         ui.row(|ui| { ui.text("Side-by-side layout"); });
573    ///     }
574    /// }
575    /// # });
576    /// ```
577    pub fn breakpoint(&self) -> Breakpoint {
578        let w = self.area_width;
579        if w < 40 {
580            Breakpoint::Xs
581        } else if w < 80 {
582            Breakpoint::Sm
583        } else if w < 120 {
584            Breakpoint::Md
585        } else if w < 160 {
586            Breakpoint::Lg
587        } else {
588            Breakpoint::Xl
589        }
590    }
591
592    /// Get the terminal height in cells.
593    pub fn height(&self) -> u32 {
594        self.area_height
595    }
596
597    /// Get the current tick count (increments each frame).
598    ///
599    /// Useful for animations and time-based logic. The tick starts at 0 and
600    /// increases by 1 on every rendered frame.
601    pub fn tick(&self) -> u64 {
602        self.tick
603    }
604
605    /// Return whether the layout debugger is enabled.
606    ///
607    /// The debugger is toggled with F12 at runtime.
608    pub fn debug_enabled(&self) -> bool {
609        self.debug
610    }
611
612    /// Return which layers the F12 debug overlay outlines (issue #201).
613    ///
614    /// Default is [`crate::DebugLayer::All`], which outlines the base tree
615    /// plus any active overlays/modals. See
616    /// [`set_debug_layer`](Self::set_debug_layer) to narrow the outline to
617    /// a specific layer.
618    ///
619    /// # Example
620    ///
621    /// ```no_run
622    /// use slt::{Context, DebugLayer};
623    ///
624    /// slt::run(|ui: &mut Context| {
625    ///     // Read the current layer to drive a UI badge or debug toolbar.
626    ///     match ui.debug_layer() {
627    ///         DebugLayer::All => ui.text("layer: all"),
628    ///         DebugLayer::TopMost => ui.text("layer: topmost"),
629    ///         DebugLayer::BaseOnly => ui.text("layer: base"),
630    ///     };
631    /// }).unwrap();
632    /// ```
633    pub fn debug_layer(&self) -> crate::DebugLayer {
634        self.debug_layer
635    }
636
637    /// Choose which layers the F12 debug overlay outlines (issue #201).
638    ///
639    /// Persists across frames. The default ([`crate::DebugLayer::All`])
640    /// matches the reporter's expectation that F12 reflects everything the
641    /// renderer is drawing. Use [`crate::DebugLayer::TopMost`] to focus on
642    /// the active modal / overlay only, or [`crate::DebugLayer::BaseOnly`]
643    /// to keep the legacy behavior of skipping overlays.
644    ///
645    /// # Runtime keybinding
646    ///
647    /// At runtime, **Shift+F12** cycles through `All` → `TopMost` →
648    /// `BaseOnly` → `All`. Plain F12 still toggles the overlay on/off.
649    /// The two keys are independent: enabling the overlay does not change
650    /// the active layer, and cycling layers does not enable the overlay.
651    ///
652    /// # Example
653    ///
654    /// ```no_run
655    /// use slt::{Context, DebugLayer};
656    ///
657    /// slt::run(|ui: &mut Context| {
658    ///     // Toggle between viewing only the base tree and viewing all
659    ///     // layers, e.g. from a custom debug menu.
660    ///     let next = match ui.debug_layer() {
661    ///         DebugLayer::All => DebugLayer::BaseOnly,
662    ///         DebugLayer::BaseOnly => DebugLayer::TopMost,
663    ///         DebugLayer::TopMost => DebugLayer::All,
664    ///     };
665    ///     ui.set_debug_layer(next);
666    /// }).unwrap();
667    /// ```
668    pub fn set_debug_layer(&mut self, layer: crate::DebugLayer) {
669        self.debug_layer = layer;
670    }
671
672    /// Return whether the devtools inspector panel is active (issue #268).
673    ///
674    /// The inspector is toggled with **Ctrl+F12** at runtime, or
675    /// programmatically via [`set_inspector`](Self::set_inspector). It is
676    /// independent of the F12 outline overlay and the Shift+F12 layer cycle.
677    /// When on, the inspector draws a resolved-style panel for the focused
678    /// widget and a focus-chain panel listing every focusable in order.
679    ///
680    /// Since 0.21.0.
681    ///
682    /// # Example
683    ///
684    /// ```no_run
685    /// use slt::Context;
686    ///
687    /// slt::run(|ui: &mut Context| {
688    ///     if ui.inspector() {
689    ///         ui.text("inspector on (Ctrl+F12 to hide)");
690    ///     }
691    /// })
692    /// .unwrap();
693    /// ```
694    pub fn inspector(&self) -> bool {
695        self.inspector_mode
696    }
697
698    /// Show or hide the devtools inspector panel (issue #268).
699    ///
700    /// Symmetric with [`set_debug_layer`](Self::set_debug_layer): the change
701    /// persists across frames. Enables (or disables) the focused-widget
702    /// resolved-style panel and the focus-chain inspector. Equivalent to the
703    /// runtime **Ctrl+F12** toggle; does not affect the F12 outline overlay.
704    ///
705    /// Since 0.21.0.
706    ///
707    /// # Example
708    ///
709    /// ```no_run
710    /// use slt::Context;
711    ///
712    /// slt::run(|ui: &mut Context| {
713    ///     // Open the inspector from a custom debug menu.
714    ///     ui.set_inspector(true);
715    /// })
716    /// .unwrap();
717    /// ```
718    pub fn set_inspector(&mut self, on: bool) {
719        self.inspector_mode = on;
720    }
721}