masonry/contexts.rs
1// Copyright 2020 the Xilem Authors and the Druid Authors
2// SPDX-License-Identifier: Apache-2.0
3
4//! The context types that are passed into various widget methods.
5
6use std::any::Any;
7use std::time::Duration;
8
9use accesskit::{NodeBuilder, TreeUpdate};
10use parley::FontContext;
11use tracing::{trace, warn};
12use winit::dpi::LogicalPosition;
13use winit::window::CursorIcon;
14
15use crate::action::Action;
16use crate::promise::PromiseToken;
17use crate::render_root::{RenderRootSignal, RenderRootState};
18use crate::text_helpers::{ImeChangeSignal, TextFieldRegistration};
19use crate::widget::{CursorChange, WidgetMut, WidgetState};
20use crate::{Insets, Point, Rect, Size, Widget, WidgetId, WidgetPod};
21
22/// A macro for implementing methods on multiple contexts.
23///
24/// There are a lot of methods defined on multiple contexts; this lets us only
25/// have to write them out once.
26macro_rules! impl_context_method {
27 ($ty:ty, { $($method:item)+ } ) => {
28 impl $ty { $($method)+ }
29 };
30 ( $ty:ty, $($more:ty),+, { $($method:item)+ } ) => {
31 impl_context_method!($ty, { $($method)+ });
32 impl_context_method!($($more),+, { $($method)+ });
33 };
34}
35
36/// A context provided inside of [`WidgetMut`].
37///
38/// When you declare a mutable reference type for your widget, methods of this type
39/// will have access to a `WidgetCtx`. If that method mutates the widget in a way that
40/// requires a later pass (for instance, if your widget has a `set_color` method),
41/// you will need to signal that change in the pass (eg `request_paint`).
42///
43// TODO add tutorial - See issue #5
44pub struct WidgetCtx<'a> {
45 pub(crate) global_state: &'a mut RenderRootState,
46 pub(crate) parent_widget_state: &'a mut WidgetState,
47 pub(crate) widget_state: &'a mut WidgetState,
48}
49
50/// A context provided to event handling methods of widgets.
51///
52/// Widgets should call [`request_paint`](Self::request_paint) whenever an event causes a change
53/// in the widget's appearance, to schedule a repaint.
54pub struct EventCtx<'a> {
55 pub(crate) global_state: &'a mut RenderRootState,
56 pub(crate) widget_state: &'a mut WidgetState,
57 pub(crate) is_handled: bool,
58 pub(crate) request_pan_to_child: Option<Rect>,
59}
60
61/// A context provided to the [`lifecycle`] method on widgets.
62///
63/// [`lifecycle`]: trait.Widget.html#tymethod.lifecycle
64pub struct LifeCycleCtx<'a> {
65 pub(crate) global_state: &'a mut RenderRootState,
66 pub(crate) widget_state: &'a mut WidgetState,
67}
68
69/// A context provided to layout handling methods of widgets.
70///
71/// As of now, the main service provided is access to a factory for
72/// creating text layout objects, which are likely to be useful
73/// during widget layout.
74pub struct LayoutCtx<'a> {
75 pub(crate) global_state: &'a mut RenderRootState,
76 pub(crate) widget_state: &'a mut WidgetState,
77 pub(crate) mouse_pos: Option<Point>,
78}
79
80/// A context passed to paint methods of widgets.
81pub struct PaintCtx<'a> {
82 pub(crate) global_state: &'a mut RenderRootState,
83 pub(crate) widget_state: &'a WidgetState,
84 /// The approximate depth in the tree at the time of painting.
85 pub(crate) depth: u32,
86 pub(crate) debug_paint: bool,
87 pub(crate) debug_widget: bool,
88}
89
90pub struct AccessCtx<'a> {
91 pub(crate) global_state: &'a mut RenderRootState,
92 pub(crate) widget_state: &'a WidgetState,
93 pub(crate) tree_update: &'a mut TreeUpdate,
94 pub(crate) current_node: NodeBuilder,
95 pub(crate) rebuild_all: bool,
96 pub(crate) scale_factor: f64,
97}
98
99pub struct WorkerCtx<'a> {
100 // TODO
101 #[allow(dead_code)]
102 pub(crate) global_state: &'a mut RenderRootState,
103}
104
105pub struct WorkerFn(pub Box<dyn FnOnce(WorkerCtx) + Send + 'static>);
106
107impl_context_method!(
108 WidgetCtx<'_>,
109 EventCtx<'_>,
110 LifeCycleCtx<'_>,
111 PaintCtx<'_>,
112 LayoutCtx<'_>,
113 AccessCtx<'_>,
114 {
115 /// get the `WidgetId` of the current widget.
116 pub fn widget_id(&self) -> WidgetId {
117 self.widget_state.id
118 }
119
120 /// Skip iterating over the given child.
121 ///
122 /// Normally, container widgets are supposed to iterate over each of their
123 /// child widgets in their methods. By default, the framework treats not
124 /// doing so as a mistake, and panics if debug assertions are on.
125 ///
126 /// This tells the framework that a child was deliberately skipped.
127 // TODO - see event flow tutorial - See issue #5
128 pub fn skip_child(&self, child: &mut WidgetPod<impl Widget>) {
129 child.mark_as_visited();
130 }
131 }
132);
133
134// methods on everyone but layoutctx
135impl_context_method!(
136 WidgetCtx<'_>,
137 EventCtx<'_>,
138 LifeCycleCtx<'_>,
139 PaintCtx<'_>,
140 {
141 /// The layout size.
142 ///
143 /// This is the layout size as ultimately determined by the parent
144 /// container, on the previous layout pass.
145 ///
146 /// Generally it will be the same as the size returned by the child widget's
147 /// [`layout`] method.
148 ///
149 /// [`layout`]: trait.Widget.html#tymethod.layout
150 pub fn size(&self) -> Size {
151 self.widget_state.size()
152 }
153
154 /// The origin of the widget in window coordinates, relative to the top left corner of the
155 /// content area.
156 pub fn window_origin(&self) -> Point {
157 self.widget_state.window_origin()
158 }
159
160 /// Convert a point from the widget's coordinate space to the window's.
161 ///
162 /// The returned point is relative to the content area; it excludes window chrome.
163 pub fn to_window(&self, widget_point: Point) -> Point {
164 self.window_origin() + widget_point.to_vec2()
165 }
166
167 /// The "hot" (aka hover) status of a widget.
168 ///
169 /// A widget is "hot" when the mouse is hovered over it. Widgets will
170 /// often change their appearance as a visual indication that they
171 /// will respond to mouse interaction.
172 ///
173 /// The hot status is computed from the widget's layout rect. In a
174 /// container hierarchy, all widgets with layout rects containing the
175 /// mouse position have hot status.
176 ///
177 /// Discussion: there is currently some confusion about whether a
178 /// widget can be considered hot when some other widget is active (for
179 /// example, when clicking to one widget and dragging to the next).
180 /// The documentation should clearly state the resolution.
181 pub fn is_hot(&self) -> bool {
182 self.widget_state.is_hot
183 }
184
185 /// The active status of a widget.
186 ///
187 /// Active status generally corresponds to a mouse button down. Widgets
188 /// with behavior similar to a button will call [`set_active`](EventCtx::set_active) on mouse
189 /// down and then up.
190 ///
191 /// When a widget is active, it gets mouse events even when the mouse
192 /// is dragged away.
193 pub fn is_active(&self) -> bool {
194 self.widget_state.is_active
195 }
196
197 /// The focus status of a widget.
198 ///
199 /// Returns `true` if this specific widget is focused.
200 /// To check if any descendants are focused use [`has_focus`].
201 ///
202 /// Focus means that the widget receives keyboard events.
203 ///
204 /// A widget can request focus using the [`request_focus`] method.
205 /// It's also possible to register for automatic focus via [`register_for_focus`].
206 ///
207 /// If a widget gains or loses focus it will get a [`LifeCycle::FocusChanged`] event.
208 ///
209 /// Only one widget at a time is focused. However due to the way events are routed,
210 /// all ancestors of that widget will also receive keyboard events.
211 ///
212 /// [`request_focus`]: struct.EventCtx.html#method.request_focus
213 /// [`register_for_focus`]: struct.LifeCycleCtx.html#method.register_for_focus
214 /// [`LifeCycle::FocusChanged`]: enum.LifeCycle.html#variant.FocusChanged
215 /// [`has_focus`]: #method.has_focus
216 pub fn is_focused(&self) -> bool {
217 self.global_state.focused_widget == Some(self.widget_id())
218 }
219
220 /// The (tree) focus status of a widget.
221 ///
222 /// Returns `true` if either this specific widget or any one of its descendants is focused.
223 /// To check if only this specific widget is focused use [`is_focused`](Self::is_focused).
224 pub fn has_focus(&self) -> bool {
225 self.widget_state.has_focus
226 }
227
228 /// The disabled state of a widget.
229 ///
230 /// Returns `true` if this widget or any of its ancestors is explicitly disabled.
231 /// To make this widget explicitly disabled use [`set_disabled`].
232 ///
233 /// Disabled means that this widget should not change the state of the application. What
234 /// that means is not entirely clear but in any it should not change its data. Therefore
235 /// others can use this as a safety mechanism to prevent the application from entering an
236 /// illegal state.
237 /// For an example the decrease button of a counter of type `usize` should be disabled if the
238 /// value is `0`.
239 ///
240 /// [`set_disabled`]: EventCtx::set_disabled
241 pub fn is_disabled(&self) -> bool {
242 self.widget_state.is_disabled()
243 }
244
245 /// Check is widget is stashed.
246 ///
247 /// **Note:** Stashed widgets are a WIP feature
248 // FIXME - take stashed parents into account
249 pub fn is_stashed(&self) -> bool {
250 self.widget_state.is_stashed
251 }
252 }
253);
254
255impl_context_method!(EventCtx<'_>, {
256 /// Set the cursor icon.
257 ///
258 /// This setting will be retained until [`clear_cursor`] is called, but it will only take
259 /// effect when this widget is either [`hot`] or [`active`]. If a child widget also sets a
260 /// cursor, the child widget's cursor will take precedence. (If that isn't what you want, use
261 /// [`override_cursor`] instead.)
262 ///
263 /// [`clear_cursor`]: EventCtx::clear_cursor
264 /// [`override_cursor`]: EventCtx::override_cursor
265 /// [`hot`]: EventCtx::is_hot
266 /// [`active`]: EventCtx::is_active
267 pub fn set_cursor(&mut self, cursor: &CursorIcon) {
268 trace!("set_cursor {:?}", cursor);
269 self.widget_state.cursor_change = CursorChange::Set(*cursor);
270 }
271
272 /// Override the cursor icon.
273 ///
274 /// This setting will be retained until [`clear_cursor`] is called, but it will only take
275 /// effect when this widget is either [`hot`] or [`active`]. This will override the cursor
276 /// preferences of a child widget. (If that isn't what you want, use [`set_cursor`] instead.)
277 ///
278 /// [`clear_cursor`]: EventCtx::clear_cursor
279 /// [`set_cursor`]: EventCtx::override_cursor
280 /// [`hot`]: EventCtx::is_hot
281 /// [`active`]: EventCtx::is_active
282 pub fn override_cursor(&mut self, cursor: &CursorIcon) {
283 trace!("override_cursor {:?}", cursor);
284 self.widget_state.cursor_change = CursorChange::Override(*cursor);
285 }
286
287 /// Clear the cursor icon.
288 ///
289 /// This undoes the effect of [`set_cursor`] and [`override_cursor`].
290 ///
291 /// [`override_cursor`]: EventCtx::override_cursor
292 /// [`set_cursor`]: EventCtx::set_cursor
293 pub fn clear_cursor(&mut self) {
294 trace!("clear_cursor");
295 self.widget_state.cursor_change = CursorChange::Default;
296 }
297});
298
299impl<'a> WidgetCtx<'a> {
300 // FIXME - Assert that child's parent is self
301 /// Return a [`WidgetMut`] to a child widget.
302 pub fn get_mut<'c, Child: Widget>(
303 &'c mut self,
304 child: &'c mut WidgetPod<Child>,
305 ) -> WidgetMut<'c, Child> {
306 let child_ctx = WidgetCtx {
307 global_state: self.global_state,
308 parent_widget_state: self.widget_state,
309 widget_state: &mut child.state,
310 };
311 WidgetMut {
312 ctx: child_ctx,
313 widget: &mut child.inner,
314 }
315 }
316}
317
318impl<'a> EventCtx<'a> {
319 /// Return a [`WidgetMut`] to a child widget.
320 // FIXME - Assert that child's parent is self
321 pub fn get_mut<'c, Child: Widget>(
322 &'c mut self,
323 child: &'c mut WidgetPod<Child>,
324 ) -> WidgetMut<'c, Child> {
325 let child_ctx = WidgetCtx {
326 global_state: self.global_state,
327 parent_widget_state: self.widget_state,
328 widget_state: &mut child.state,
329 };
330 WidgetMut {
331 ctx: child_ctx,
332 widget: &mut child.inner,
333 }
334 }
335}
336
337impl<'a> LifeCycleCtx<'a> {
338 /// Return a [`WidgetMut`] to a child widget.
339 // FIXME - Assert that child's parent is self
340 pub fn get_mut<'c, Child: Widget>(
341 &'c mut self,
342 child: &'c mut WidgetPod<Child>,
343 ) -> WidgetMut<'c, Child> {
344 let child_ctx = WidgetCtx {
345 global_state: self.global_state,
346 parent_widget_state: self.widget_state,
347 widget_state: &mut child.state,
348 };
349 WidgetMut {
350 ctx: child_ctx,
351 widget: &mut child.inner,
352 }
353 }
354}
355
356// methods on event and lifecycle
357impl_context_method!(WidgetCtx<'_>, EventCtx<'_>, LifeCycleCtx<'_>, {
358 /// Request a [`paint`](crate::Widget::paint) pass.
359 pub fn request_paint(&mut self) {
360 trace!("request_paint");
361 self.widget_state.needs_paint = true;
362 }
363
364 /// Request a layout pass.
365 ///
366 /// A Widget's [`layout`] method is always called when the widget tree
367 /// changes, or the window is resized.
368 ///
369 /// If your widget would like to have layout called at any other time,
370 /// (such as if it would like to change the layout of children in
371 /// response to some event) it must call this method.
372 ///
373 /// [`layout`]: crate::Widget::layout
374 pub fn request_layout(&mut self) {
375 trace!("request_layout");
376 self.widget_state.needs_layout = true;
377 }
378
379 pub fn request_accessibility_update(&mut self) {
380 trace!("request_accessibility_update");
381 self.widget_state.needs_accessibility_update = true;
382 self.widget_state.request_accessibility_update = true;
383 }
384
385 /// Request an animation frame.
386 pub fn request_anim_frame(&mut self) {
387 trace!("request_anim_frame");
388 self.widget_state.request_anim = true;
389 }
390
391 /// Indicate that your children have changed.
392 ///
393 /// Widgets must call this method after adding a new child or removing a child.
394 pub fn children_changed(&mut self) {
395 trace!("children_changed");
396 self.widget_state.children_changed = true;
397 self.widget_state.update_focus_chain = true;
398 self.request_layout();
399 }
400
401 /// Set the disabled state for this widget.
402 ///
403 /// Setting this to `false` does not mean a widget is not still disabled; for instance it may
404 /// still be disabled by an ancestor. See [`is_disabled`] for more information.
405 ///
406 /// Calling this method during [`LifeCycle::DisabledChanged`] has no effect.
407 ///
408 /// [`LifeCycle::DisabledChanged`]: struct.LifeCycle.html#variant.DisabledChanged
409 /// [`is_disabled`]: EventCtx::is_disabled
410 pub fn set_disabled(&mut self, disabled: bool) {
411 // widget_state.children_disabled_changed is not set because we want to be able to delete
412 // changes that happened during DisabledChanged.
413 self.widget_state.is_explicitly_disabled_new = disabled;
414 }
415
416 /// Mark child widget as stashed.
417 ///
418 /// **Note:** Stashed widgets are a WIP feature
419 pub fn set_stashed(&mut self, child: &mut WidgetPod<impl Widget>, stashed: bool) {
420 child.state.is_stashed = stashed;
421 self.children_changed();
422 }
423
424 #[allow(unused)]
425 /// Indicate that text input state has changed.
426 ///
427 /// A widget that accepts text input should call this anytime input state
428 /// (such as the text or the selection) changes as a result of a non text-input
429 /// event.
430 pub fn invalidate_text_input(&mut self, event: ImeChangeSignal) {
431 todo!("invalidate_text_input");
432 }
433});
434
435// methods on everyone but paintctx
436impl_context_method!(
437 WidgetCtx<'_>,
438 EventCtx<'_>,
439 LifeCycleCtx<'_>,
440 LayoutCtx<'_>,
441 {
442 /// Submit an [`Action`].
443 ///
444 /// Note: Actions are still a WIP feature.
445 pub fn submit_action(&mut self, action: Action) {
446 trace!("submit_action");
447 self.global_state
448 .signal_queue
449 .push_back(RenderRootSignal::Action(action, self.widget_state.id));
450 }
451
452 /// Run the provided function in the background.
453 ///
454 /// The function takes a [`WorkerCtx`] which it can use to
455 /// communicate with the main thread.
456 pub fn run_in_background(
457 &mut self,
458 _background_task: impl FnOnce(WorkerCtx) + Send + 'static,
459 ) {
460 // TODO - Use RenderRootSignal::SpawnWorker
461 todo!("run_in_background");
462 }
463
464 /// Run the provided function in the background, and send its result once it's done.
465 ///
466 /// The function takes a [`WorkerCtx`] which it can use to
467 /// communicate with the main thread.
468 ///
469 /// Once the function returns, an [`Event::PromiseResult`](crate::Event::PromiseResult)
470 /// is emitted with the return value.
471 pub fn compute_in_background<T: Any + Send>(
472 &mut self,
473 _background_task: impl FnOnce(WorkerCtx) -> T + Send + 'static,
474 ) -> PromiseToken<T> {
475 // TODO - Use RenderRootSignal::SpawnWorker
476 todo!("compute_in_background");
477 }
478
479 /// Request a timer event.
480 ///
481 /// The return value is a token, which can be used to associate the
482 /// request with the event.
483 pub fn request_timer(&mut self, _deadline: Duration) -> TimerToken {
484 todo!("request_timer");
485 }
486 }
487);
488
489// FIXME - Remove
490pub struct TimerToken;
491
492impl EventCtx<'_> {
493 /// Send a signal to parent widgets to scroll this widget into view.
494 pub fn request_pan_to_this(&mut self) {
495 self.request_pan_to_child = Some(self.widget_state.layout_rect());
496 }
497
498 /// Set the "active" state of the widget.
499 ///
500 /// See [`EventCtx::is_active`](Self::is_active).
501 pub fn set_active(&mut self, active: bool) {
502 trace!("set_active({})", active);
503 self.widget_state.is_active = active;
504 // TODO: plumb mouse grab through to platform (through druid-shell)
505 }
506
507 /// Set the event as "handled", which stops its propagation to other
508 /// widgets.
509 pub fn set_handled(&mut self) {
510 trace!("set_handled");
511 self.is_handled = true;
512 }
513
514 /// Determine whether the event has been handled by some other widget.
515 pub fn is_handled(&self) -> bool {
516 self.is_handled
517 }
518
519 /// Request keyboard focus.
520 ///
521 /// Because only one widget can be focused at a time, multiple focus requests
522 /// from different widgets during a single event cycle means that the last
523 /// widget that requests focus will override the previous requests.
524 ///
525 /// See [`is_focused`](Self::is_focused) for more information about focus.
526 pub fn request_focus(&mut self) {
527 trace!("request_focus");
528 // We need to send the request even if we're currently focused,
529 // because we may have a sibling widget that already requested focus
530 // and we have no way of knowing that yet. We need to override that
531 // to deliver on the "last focus request wins" promise.
532 let id = self.widget_id();
533 self.global_state.next_focused_widget = Some(id);
534 }
535
536 /// Transfer focus to the widget with the given `WidgetId`.
537 ///
538 /// See [`is_focused`](Self::is_focused) for more information about focus.
539 pub fn set_focus(&mut self, target: WidgetId) {
540 trace!("set_focus target={:?}", target);
541 self.global_state.next_focused_widget = Some(target);
542 }
543
544 /// Give up focus.
545 ///
546 /// This should only be called by a widget that currently has focus.
547 ///
548 /// See [`is_focused`](Self::is_focused) for more information about focus.
549 pub fn resign_focus(&mut self) {
550 trace!("resign_focus");
551 if self.has_focus() {
552 self.global_state.next_focused_widget = None;
553 } else {
554 warn!(
555 "resign_focus can only be called by the currently focused widget \
556 or one of its ancestors. ({:?})",
557 self.widget_id()
558 );
559 }
560 }
561}
562
563impl LifeCycleCtx<'_> {
564 /// Registers a child widget.
565 ///
566 /// This should only be called in response to a `LifeCycle::WidgetAdded` event.
567 ///
568 /// In general, you should not need to call this method; it is handled by
569 /// the `WidgetPod`.
570 // TODO - See issue #9
571 pub(crate) fn register_child(&mut self, child_id: WidgetId) {
572 trace!("register_child id={:?}", child_id);
573 self.widget_state.children.add(&child_id);
574 }
575
576 /// Register this widget to be eligile to accept focus automatically.
577 ///
578 /// This should only be called in response to a [`LifeCycle::BuildFocusChain`] event.
579 ///
580 /// See [`EventCtx::is_focused`](Self::is_focused) for more information about focus.
581 ///
582 /// [`LifeCycle::BuildFocusChain`]: enum.Lifecycle.html#variant.BuildFocusChain
583 pub fn register_for_focus(&mut self) {
584 trace!("register_for_focus");
585 self.widget_state.focus_chain.push(self.widget_id());
586 }
587
588 /// Register this widget as accepting text input.
589 pub fn register_as_text_input(&mut self) {
590 let registration = TextFieldRegistration {
591 widget_id: self.widget_id(),
592 };
593 self.widget_state.text_registrations.push(registration);
594 }
595
596 // TODO - remove - See issue #15
597 /// Register this widget as a portal.
598 ///
599 /// This should only be used by scroll areas.
600 pub fn register_as_portal(&mut self) {
601 self.widget_state.is_portal = true;
602 }
603}
604
605impl LayoutCtx<'_> {
606 /// Set explicit paint [`Insets`] for this widget.
607 ///
608 /// You are not required to set explicit paint bounds unless you need
609 /// to paint outside of your layout bounds. In this case, the argument
610 /// should be an [`Insets`] struct that indicates where your widget
611 /// needs to overpaint, relative to its bounds.
612 ///
613 /// For more information, see [`WidgetPod::paint_insets`].
614 ///
615 /// [`Insets`]: struct.Insets.html
616 /// [`WidgetPod::paint_insets`]: struct.WidgetPod.html#method.paint_insets
617 pub fn set_paint_insets(&mut self, insets: impl Into<Insets>) {
618 let insets = insets.into();
619 trace!("set_paint_insets {:?}", insets);
620 self.widget_state.paint_insets = insets.nonnegative();
621 }
622
623 /// Set an explicit baseline position for this widget.
624 ///
625 /// The baseline position is used to align widgets that contain text,
626 /// such as buttons, labels, and other controls. It may also be used
627 /// by other widgets that are opinionated about how they are aligned
628 /// relative to neighbouring text, such as switches or checkboxes.
629 ///
630 /// The provided value should be the distance from the *bottom* of the
631 /// widget to the baseline.
632 pub fn set_baseline_offset(&mut self, baseline: f64) {
633 trace!("set_baseline_offset {}", baseline);
634 self.widget_state.baseline_offset = baseline;
635 }
636
637 /// Set the position of a child widget, in the paren't coordinate space. This
638 /// will also implicitly change "hot" status and affect the parent's display rect.
639 ///
640 /// Container widgets must call this method with each non-stashed child in their
641 /// layout method, after calling `child.layout(...)`.
642 pub fn place_child(&mut self, child: &mut WidgetPod<impl Widget>, origin: Point) {
643 if origin != child.state.origin {
644 child.state.origin = origin;
645 child.state.needs_window_origin = true;
646 }
647 child.state.is_expecting_place_child_call = false;
648
649 self.widget_state.local_paint_rect =
650 self.widget_state.local_paint_rect.union(child.paint_rect());
651
652 let mouse_pos = self.mouse_pos.map(|pos| LogicalPosition::new(pos.x, pos.y));
653 // if the widget has moved, it may have moved under the mouse, in which
654 // case we need to handle that.
655 if WidgetPod::update_hot_state(
656 &mut child.inner,
657 &mut child.state,
658 self.global_state,
659 mouse_pos,
660 ) {
661 self.widget_state.merge_up(&mut child.state);
662 }
663 }
664}
665
666impl_context_method!(LayoutCtx<'_>, PaintCtx<'_>, {
667 pub fn font_ctx(&mut self) -> &mut FontContext {
668 &mut self.global_state.font_context
669 }
670});
671
672impl PaintCtx<'_> {
673 /// The depth in the tree of the currently painting widget.
674 ///
675 /// This may be used in combination with [`paint_with_z_index`](Self::paint_with_z_index) in order
676 /// to correctly order painting operations.
677 ///
678 /// The `depth` here may not be exact; it is only guaranteed that a child will
679 /// have a greater depth than its parent.
680 #[inline]
681 pub fn depth(&self) -> u32 {
682 self.depth
683 }
684}
685
686impl AccessCtx<'_> {
687 pub fn current_node(&mut self) -> &mut NodeBuilder {
688 &mut self.current_node
689 }
690
691 /// Report whether accessibility was requested on this widget.
692 ///
693 /// This method is primarily intended for containers. The `accessibility`
694 /// method will be called on a widget when it or any of its descendants
695 /// have seen a request. However, in many cases a container need not push
696 /// a node for itself.
697 pub fn is_requested(&self) -> bool {
698 self.widget_state.needs_accessibility_update
699 }
700}