druid/contexts.rs
1// Copyright 2020 The Druid Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The context types that are passed into various widget methods.
16
17use std::{
18 any::{Any, TypeId},
19 collections::{HashMap, VecDeque},
20 ops::{Deref, DerefMut},
21 rc::Rc,
22 time::Duration,
23};
24use tracing::{error, trace, warn};
25
26use crate::commands::SCROLL_TO_VIEW;
27use crate::core::{CommandQueue, CursorChange, FocusChange, WidgetState};
28use crate::env::KeyLike;
29use crate::menu::ContextMenu;
30use crate::piet::{Piet, PietText, RenderContext};
31use crate::shell::text::Event as ImeInvalidation;
32use crate::shell::Region;
33use crate::text::{ImeHandlerRef, TextFieldRegistration};
34use crate::{
35 commands, sub_window::SubWindowDesc, widget::Widget, Affine, Command, Cursor, Data, Env,
36 ExtEventSink, Insets, Menu, Notification, Point, Rect, Scale, SingleUse, Size, Target,
37 TimerToken, Vec2, WidgetId, WindowConfig, WindowDesc, WindowHandle, WindowId,
38};
39
40/// A macro for implementing methods on multiple contexts.
41///
42/// There are a lot of methods defined on multiple contexts; this lets us only
43/// have to write them out once.
44macro_rules! impl_context_method {
45 ($ty:ty, { $($method:item)+ } ) => {
46 impl $ty { $($method)+ }
47 };
48 ( $ty:ty, $($more:ty),+, { $($method:item)+ } ) => {
49 impl_context_method!($ty, { $($method)+ });
50 impl_context_method!($($more),+, { $($method)+ });
51 };
52}
53
54/// A macro for implementing context traits for multiple contexts.
55macro_rules! impl_context_trait {
56 ($tr:ty => $ty:ty, { $($method:item)+ } ) => {
57 impl $tr for $ty { $($method)+ }
58 };
59 ($tr:ty => $ty:ty, $($more:ty),+, { $($method:item)+ } ) => {
60 impl_context_trait!($tr => $ty, { $($method)+ });
61 impl_context_trait!($tr => $($more),+, { $($method)+ });
62 };
63}
64
65/// Static state that is shared between most contexts.
66pub(crate) struct ContextState<'a> {
67 pub(crate) command_queue: &'a mut CommandQueue,
68 pub(crate) ext_handle: &'a ExtEventSink,
69 pub(crate) window_id: WindowId,
70 pub(crate) window: &'a WindowHandle,
71 pub(crate) text: PietText,
72 /// The id of the widget that currently has focus.
73 pub(crate) focus_widget: Option<WidgetId>,
74 pub(crate) root_app_data_type: TypeId,
75 pub(crate) timers: &'a mut HashMap<TimerToken, WidgetId>,
76 pub(crate) text_registrations: &'a mut Vec<TextFieldRegistration>,
77}
78
79/// A mutable context provided to event handling methods of widgets.
80///
81/// Widgets should call [`request_paint`] whenever an event causes a change
82/// in the widget's appearance, to schedule a repaint.
83///
84/// [`request_paint`]: #method.request_paint
85pub struct EventCtx<'a, 'b> {
86 pub(crate) state: &'a mut ContextState<'b>,
87 pub(crate) widget_state: &'a mut WidgetState,
88 pub(crate) notifications: &'a mut VecDeque<Notification>,
89 pub(crate) is_handled: bool,
90 pub(crate) is_root: bool,
91}
92
93/// A mutable context provided to the [`lifecycle`] method on widgets.
94///
95/// Certain methods on this context are only meaningful during the handling of
96/// specific lifecycle events; for instance [`register_child`]
97/// should only be called while handling [`LifeCycle::WidgetAdded`].
98///
99/// [`lifecycle`]: Widget::lifecycle
100/// [`register_child`]: #method.register_child
101/// [`LifeCycle::WidgetAdded`]: crate::LifeCycle::WidgetAdded
102pub struct LifeCycleCtx<'a, 'b> {
103 pub(crate) state: &'a mut ContextState<'b>,
104 pub(crate) widget_state: &'a mut WidgetState,
105}
106
107/// A mutable context provided to data update methods of widgets.
108///
109/// Widgets should call [`request_paint`] whenever a data change causes a change
110/// in the widget's appearance, to schedule a repaint.
111///
112/// [`request_paint`]: #method.request_paint
113pub struct UpdateCtx<'a, 'b> {
114 pub(crate) state: &'a mut ContextState<'b>,
115 pub(crate) widget_state: &'a mut WidgetState,
116 pub(crate) prev_env: Option<&'a Env>,
117 pub(crate) env: &'a Env,
118}
119
120/// A context provided to layout-handling methods of widgets.
121///
122/// As of now, the main service provided is access to a factory for
123/// creating text layout objects, which are likely to be useful
124/// during widget layout.
125pub struct LayoutCtx<'a, 'b> {
126 pub(crate) state: &'a mut ContextState<'b>,
127 pub(crate) widget_state: &'a mut WidgetState,
128}
129
130/// Z-order paint operations with transformations.
131pub(crate) struct ZOrderPaintOp {
132 pub z_index: u32,
133 pub paint_func: Box<dyn FnOnce(&mut PaintCtx) + 'static>,
134 pub transform: Affine,
135}
136
137/// A context passed to paint methods of widgets.
138///
139/// In addition to the API below, [`PaintCtx`] derefs to an implementation of
140/// the [`RenderContext`] trait, which defines the basic available drawing
141/// commands.
142pub struct PaintCtx<'a, 'b, 'c> {
143 pub(crate) state: &'a mut ContextState<'b>,
144 pub(crate) widget_state: &'a WidgetState,
145 /// The render context for actually painting.
146 pub render_ctx: &'a mut Piet<'c>,
147 /// The z-order paint operations.
148 pub(crate) z_ops: Vec<ZOrderPaintOp>,
149 /// The currently visible region.
150 pub(crate) region: Region,
151 /// The approximate depth in the tree at the time of painting.
152 pub(crate) depth: u32,
153}
154
155/// The state of a widget and its global context.
156pub struct State<'a> {
157 // currently the only method using the State struct is set_origin.
158 // the context state could be included into this struct to allow changes to context state
159 // changes from Context traits
160 // pub(crate) state: &'a mut ContextState<'b>,
161 pub(crate) widget_state: &'a mut WidgetState,
162}
163
164/// Convenience trait for code generic over contexts.
165///
166/// Methods that deal with commands and timers.
167/// Available to all contexts but [`PaintCtx`].
168pub trait ChangeCtx {
169 /// Submit a [`Command`] to be run after this event is handled. See [`submit_command`].
170 ///
171 /// [`submit_command`]: EventCtx::submit_command
172 fn submit_command(&mut self, cmd: impl Into<Command>);
173 /// Returns an [`ExtEventSink`] for submitting commands from other threads. See ['get_external_handle'].
174 ///
175 /// [`get_external_handle`]: EventCtx::get_external_handle
176 fn get_external_handle(&self) -> ExtEventSink;
177 /// Request a timer event. See [`request_timer`]
178 ///
179 /// [`request_timer`]: EventCtx::request_timer
180 fn request_timer(&mut self, deadline: Duration) -> TimerToken;
181
182 /// Returns the state of the widget.
183 ///
184 /// This method should only be used by the framework to do mergeups.
185 fn state(&mut self) -> State;
186}
187
188/// Convenience trait for invalidation and request methods available on multiple contexts.
189///
190/// These methods are available on [`EventCtx`], [`LifeCycleCtx`], and [`UpdateCtx`].
191pub trait RequestCtx: ChangeCtx {
192 /// Request a [`paint`] pass. See ['request_paint']
193 ///
194 /// ['request_paint']: EventCtx::request_paint
195 /// [`paint`]: Widget::paint
196 fn request_paint(&mut self);
197 /// Request a [`paint`] pass for redrawing a rectangle. See [`request_paint_rect`].
198 ///
199 /// [`request_paint_rect`]: EventCtx::request_paint_rect
200 /// [`paint`]: Widget::paint
201 fn request_paint_rect(&mut self, rect: Rect);
202 /// Request a layout pass. See [`request_layout`].
203 ///
204 /// [`request_layout`]: EventCtx::request_layout
205 fn request_layout(&mut self);
206 /// Request an animation frame. See [`request_anim_frame`].
207 ///
208 /// [`request_anim_frame`]: EventCtx::request_anim_frame
209 fn request_anim_frame(&mut self);
210 /// Indicate that your children have changed. See [`children_changed`].
211 ///
212 /// [`children_changed`]: EventCtx::children_changed
213 fn children_changed(&mut self);
214 /// Create a new sub-window. See [`new_sub_window`].
215 ///
216 /// [`new_sub_window`]: EventCtx::new_sub_window
217 fn new_sub_window<W: Widget<U> + 'static, U: Data>(
218 &mut self,
219 window_config: WindowConfig,
220 widget: W,
221 data: U,
222 env: Env,
223 ) -> WindowId;
224 /// Change the disabled state of this widget. See [`set_disabled`].
225 ///
226 /// [`set_disabled`]: EventCtx::set_disabled
227 fn set_disabled(&mut self, disabled: bool);
228 /// Indicate that text input state has changed. See [`invalidate_text_input`].
229 ///
230 /// [`invalidate_text_input`]: EventCtx::invalidate_text_input
231 fn invalidate_text_input(&mut self, event: ImeInvalidation);
232 /// Scrolls this widget into view.
233 ///
234 /// [`scroll_to_view`]: EventCtx::scroll_to_view
235 fn scroll_to_view(&mut self);
236 /// Scrolls the area into view. See [`scroll_area_to_view`].
237 ///
238 /// [`scroll_area_to_view`]: EventCtx::scroll_area_to_view
239 fn scroll_area_to_view(&mut self, area: Rect);
240}
241
242impl_context_trait!(
243 ChangeCtx => EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>, LayoutCtx<'_, '_>,
244 {
245
246 fn submit_command(&mut self, cmd: impl Into<Command>) {
247 Self::submit_command(self, cmd)
248 }
249
250 fn get_external_handle(&self) -> ExtEventSink {
251 Self::get_external_handle(self)
252 }
253
254 fn request_timer(&mut self, deadline: Duration) -> TimerToken {
255 Self::request_timer(self, deadline)
256 }
257
258 fn state(&mut self) -> State {
259 State {
260 //state: &mut *self.state,
261 widget_state: &mut *self.widget_state,
262 }
263 }
264 }
265);
266
267impl_context_trait!(
268 RequestCtx => EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>,
269 {
270 fn request_paint(&mut self) {
271 Self::request_paint(self)
272 }
273
274 fn request_paint_rect(&mut self, rect: Rect) {
275 Self::request_paint_rect(self, rect)
276 }
277
278 fn request_layout(&mut self) {
279 Self::request_layout(self)
280 }
281
282 fn request_anim_frame(&mut self) {
283 Self::request_anim_frame(self)
284 }
285
286 fn children_changed(&mut self) {
287 Self::children_changed(self)
288 }
289
290 fn new_sub_window<W: Widget<U> + 'static, U: Data>(
291 &mut self,
292 window_config: WindowConfig,
293 widget: W,
294 data: U,
295 env: Env,
296 ) -> WindowId {
297 Self::new_sub_window(self, window_config, widget, data, env)
298 }
299
300 fn set_disabled(&mut self, disabled: bool) {
301 Self::set_disabled(self, disabled)
302 }
303
304 fn invalidate_text_input(&mut self, event: ImeInvalidation) {
305 Self::invalidate_text_input(self, event)
306 }
307
308 fn scroll_to_view(&mut self) {
309 Self::scroll_to_view(self)
310 }
311
312 fn scroll_area_to_view(&mut self, area: Rect) {
313 Self::scroll_area_to_view(self, area)
314 }
315 }
316);
317
318// methods on everyone
319impl_context_method!(
320 EventCtx<'_, '_>,
321 UpdateCtx<'_, '_>,
322 LifeCycleCtx<'_, '_>,
323 PaintCtx<'_, '_, '_>,
324 LayoutCtx<'_, '_>,
325 {
326 /// get the `WidgetId` of the current widget.
327 pub fn widget_id(&self) -> WidgetId {
328 self.widget_state.id
329 }
330
331 /// Returns a reference to the current `WindowHandle`.
332 pub fn window(&self) -> &WindowHandle {
333 self.state.window
334 }
335
336 /// Get the `WindowId` of the current window.
337 pub fn window_id(&self) -> WindowId {
338 self.state.window_id
339 }
340
341 /// Get an object which can create text layouts.
342 pub fn text(&mut self) -> &mut PietText {
343 &mut self.state.text
344 }
345
346 /// The current window's [`Scale`].
347 ///
348 /// The returned [`Scale`] is a copy and thus its information will be stale after
349 /// the platform changes the window's scale. This means you can only rely on it
350 /// until the next [`Event::WindowScale`] event happens.
351 ///
352 /// [`Scale`]: crate::Scale
353 /// [`Event::WindowScale`]: crate::Event::WindowScale
354 pub fn scale(&self) -> Scale {
355 self.state.window.get_scale().unwrap_or_default()
356 }
357 }
358);
359
360// methods on everyone but layoutctx
361impl_context_method!(
362 EventCtx<'_, '_>,
363 UpdateCtx<'_, '_>,
364 LifeCycleCtx<'_, '_>,
365 PaintCtx<'_, '_, '_>,
366 {
367 /// The layout size.
368 ///
369 /// This is the layout size as ultimately determined by the parent
370 /// container, on the previous layout pass.
371 ///
372 /// Generally it will be the same as the size returned by the child widget's
373 /// [`layout`] method.
374 ///
375 /// [`layout`]: Widget::layout
376 pub fn size(&self) -> Size {
377 self.widget_state.size()
378 }
379
380 /// The origin of the widget in window coordinates, relative to the top left corner of the
381 /// content area.
382 pub fn window_origin(&self) -> Point {
383 self.widget_state.window_origin()
384 }
385
386 /// Convert a point from the widget's coordinate space to the window's.
387 ///
388 /// The returned point is relative to the content area; it excludes window chrome.
389 pub fn to_window(&self, widget_point: Point) -> Point {
390 self.window_origin() + widget_point.to_vec2()
391 }
392
393 /// Convert a point from the widget's coordinate space to the screen's.
394 /// See the [`Screen`] module
395 ///
396 /// [`Screen`]: crate::shell::Screen
397 pub fn to_screen(&self, widget_point: Point) -> Point {
398 let insets = self.window().content_insets();
399 let content_origin = self.window().get_position() + Vec2::new(insets.x0, insets.y0);
400 content_origin + self.to_window(widget_point).to_vec2()
401 }
402
403 /// Query the "hot" state of the widget.
404 ///
405 /// See [`WidgetPod::is_hot`] for additional information.
406 ///
407 /// [`WidgetPod::is_hot`]: crate::WidgetPod::is_hot
408 pub fn is_hot(&self) -> bool {
409 self.widget_state.is_hot
410 }
411
412 /// Query the "active" state of the widget.
413 ///
414 /// See [`WidgetPod::is_active`] for additional information.
415 ///
416 /// [`WidgetPod::is_active`]: crate::WidgetPod::is_active
417 pub fn is_active(&self) -> bool {
418 self.widget_state.is_active
419 }
420
421 /// The focus status of a widget.
422 ///
423 /// Returns `true` if this specific widget is focused.
424 /// To check if any descendants are focused use [`has_focus`].
425 ///
426 /// Focus means that the widget receives keyboard events.
427 ///
428 /// A widget can request focus using the [`request_focus`] method.
429 /// It's also possible to register for automatic focus via [`register_for_focus`].
430 ///
431 /// If a widget gains or loses focus it will get a [`LifeCycle::FocusChanged`] event.
432 ///
433 /// Only one widget at a time is focused. However due to the way events are routed,
434 /// all ancestors of that widget will also receive keyboard events.
435 ///
436 /// [`request_focus`]: EventCtx::request_focus
437 /// [`register_for_focus`]: LifeCycleCtx::register_for_focus
438 /// [`LifeCycle::FocusChanged`]: crate::LifeCycle::FocusChanged
439 /// [`has_focus`]: #method.has_focus
440 pub fn is_focused(&self) -> bool {
441 self.state.focus_widget == Some(self.widget_id())
442 }
443
444 /// The (tree) focus status of a widget.
445 ///
446 /// Returns `true` if either this specific widget or any one of its descendants is focused.
447 /// To check if only this specific widget is focused use [`is_focused`],
448 ///
449 /// [`is_focused`]: crate::EventCtx::is_focused
450 pub fn has_focus(&self) -> bool {
451 self.widget_state.has_focus
452 }
453
454 /// The disabled state of a widget.
455 ///
456 /// Returns `true` if this widget or any of its ancestors is explicitly disabled.
457 /// To make this widget explicitly disabled use [`set_disabled`].
458 ///
459 /// Disabled means that this widget should not change the state of the application. What
460 /// that means is not entirely clear but in any it should not change its data. Therefore
461 /// others can use this as a safety mechanism to prevent the application from entering an
462 /// illegal state.
463 /// For an example the decrease button of a counter of type `usize` should be disabled if the
464 /// value is `0`.
465 ///
466 /// [`set_disabled`]: crate::EventCtx::set_disabled
467 pub fn is_disabled(&self) -> bool {
468 self.widget_state.is_disabled()
469 }
470 }
471);
472
473impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, {
474 /// Set the cursor icon.
475 ///
476 /// This setting will be retained until [`clear_cursor`] is called, but it will only take
477 /// effect when this widget is either [`hot`] or [`active`]. If a child widget also sets a
478 /// cursor, the child widget's cursor will take precedence. (If that isn't what you want, use
479 /// [`override_cursor`] instead.)
480 ///
481 /// [`clear_cursor`]: crate::EventCtx::clear_cursor
482 /// [`override_cursor`]: crate::EventCtx::override_cursor
483 /// [`hot`]: crate::EventCtx::is_hot
484 /// [`active`]: crate::EventCtx::is_active
485 pub fn set_cursor(&mut self, cursor: &Cursor) {
486 trace!("set_cursor {:?}", cursor);
487 self.widget_state.cursor_change = CursorChange::Set(cursor.clone());
488 }
489
490 /// Override the cursor icon.
491 ///
492 /// This setting will be retained until [`clear_cursor`] is called, but it will only take
493 /// effect when this widget is either [`hot`] or [`active`]. This will override the cursor
494 /// preferences of a child widget. (If that isn't what you want, use [`set_cursor`] instead.)
495 ///
496 /// [`clear_cursor`]: crate::EventCtx::clear_cursor
497 /// [`set_cursor`]: crate::EventCtx::set_cursor
498 /// [`hot`]: crate::EventCtx::is_hot
499 /// [`active`]: crate::EventCtx::is_active
500 pub fn override_cursor(&mut self, cursor: &Cursor) {
501 trace!("override_cursor {:?}", cursor);
502 self.widget_state.cursor_change = CursorChange::Override(cursor.clone());
503 }
504
505 /// Clear the cursor icon.
506 ///
507 /// This undoes the effect of [`set_cursor`] and [`override_cursor`].
508 ///
509 /// [`override_cursor`]: crate::EventCtx::override_cursor
510 /// [`set_cursor`]: crate::EventCtx::set_cursor
511 pub fn clear_cursor(&mut self) {
512 trace!("clear_cursor");
513 self.widget_state.cursor_change = CursorChange::Default;
514 }
515});
516
517// methods on event, update and layout.
518impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, LayoutCtx<'_, '_>, {
519 /// Indicate that your [`ViewContext`] has changed.
520 ///
521 /// This event is sent after layout is done and before paint is called. Note that you can still
522 /// receive this event even if there was no prior call to layout.
523 ///
524 /// Widgets must call this method after changing the clip region of their children.
525 /// Changes to the other parts of [`ViewContext`] (cursor position and global origin) are tracked
526 /// internally.
527 ///
528 /// [`ViewContext`]: crate::ViewContext
529 pub fn view_context_changed(&mut self) {
530 self.widget_state.view_context_changed = true;
531 }
532});
533
534// methods on event, update, and lifecycle
535impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>, {
536 /// Request a [`paint`] pass. This is equivalent to calling
537 /// [`request_paint_rect`] for the widget's [`paint_rect`].
538 ///
539 /// [`paint`]: Widget::paint
540 /// [`request_paint_rect`]: #method.request_paint_rect
541 /// [`paint_rect`]: crate::WidgetPod::paint_rect
542 pub fn request_paint(&mut self) {
543 trace!("request_paint");
544 self.widget_state.invalid.set_rect(
545 self.widget_state.paint_rect() - self.widget_state.layout_rect().origin().to_vec2(),
546 );
547 }
548
549 /// Request a [`paint`] pass for redrawing a rectangle, which is given
550 /// relative to our layout rectangle.
551 ///
552 /// [`paint`]: Widget::paint
553 pub fn request_paint_rect(&mut self, rect: Rect) {
554 trace!("request_paint_rect {}", rect);
555 self.widget_state.invalid.add_rect(rect);
556 }
557
558 /// Request a layout pass.
559 ///
560 /// A Widget's [`layout`] method is always called when the widget tree
561 /// changes, or the window is resized.
562 ///
563 /// If your widget would like to have layout called at any other time,
564 /// (such as if it would like to change the layout of children in
565 /// response to some event) it must call this method.
566 ///
567 /// [`layout`]: Widget::layout
568 pub fn request_layout(&mut self) {
569 trace!("request_layout");
570 self.widget_state.needs_layout = true;
571 }
572
573 /// Request an [`AnimFrame`] event.
574 ///
575 /// Receiving [`AnimFrame`] does not inherently mean a `paint` invocation will follow.
576 /// If you want something actually painted you need to explicitly call [`request_paint`]
577 /// or [`request_paint_rect`] when handling the [`AnimFrame`] event.
578 ///
579 /// Note that not requesting paint when handling the [`AnimFrame`] event and then
580 /// recursively requesting another [`AnimFrame`] can lead to rapid event fire,
581 /// which is probably not what you want and would most likely be wasted compute cycles.
582 ///
583 /// [`AnimFrame`]: crate::Event::AnimFrame
584 /// [`request_paint`]: #method.request_paint
585 /// [`request_paint_rect`]: #method.request_paint_rect
586 pub fn request_anim_frame(&mut self) {
587 trace!("request_anim_frame");
588 self.widget_state.request_anim = true;
589 }
590
591 /// Indicate that your children have changed.
592 ///
593 /// Widgets must call this method after adding a new child, removing a child or changing which
594 /// children are hidden (see [`should_propagate_to_hidden`]).
595 ///
596 /// [`should_propagate_to_hidden`]: crate::Event::should_propagate_to_hidden
597 pub fn children_changed(&mut self) {
598 trace!("children_changed");
599 self.widget_state.children_changed = true;
600 self.widget_state.update_focus_chain = true;
601 self.request_layout();
602 }
603
604 /// Set the disabled state for this widget.
605 ///
606 /// Setting this to `false` does not mean a widget is not still disabled; for instance it may
607 /// still be disabled by an ancestor. See [`is_disabled`] for more information.
608 ///
609 /// Calling this method during [`LifeCycle::DisabledChanged`] has no effect.
610 ///
611 /// [`LifeCycle::DisabledChanged`]: crate::LifeCycle::DisabledChanged
612 /// [`is_disabled`]: EventCtx::is_disabled
613 pub fn set_disabled(&mut self, disabled: bool) {
614 // widget_state.children_disabled_changed is not set because we want to be able to delete
615 // changes that happened during DisabledChanged.
616 self.widget_state.is_explicitly_disabled_new = disabled;
617 }
618
619 /// Indicate that text input state has changed.
620 ///
621 /// A widget that accepts text input should call this anytime input state
622 /// (such as the text or the selection) changes as a result of a non text-input
623 /// event.
624 pub fn invalidate_text_input(&mut self, event: ImeInvalidation) {
625 let payload = commands::ImeInvalidation {
626 widget: self.widget_id(),
627 event,
628 };
629 let cmd = commands::INVALIDATE_IME
630 .with(payload)
631 .to(Target::Window(self.window_id()));
632 self.submit_command(cmd);
633 }
634
635 /// Create a new sub-window.
636 ///
637 /// The sub-window will have its app data synchronised with caller's nearest ancestor [`WidgetPod`].
638 /// 'U' must be the type of the nearest surrounding [`WidgetPod`]. The 'data' argument should be
639 /// the current value of data for that widget.
640 ///
641 /// [`WidgetPod`]: crate::WidgetPod
642 // TODO - dynamically check that the type of the pod we are registering this on is the same as the type of the
643 // requirement. Needs type ids recorded. This goes wrong if you don't have a pod between you and a lens.
644 pub fn new_sub_window<W: Widget<U> + 'static, U: Data>(
645 &mut self,
646 window_config: WindowConfig,
647 widget: W,
648 data: U,
649 env: Env,
650 ) -> WindowId {
651 trace!("new_sub_window");
652 let req = SubWindowDesc::new(self.widget_id(), window_config, widget, data, env);
653 let window_id = req.window_id;
654 self.widget_state
655 .add_sub_window_host(window_id, req.host_id);
656 self.submit_command(commands::NEW_SUB_WINDOW.with(SingleUse::new(req)));
657 window_id
658 }
659
660 /// Scrolls this widget into view.
661 ///
662 /// If this widget is only partially visible or not visible at all because of [`Scroll`]s
663 /// it is wrapped in, they will do the minimum amount of scrolling necessary to bring this
664 /// widget fully into view.
665 ///
666 /// If the widget is [`hidden`], this method has no effect.
667 ///
668 /// This functionality is achieved by sending a [`SCROLL_TO_VIEW`] notification.
669 ///
670 /// [`Scroll`]: crate::widget::Scroll
671 /// [`hidden`]: crate::Event::should_propagate_to_hidden
672 /// [`SCROLL_TO_VIEW`]: crate::commands::SCROLL_TO_VIEW
673 pub fn scroll_to_view(&mut self) {
674 self.scroll_area_to_view(self.size().to_rect())
675 }
676});
677
678// methods on everyone but paintctx
679impl_context_method!(
680 EventCtx<'_, '_>,
681 UpdateCtx<'_, '_>,
682 LifeCycleCtx<'_, '_>,
683 LayoutCtx<'_, '_>,
684 {
685 /// Submit a [`Command`] to be run after this event is handled.
686 ///
687 /// Commands are run in the order they are submitted; all commands
688 /// submitted during the handling of an event are executed before
689 /// the [`update`] method is called; events submitted during [`update`]
690 /// are handled after painting.
691 ///
692 /// [`Target::Auto`] commands will be sent to the window containing the widget.
693 ///
694 /// [`update`]: Widget::update
695 pub fn submit_command(&mut self, cmd: impl Into<Command>) {
696 trace!("submit_command");
697 self.state.submit_command(cmd.into())
698 }
699
700 /// Returns an [`ExtEventSink`] that can be moved between threads,
701 /// and can be used to submit commands back to the application.
702 pub fn get_external_handle(&self) -> ExtEventSink {
703 trace!("get_external_handle");
704 self.state.ext_handle.clone()
705 }
706
707 /// Request a timer event.
708 ///
709 /// The return value is a token, which can be used to associate the
710 /// request with the event.
711 pub fn request_timer(&mut self, deadline: Duration) -> TimerToken {
712 trace!("request_timer deadline={:?}", deadline);
713 self.state.request_timer(self.widget_state.id, deadline)
714 }
715 }
716);
717
718impl EventCtx<'_, '_> {
719 /// Submit a [`Notification`].
720 ///
721 /// The provided argument can be a [`Selector`] or a [`Command`]; this lets
722 /// us work with the existing API for adding a payload to a [`Selector`].
723 ///
724 /// If the argument is a `Command`, the command's target will be ignored.
725 ///
726 /// # Examples
727 ///
728 /// ```
729 /// # use druid::{Event, EventCtx, Selector};
730 /// const IMPORTANT_EVENT: Selector<String> = Selector::new("druid-example.important-event");
731 ///
732 /// fn check_event(ctx: &mut EventCtx, event: &Event) {
733 /// if is_this_the_event_we_were_looking_for(event) {
734 /// ctx.submit_notification(IMPORTANT_EVENT.with("That's the one".to_string()))
735 /// }
736 /// }
737 ///
738 /// # fn is_this_the_event_we_were_looking_for(event: &Event) -> bool { true }
739 /// ```
740 ///
741 /// [`Selector`]: crate::Selector
742 pub fn submit_notification(&mut self, note: impl Into<Command>) {
743 trace!("submit_notification");
744 let note = note.into().into_notification(self.widget_state.id);
745 self.notifications.push_back(note);
746 }
747
748 /// Submit a [`Notification`] without warning.
749 ///
750 /// In contrast to [`submit_notification`], calling this method will not result in an
751 /// "unhandled notification" warning.
752 ///
753 /// [`submit_notification`]: crate::EventCtx::submit_notification
754 pub fn submit_notification_without_warning(&mut self, note: impl Into<Command>) {
755 trace!("submit_notification");
756 let note = note
757 .into()
758 .into_notification(self.widget_state.id)
759 .warn_if_unused(false);
760 self.notifications.push_back(note);
761 }
762
763 /// Set the "active" state of the widget.
764 ///
765 /// See [`EventCtx::is_active`](struct.EventCtx.html#method.is_active).
766 pub fn set_active(&mut self, active: bool) {
767 trace!("set_active({})", active);
768 self.widget_state.is_active = active;
769 // TODO: plumb mouse grab through to platform (through druid-shell)
770 }
771
772 /// Create a new window.
773 /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]).
774 ///
775 /// [`AppLauncher::launch`]: crate::AppLauncher::launch
776 pub fn new_window<T: Any>(&mut self, desc: WindowDesc<T>) {
777 trace!("new_window");
778 if self.state.root_app_data_type == TypeId::of::<T>() {
779 self.submit_command(
780 commands::NEW_WINDOW
781 .with(SingleUse::new(Box::new(desc)))
782 .to(Target::Global),
783 );
784 } else {
785 debug_panic!("EventCtx::new_window<T> - T must match the application data type.");
786 }
787 }
788
789 /// Show the context menu in the window containing the current widget.
790 /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]).
791 ///
792 /// [`AppLauncher::launch`]: crate::AppLauncher::launch
793 pub fn show_context_menu<T: Any>(&mut self, menu: Menu<T>, location: Point) {
794 trace!("show_context_menu");
795 if self.state.root_app_data_type == TypeId::of::<T>() {
796 let menu = ContextMenu { menu, location };
797 self.submit_command(
798 commands::SHOW_CONTEXT_MENU
799 .with(SingleUse::new(Box::new(menu)))
800 .to(Target::Window(self.state.window_id)),
801 );
802 } else {
803 debug_panic!(
804 "EventCtx::show_context_menu<T> - T must match the application data type."
805 );
806 }
807 }
808
809 /// Set the event as "handled", which stops its propagation to other
810 /// widgets.
811 pub fn set_handled(&mut self) {
812 trace!("set_handled");
813 self.is_handled = true;
814 }
815
816 /// Determine whether the event has been handled by some other widget.
817 pub fn is_handled(&self) -> bool {
818 self.is_handled
819 }
820
821 /// Request keyboard focus.
822 ///
823 /// Because only one widget can be focused at a time, multiple focus requests
824 /// from different widgets during a single event cycle means that the last
825 /// widget that requests focus will override the previous requests.
826 ///
827 /// See [`is_focused`] for more information about focus.
828 ///
829 /// [`is_focused`]: struct.EventCtx.html#method.is_focused
830 pub fn request_focus(&mut self) {
831 trace!("request_focus");
832 // We need to send the request even if we're currently focused,
833 // because we may have a sibling widget that already requested focus
834 // and we have no way of knowing that yet. We need to override that
835 // to deliver on the "last focus request wins" promise.
836 let id = self.widget_id();
837 self.widget_state.request_focus = Some(FocusChange::Focus(id));
838 }
839
840 /// Transfer focus to the widget with the given `WidgetId`.
841 ///
842 /// See [`is_focused`] for more information about focus.
843 ///
844 /// [`is_focused`]: struct.EventCtx.html#method.is_focused
845 pub fn set_focus(&mut self, target: WidgetId) {
846 trace!("set_focus target={:?}", target);
847 self.widget_state.request_focus = Some(FocusChange::Focus(target));
848 }
849
850 /// Transfer focus to the next focusable widget.
851 ///
852 /// This should only be called by a widget that currently has focus.
853 ///
854 /// See [`is_focused`] for more information about focus.
855 ///
856 /// [`is_focused`]: struct.EventCtx.html#method.is_focused
857 pub fn focus_next(&mut self) {
858 trace!("focus_next");
859 if self.has_focus() {
860 self.widget_state.request_focus = Some(FocusChange::Next);
861 } else {
862 warn!(
863 "focus_next can only be called by the currently \
864 focused widget or one of its ancestors."
865 );
866 }
867 }
868
869 /// Transfer focus to the previous focusable widget.
870 ///
871 /// This should only be called by a widget that currently has focus.
872 ///
873 /// See [`is_focused`] for more information about focus.
874 ///
875 /// [`is_focused`]: struct.EventCtx.html#method.is_focused
876 pub fn focus_prev(&mut self) {
877 trace!("focus_prev");
878 if self.has_focus() {
879 self.widget_state.request_focus = Some(FocusChange::Previous);
880 } else {
881 warn!(
882 "focus_prev can only be called by the currently \
883 focused widget or one of its ancestors."
884 );
885 }
886 }
887
888 /// Give up focus.
889 ///
890 /// This should only be called by a widget that currently has focus.
891 ///
892 /// See [`is_focused`] for more information about focus.
893 ///
894 /// [`is_focused`]: struct.EventCtx.html#method.is_focused
895 pub fn resign_focus(&mut self) {
896 trace!("resign_focus");
897 if self.has_focus() {
898 self.widget_state.request_focus = Some(FocusChange::Resign);
899 } else {
900 warn!(
901 "resign_focus can only be called by the currently focused widget \
902 or one of its ancestors. ({:?})",
903 self.widget_id()
904 );
905 }
906 }
907
908 /// Request an update cycle.
909 ///
910 /// After this, `update` will be called on the widget in the next update cycle, even
911 /// if there's not a data change.
912 ///
913 /// The use case for this method is when a container widget synthesizes data for its
914 /// children. This is appropriate in specialized cases, but before reaching for this
915 /// method, consider whether it might be better to refactor to be more idiomatic, in
916 /// particular to make that data available in the app state.
917 pub fn request_update(&mut self) {
918 trace!("request_update");
919 self.widget_state.request_update = true;
920 }
921
922 /// Scrolls the area into view.
923 ///
924 /// If the area is only partially visible or not visible at all because of [`Scroll`]s
925 /// this widget is wrapped in, they will do the minimum amount of scrolling necessary to
926 /// bring the area fully into view.
927 ///
928 /// If the widget is [`hidden`], this method has no effect.
929 ///
930 /// [`Scroll`]: crate::widget::Scroll
931 /// [`hidden`]: crate::Event::should_propagate_to_hidden
932 pub fn scroll_area_to_view(&mut self, area: Rect) {
933 //TODO: only do something if this widget is not hidden
934 self.submit_notification_without_warning(
935 SCROLL_TO_VIEW.with(area + self.window_origin().to_vec2()),
936 );
937 }
938}
939
940impl UpdateCtx<'_, '_> {
941 /// Returns `true` if this widget or a descendent as explicitly requested
942 /// an update call.
943 ///
944 /// This should only be needed in advanced cases;
945 /// see [`EventCtx::request_update`] for more information.
946 ///
947 /// [`EventCtx::request_update`]: EventCtx::request_update
948 pub fn has_requested_update(&mut self) -> bool {
949 self.widget_state.request_update
950 }
951
952 /// Returns `true` if the current [`Env`] has changed since the previous
953 /// [`update`] call.
954 ///
955 /// [`update`]: Widget::update
956 pub fn env_changed(&self) -> bool {
957 self.prev_env.is_some()
958 }
959
960 /// Returns `true` if the given key has changed since the last [`update`]
961 /// call.
962 ///
963 /// The argument can be anything that is resolveable from the [`Env`],
964 /// such as a [`Key`] or a [`KeyOrValue`].
965 ///
966 /// [`update`]: Widget::update
967 /// [`Key`]: crate::Key
968 /// [`KeyOrValue`]: crate::KeyOrValue
969 pub fn env_key_changed<T>(&self, key: &impl KeyLike<T>) -> bool {
970 match self.prev_env.as_ref() {
971 Some(prev) => key.changed(prev, self.env),
972 None => false,
973 }
974 }
975
976 /// Scrolls the area into view.
977 ///
978 /// If the area is only partially visible or not visible at all because of [`Scroll`]s
979 /// this widget is wrapped in, they will do the minimum amount of scrolling necessary to
980 /// bring the area fully into view.
981 ///
982 /// If the widget is [`hidden`], this method has no effect.
983 ///
984 /// [`Scroll`]: crate::widget::Scroll
985 /// [`hidden`]: crate::Event::should_propagate_to_hidden
986 pub fn scroll_area_to_view(&mut self, area: Rect) {
987 //TODO: only do something if this widget is not hidden
988 self.submit_command(Command::new(
989 SCROLL_TO_VIEW,
990 area + self.window_origin().to_vec2(),
991 self.widget_id(),
992 ));
993 }
994}
995
996impl LifeCycleCtx<'_, '_> {
997 /// Registers a child widget.
998 ///
999 /// This should only be called in response to a `LifeCycle::WidgetAdded` event.
1000 ///
1001 /// In general, you should not need to call this method; it is handled by
1002 /// the `WidgetPod`.
1003 pub fn register_child(&mut self, child_id: WidgetId) {
1004 trace!("register_child id={:?}", child_id);
1005 self.widget_state.children.add(&child_id);
1006 }
1007
1008 /// Register this widget to be eligible to accept focus automatically.
1009 ///
1010 /// This should only be called in response to a [`LifeCycle::BuildFocusChain`] event.
1011 ///
1012 /// See [`EventCtx::is_focused`] for more information about focus.
1013 ///
1014 /// [`LifeCycle::BuildFocusChain`]: crate::LifeCycle::BuildFocusChain
1015 /// [`EventCtx::is_focused`]: EventCtx::is_focused
1016 pub fn register_for_focus(&mut self) {
1017 trace!("register_for_focus");
1018 self.widget_state.focus_chain.push(self.widget_id());
1019 }
1020
1021 /// Register this widget as accepting text input.
1022 pub fn register_text_input(&mut self, document: impl ImeHandlerRef + 'static) {
1023 let registration = TextFieldRegistration {
1024 document: Rc::new(document),
1025 widget_id: self.widget_id(),
1026 };
1027 self.state.text_registrations.push(registration);
1028 }
1029
1030 /// Scrolls the area into view.
1031 ///
1032 /// If the area is only partially visible or not visible at all because of [`Scroll`]s
1033 /// this widget is wrapped in, they will do the minimum amount of scrolling necessary to
1034 /// bring the area fully into view.
1035 ///
1036 /// If the widget is [`hidden`], this method has no effect.
1037 ///
1038 /// [`Scroll`]: crate::widget::Scroll
1039 /// [`hidden`]: crate::Event::should_propagate_to_hidden
1040 pub fn scroll_area_to_view(&mut self, area: Rect) {
1041 //TODO: only do something if this widget is not hidden
1042 self.submit_command(
1043 SCROLL_TO_VIEW
1044 .with(area + self.window_origin().to_vec2())
1045 .to(self.widget_id()),
1046 );
1047 }
1048}
1049
1050impl<'a, 'b> LayoutCtx<'a, 'b> {
1051 /// Set explicit paint [`Insets`] for this widget.
1052 ///
1053 /// You are not required to set explicit paint bounds unless you need
1054 /// to paint outside of your layout bounds. In this case, the argument
1055 /// should be an [`Insets`] struct that indicates where your widget
1056 /// needs to overpaint, relative to its bounds.
1057 ///
1058 /// For more information, see [`WidgetPod::paint_insets`].
1059 ///
1060 /// [`WidgetPod::paint_insets`]: crate::WidgetPod::paint_insets
1061 pub fn set_paint_insets(&mut self, insets: impl Into<Insets>) {
1062 let insets = insets.into();
1063 trace!("set_paint_insets {:?}", insets);
1064 self.widget_state.paint_insets = insets.nonnegative();
1065 }
1066
1067 /// Set an explicit baseline position for this widget.
1068 ///
1069 /// The baseline position is used to align widgets that contain text,
1070 /// such as buttons, labels, and other controls. It may also be used
1071 /// by other widgets that are opinionated about how they are aligned
1072 /// relative to neighbouring text, such as switches or checkboxes.
1073 ///
1074 /// The provided value should be the distance from the *bottom* of the
1075 /// widget to the baseline.
1076 pub fn set_baseline_offset(&mut self, baseline: f64) {
1077 trace!("set_baseline_offset {}", baseline);
1078 self.widget_state.baseline_offset = baseline
1079 }
1080}
1081
1082impl PaintCtx<'_, '_, '_> {
1083 /// The depth in the tree of the currently painting widget.
1084 ///
1085 /// This may be used in combination with [`paint_with_z_index`] in order
1086 /// to correctly order painting operations.
1087 ///
1088 /// The `depth` here may not be exact; it is only guaranteed that a child will
1089 /// have a greater depth than its parent.
1090 ///
1091 /// [`paint_with_z_index`]: #method.paint_with_z_index
1092 #[inline]
1093 pub fn depth(&self) -> u32 {
1094 self.depth
1095 }
1096
1097 /// Returns the region that needs to be repainted.
1098 #[inline]
1099 pub fn region(&self) -> &Region {
1100 &self.region
1101 }
1102
1103 /// Creates a temporary `PaintCtx` with a new visible region, and calls
1104 /// the provided function with that `PaintCtx`.
1105 ///
1106 /// This is used by containers to ensure that their children have the correct
1107 /// visible region given their layout.
1108 pub fn with_child_ctx(&mut self, region: impl Into<Region>, f: impl FnOnce(&mut PaintCtx)) {
1109 let mut child_ctx = PaintCtx {
1110 render_ctx: self.render_ctx,
1111 state: self.state,
1112 widget_state: self.widget_state,
1113 z_ops: Vec::new(),
1114 region: region.into(),
1115 depth: self.depth + 1,
1116 };
1117 f(&mut child_ctx);
1118 self.z_ops.append(&mut child_ctx.z_ops);
1119 }
1120
1121 /// Saves the current context, executes the closures, and restores the context.
1122 ///
1123 /// This is useful if you would like to transform or clip or otherwise
1124 /// modify the drawing context but do not want that modification to
1125 /// effect other widgets.
1126 ///
1127 /// # Examples
1128 ///
1129 /// ```
1130 /// # use druid::{Env, PaintCtx, RenderContext, theme};
1131 /// # struct T;
1132 /// # impl T {
1133 /// fn paint(&mut self, ctx: &mut PaintCtx, _data: &T, env: &Env) {
1134 /// let clip_rect = ctx.size().to_rect().inset(5.0);
1135 /// ctx.with_save(|ctx| {
1136 /// ctx.clip(clip_rect);
1137 /// ctx.stroke(clip_rect, &env.get(theme::PRIMARY_DARK), 5.0);
1138 /// });
1139 /// }
1140 /// # }
1141 /// ```
1142 pub fn with_save(&mut self, f: impl FnOnce(&mut PaintCtx)) {
1143 if let Err(e) = self.render_ctx.save() {
1144 error!("Failed to save RenderContext: '{}'", e);
1145 return;
1146 }
1147
1148 f(self);
1149
1150 if let Err(e) = self.render_ctx.restore() {
1151 error!("Failed to restore RenderContext: '{}'", e);
1152 }
1153 }
1154
1155 /// Allows to specify order for paint operations.
1156 ///
1157 /// Larger `z_index` indicate that an operation will be executed later.
1158 pub fn paint_with_z_index(
1159 &mut self,
1160 z_index: u32,
1161 paint_func: impl FnOnce(&mut PaintCtx) + 'static,
1162 ) {
1163 let current_transform = self.render_ctx.current_transform();
1164 self.z_ops.push(ZOrderPaintOp {
1165 z_index,
1166 paint_func: Box::new(paint_func),
1167 transform: current_transform,
1168 })
1169 }
1170}
1171
1172impl<'a> ContextState<'a> {
1173 pub(crate) fn new<T: 'static>(
1174 command_queue: &'a mut CommandQueue,
1175 ext_handle: &'a ExtEventSink,
1176 window: &'a WindowHandle,
1177 window_id: WindowId,
1178 focus_widget: Option<WidgetId>,
1179 timers: &'a mut HashMap<TimerToken, WidgetId>,
1180 text_registrations: &'a mut Vec<TextFieldRegistration>,
1181 ) -> Self {
1182 ContextState {
1183 command_queue,
1184 ext_handle,
1185 window,
1186 window_id,
1187 focus_widget,
1188 timers,
1189 text_registrations,
1190 text: window.text(),
1191 root_app_data_type: TypeId::of::<T>(),
1192 }
1193 }
1194
1195 fn submit_command(&mut self, command: Command) {
1196 trace!("submit_command");
1197 self.command_queue
1198 .push_back(command.default_to(self.window_id.into()));
1199 }
1200
1201 fn request_timer(&mut self, widget_id: WidgetId, deadline: Duration) -> TimerToken {
1202 trace!("request_timer deadline={:?}", deadline);
1203 let timer_token = self.window.request_timer(deadline);
1204 self.timers.insert(timer_token, widget_id);
1205 timer_token
1206 }
1207}
1208
1209impl<'c> Deref for PaintCtx<'_, '_, 'c> {
1210 type Target = Piet<'c>;
1211
1212 fn deref(&self) -> &Self::Target {
1213 self.render_ctx
1214 }
1215}
1216
1217impl<'c> DerefMut for PaintCtx<'_, '_, 'c> {
1218 fn deref_mut(&mut self) -> &mut Self::Target {
1219 self.render_ctx
1220 }
1221}