From 716a04c28e3085c20428d4c58e7cce75f397852f Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Thu, 21 May 2020 21:00:06 -0400 Subject: [PATCH 1/2] Use a macro to implement context methods This attempts to solve the issue of duplicate code and out of date documentation for methods shared between multiple contexts. The approach taken here is to use a simple macro to implement those methods. A consequence of this work is that methods are now more consistently available across more contexts; as an example, `window_id` and `window` are now available from all contexts, whereas they were previously missing from `PaintCtx` for no particular reason. --- CHANGELOG.md | 5 +- druid/src/contexts.rs | 594 +++++++++++++----------------------------- 2 files changed, 177 insertions(+), 422 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fd77c6771..8ee91888ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i - `LifeCycle::Size` event to inform widgets that their size changed. ([#953] by [@xStrom]) - `Button::dynamic` constructor. ([#963] by [@totsteps]) - `set_menu` method on `UpdateCtx` and `LifeCycleCtx` ([#970] by [@cmyr]) +- Standardize and expose more methods on more contexts ([#972] by [@cmyr]) ### Changed @@ -73,8 +74,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i - Replaced `Command::one_shot` and `::take_object` with a `SingleUse` payload wrapper type. ([#959] by [@finnerale]) - Renamed `WidgetPod` methods: `paint` to `paint_raw`, `paint_with_offset` to `paint`, `paint_with_offset_always` to `paint_always`. ([#980] by [@totsteps]) - `Command` and `Selector` have been reworked and are now statically typed, similarly to `Env` and `Key`. ([#993] by [@finnerale]) -- Standardize the type returned by the contexts' `text()` methods. ([#996] by - [@cmyr]) +- Standardize the type returned by the contexts' `text()` methods. ([#996] by [@cmyr]) ### Deprecated @@ -240,6 +240,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i [#967]: https://github.com/xi-editor/druid/pull/967 [#969]: https://github.com/xi-editor/druid/pull/969 [#970]: https://github.com/xi-editor/druid/pull/970 +[#972]: https://github.com/xi-editor/druid/pull/972 [#980]: https://github.com/xi-editor/druid/pull/980 [#982]: https://github.com/xi-editor/druid/pull/982 [#984]: https://github.com/xi-editor/druid/pull/984 diff --git a/druid/src/contexts.rs b/druid/src/contexts.rs index e25efd6f12..7b449a2c22 100644 --- a/druid/src/contexts.rs +++ b/druid/src/contexts.rs @@ -28,6 +28,20 @@ use crate::{ Target, Text, TimerToken, Vec2, WidgetId, WindowDesc, WindowHandle, WindowId, }; +/// A macro for implementing methods on multiple contexts. +/// +/// There are a lot of methods defined on multiple methods; this lets us only +/// have to write them out once. +macro_rules! impl_context_method { + ($ty:ty, { $($method:item)+ } ) => { + impl $ty { $($method)+ } + }; + ( $ty:ty, $($more:ty),+, { $($method:item)+ } ) => { + impl_context_method!($ty, { $($method)+ }); + impl_context_method!($($more),+, { $($method)+ }); + }; +} + /// Static state that is shared between most contexts. pub(crate) struct ContextState<'a> { pub(crate) command_queue: &'a mut CommandQueue, @@ -45,12 +59,9 @@ pub(crate) struct ContextState<'a> { /// /// [`request_paint`]: #method.request_paint pub struct EventCtx<'a, 'b> { - // Note: there's a bunch of state that's just passed down, might - // want to group that into a single struct. pub(crate) state: &'a mut ContextState<'b>, - pub(crate) cursor: &'a mut Option, - /// Commands submitted to be run after this event. pub(crate) widget_state: &'a mut WidgetState, + pub(crate) cursor: &'a mut Option, pub(crate) is_handled: bool, pub(crate) is_root: bool, } @@ -127,17 +138,135 @@ pub struct PaintCtx<'a, 'b, 'c> { #[derive(Debug, Clone)] pub struct Region(Rect); -impl EventCtx<'_, '_> { +// methods on everyone +impl_context_method!( + EventCtx<'_, '_>, + UpdateCtx<'_, '_>, + LifeCycleCtx<'_, '_>, + PaintCtx<'_, '_, '_>, + LayoutCtx<'_, '_>, + { + /// get the `WidgetId` of the current widget. + pub fn widget_id(&self) -> WidgetId { + self.widget_state.id + } + + /// Returns a reference to the current `WindowHandle`. + pub fn window(&self) -> &WindowHandle { + &self.state.window + } + + /// Get the `WindowId` of the current window. + pub fn window_id(&self) -> WindowId { + self.state.window_id + } + + /// Get an object which can create text layouts. + pub fn text(&self) -> Text { + self.state.window.text() + } + } +); + +// methods on everyone but layoutctx +impl_context_method!( + EventCtx<'_, '_>, + UpdateCtx<'_, '_>, + LifeCycleCtx<'_, '_>, + PaintCtx<'_, '_, '_>, + { + /// The layout size. + /// + /// This is the layout size as ultimately determined by the parent + /// container, on the previous layout pass. + /// + /// Generally it will be the same as the size returned by the child widget's + /// [`layout`] method. + /// + /// [`layout`]: trait.Widget.html#tymethod.layout + pub fn size(&self) -> Size { + self.widget_state.size() + } + + /// The "hot" (aka hover) status of a widget. + /// + /// A widget is "hot" when the mouse is hovered over it. Widgets will + /// often change their appearance as a visual indication that they + /// will respond to mouse interaction. + /// + /// The hot status is computed from the widget's layout rect. In a + /// container hierarchy, all widgets with layout rects containing the + /// mouse position have hot status. + /// + /// Discussion: there is currently some confusion about whether a + /// widget can be considered hot when some other widget is active (for + /// example, when clicking to one widget and dragging to the next). + /// The documentation should clearly state the resolution. + pub fn is_hot(&self) -> bool { + self.widget_state.is_hot + } + + /// The active status of a widget. + /// + /// Active status generally corresponds to a mouse button down. Widgets + /// with behavior similar to a button will call [`set_active`] on mouse + /// down and then up. + /// + /// When a widget is active, it gets mouse events even when the mouse + /// is dragged away. + /// + /// [`set_active`]: struct.EventCtx.html#method.set_active + pub fn is_active(&self) -> bool { + self.widget_state.is_active + } + + /// The focus status of a widget. + /// + /// Returns `true` if this specific widget is focused. + /// To check if any descendants are focused use [`has_focus`]. + /// + /// Focus means that the widget receives keyboard events. + /// + /// A widget can request focus using the [`request_focus`] method. + /// It's also possible to register for automatic focus via [`register_for_focus`]. + /// + /// If a widget gains or loses focus it will get a [`LifeCycle::FocusChanged`] event. + /// + /// Only one widget at a time is focused. However due to the way events are routed, + /// all ancestors of that widget will also receive keyboard events. + /// + /// [`request_focus`]: struct.EventCtx.html#method.request_focus + /// [`register_for_focus`]: struct.LifeCycleCtx.html#method.register_for_focus + /// [`LifeCycle::FocusChanged`]: enum.LifeCycle.html#variant.FocusChanged + /// [`has_focus`]: #method.has_focus + pub fn is_focused(&self) -> bool { + self.state.focus_widget == Some(self.widget_id()) + } + + /// The (tree) focus status of a widget. + /// + /// Returns `true` if either this specific widget or any one of its descendants is focused. + /// To check if only this specific widget is focused use [`is_focused`], + /// + /// [`is_focused`]: #method.is_focused + pub fn has_focus(&self) -> bool { + self.widget_state.has_focus + } + } +); + +// methods on event, update, and lifecycle +impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>, { #[deprecated(since = "0.5.0", note = "use request_paint instead")] pub fn invalidate(&mut self) { self.request_paint(); } - /// Request a [`paint`] pass. This is equivalent to calling [`request_paint_rect`] for the - /// widget's [`paint_rect`]. + /// Request a [`paint`] pass. This is equivalent to calling + /// [`request_paint_rect`] for the widget's [`paint_rect`]. /// /// [`paint`]: trait.Widget.html#tymethod.paint - /// [`request_paint_rect`]: struct.EventCtx.html#method.request_paint_rect + /// [`request_paint_rect`]: #method.request_paint_rect /// [`paint_rect`]: struct.WidgetPod.html#method.paint_rect pub fn request_paint(&mut self) { self.request_paint_rect( @@ -145,8 +274,8 @@ impl EventCtx<'_, '_> { ); } - /// Request a [`paint`] pass for redrawing a rectangle, which is given relative to our layout - /// rectangle. + /// Request a [`paint`] pass for redrawing a rectangle, which is given + /// relative to our layout rectangle. /// /// [`paint`]: trait.Widget.html#tymethod.paint pub fn request_paint_rect(&mut self, rect: Rect) { @@ -167,6 +296,20 @@ impl EventCtx<'_, '_> { self.widget_state.needs_layout = true; } + /// Request an animation frame. + pub fn request_anim_frame(&mut self) { + self.widget_state.request_anim = true; + self.request_paint(); + } + + /// Request a timer event. + /// + /// The return value is a token, which can be used to associate the + /// request with the event. + pub fn request_timer(&mut self, deadline: Duration) -> TimerToken { + self.state.request_timer(&mut self.widget_state, deadline) + } + /// Indicate that your children have changed. /// /// Widgets must call this method after adding a new child. @@ -175,11 +318,29 @@ impl EventCtx<'_, '_> { self.request_layout(); } - /// Get an object which can create text layouts. - pub fn text(&mut self) -> Text { - self.state.window.text() + /// Submit a [`Command`] to be run after this event is handled. + /// + /// Commands are run in the order they are submitted; all commands + /// submitted during the handling of an event are executed before + /// the [`update`] method is called; events submitted during [`update`] + /// are handled after painting. + /// + /// [`Command`]: struct.Command.html + /// [`update`]: trait.Widget.html#tymethod.update + pub fn submit_command(&mut self, cmd: impl Into, target: impl Into>) { + self.state.submit_command(cmd.into(), target.into()) } + /// Set the menu of the window containing the current widget. + /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]). + /// + /// [`AppLauncher::launch`]: struct.AppLauncher.html#method.launch + pub fn set_menu(&mut self, menu: MenuDesc) { + self.state.set_menu(menu); + } +}); + +impl EventCtx<'_, '_> { /// Set the cursor icon. /// /// Call this when handling a mouse move event, to set the cursor for the @@ -205,43 +366,6 @@ impl EventCtx<'_, '_> { // TODO: plumb mouse grab through to platform (through druid-shell) } - /// The "hot" (aka hover) status of a widget. - /// - /// A widget is "hot" when the mouse is hovered over it. Widgets will - /// often change their appearance as a visual indication that they - /// will respond to mouse interaction. - /// - /// The hot status is computed from the widget's layout rect. In a - /// container hierarchy, all widgets with layout rects containing the - /// mouse position have hot status. - /// - /// Discussion: there is currently some confusion about whether a - /// widget can be considered hot when some other widget is active (for - /// example, when clicking to one widget and dragging to the next). - /// The documentation should clearly state the resolution. - pub fn is_hot(&self) -> bool { - self.widget_state.is_hot - } - - /// The active status of a widget. - /// - /// Active status generally corresponds to a mouse button down. Widgets - /// with behavior similar to a button will call [`set_active`] on mouse - /// down and then up. - /// - /// When a widget is active, it gets mouse events even when the mouse - /// is dragged away. - /// - /// [`set_active`]: struct.EventCtx.html#method.set_active - pub fn is_active(&self) -> bool { - self.widget_state.is_active - } - - /// Returns a reference to the current `WindowHandle`. - pub fn window(&self) -> &WindowHandle { - &self.state.window - } - /// Create a new window. /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]). /// @@ -262,14 +386,6 @@ impl EventCtx<'_, '_> { } } - /// Set the menu of the window containing the current widget. - /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]). - /// - /// [`AppLauncher::launch`]: struct.AppLauncher.html#method.launch - pub fn set_menu(&mut self, menu: MenuDesc) { - self.state.set_menu(menu); - } - /// Show the context menu in the window containing the current widget. /// `T` must be the application's root `Data` type (the type provided to [`AppLauncher::launch`]). /// @@ -301,41 +417,6 @@ impl EventCtx<'_, '_> { self.is_handled } - /// The focus status of a widget. - /// - /// Returns `true` if this specific widget is focused. - /// To check if any descendants are focused use [`has_focus`]. - /// - /// Focus means that the widget receives keyboard events. - /// - /// A widget can request focus using the [`request_focus`] method. - /// It's also possible to register for automatic focus via [`register_for_focus`]. - /// - /// If a widget gains or loses focus it will get a [`LifeCycle::FocusChanged`] event. - /// - /// Only one widget at a time is focused. However due to the way events are routed, - /// all ancestors of that widget will also receive keyboard events. - /// - /// [`request_focus`]: struct.EventCtx.html#method.request_focus - /// [`register_for_focus`]: struct.LifeCycleCtx.html#method.register_for_focus - /// [`LifeCycle::FocusChanged`]: enum.LifeCycle.html#variant.FocusChanged - /// [`has_focus`]: struct.EventCtx.html#method.has_focus - pub fn is_focused(&self) -> bool { - self.state.focus_widget == Some(self.widget_id()) - } - - /// The (tree) focus status of a widget. - /// - /// Returns `true` if either this specific widget or any one of its descendants is focused. - /// To check if only this specific widget is focused use [`is_focused`]. - /// - /// See [`is_focused`] for more information about focus. - /// - /// [`is_focused`]: struct.EventCtx.html#method.is_focused - pub fn has_focus(&self) -> bool { - self.widget_state.has_focus - } - /// Request keyboard focus. /// /// Because only one widget can be focused at a time, multiple focus requests @@ -401,97 +482,9 @@ impl EventCtx<'_, '_> { ); } } - - /// Request an animation frame. - pub fn request_anim_frame(&mut self) { - self.widget_state.request_anim = true; - self.request_paint(); - } - - /// Request a timer event. - /// - /// The return value is a token, which can be used to associate the - /// request with the event. - pub fn request_timer(&mut self, deadline: Duration) -> TimerToken { - self.state.request_timer(&mut self.widget_state, deadline) - } - - /// The layout size. - /// - /// This is the layout size as ultimately determined by the parent - /// container, on the previous layout pass. - /// - /// Generally it will be the same as the size returned by the child widget's - /// [`layout`] method. - /// - /// [`layout`]: trait.Widget.html#tymethod.layout - pub fn size(&self) -> Size { - self.widget_state.size() - } - - /// Submit a [`Command`] to be run after this event is handled. - /// - /// Commands are run in the order they are submitted; all commands - /// submitted during the handling of an event are executed before - /// the [`update`] method is called. - /// - /// [`Command`]: struct.Command.html - /// [`update`]: trait.Widget.html#tymethod.update - pub fn submit_command(&mut self, cmd: impl Into, target: impl Into>) { - self.state.submit_command(cmd.into(), target.into()) - } - - /// Get the window id. - pub fn window_id(&self) -> WindowId { - self.state.window_id - } - - /// get the `WidgetId` of the current widget. - pub fn widget_id(&self) -> WidgetId { - self.widget_state.id - } } impl LifeCycleCtx<'_, '_> { - #[deprecated(since = "0.5.0", note = "use request_paint instead")] - pub fn invalidate(&mut self) { - self.request_paint(); - } - - /// Request a [`paint`] pass. This is equivalent to calling [`request_paint_rect`] for the - /// widget's [`paint_rect`]. - /// - /// [`paint`]: trait.Widget.html#tymethod.paint - /// [`request_paint_rect`]: struct.LifeCycleCtx.html#method.request_paint_rect - /// [`paint_rect`]: struct.WidgetPod.html#method.paint_rect - pub fn request_paint(&mut self) { - self.request_paint_rect( - self.widget_state.paint_rect() - self.widget_state.layout_rect().origin().to_vec2(), - ); - } - - /// Request a [`paint`] pass for redrawing a rectangle, which is given relative to our layout - /// rectangle. - /// - /// [`paint`]: trait.Widget.html#tymethod.paint - pub fn request_paint_rect(&mut self, rect: Rect) { - self.widget_state.invalid.add_rect(rect); - } - - /// Request layout. - /// - /// See [`EventCtx::request_layout`] for more information. - /// - /// [`EventCtx::request_layout`]: struct.EventCtx.html#method.request_layout - pub fn request_layout(&mut self) { - self.widget_state.needs_layout = true; - } - - /// Returns the current widget's `WidgetId`. - pub fn widget_id(&self) -> WidgetId { - self.widget_state.id - } - /// Registers a child widget. /// /// This should only be called in response to a `LifeCycle::WidgetAdded` event. @@ -513,188 +506,9 @@ impl LifeCycleCtx<'_, '_> { pub fn register_for_focus(&mut self) { self.widget_state.focus_chain.push(self.widget_id()); } - - /// Indicate that your children have changed. - /// - /// Widgets must call this method after adding a new child. - pub fn children_changed(&mut self) { - self.widget_state.children_changed = true; - self.request_layout(); - } - - /// Request an animation frame. - pub fn request_anim_frame(&mut self) { - self.widget_state.request_anim = true; - self.request_paint(); - } - - /// Request a timer event. - /// - /// The return value is a token, which can be used to associate the - /// request with the event. - pub fn request_timer(&mut self, deadline: Duration) -> TimerToken { - self.state.request_timer(&mut self.widget_state, deadline) - } - - /// The layout size. - /// - /// This is the layout size as ultimately determined by the parent - /// container, on the previous layout pass. - /// - /// Generally it will be the same as the size returned by the child widget's - /// [`layout`] method. - /// - /// [`layout`]: trait.Widget.html#tymethod.layout - pub fn size(&self) -> Size { - self.widget_state.size() - } - - /// Submit a [`Command`] to be run after this event is handled. - /// - /// Commands are run in the order they are submitted; all commands - /// submitted during the handling of an event are executed before - /// the [`update`] method is called. - /// - /// [`Command`]: struct.Command.html - /// [`update`]: trait.Widget.html#tymethod.update - pub fn submit_command(&mut self, cmd: impl Into, target: impl Into>) { - self.state.submit_command(cmd.into(), target.into()) - } - - /// Set the menu of the window containing the current widget. - /// `T` must be the application's root `Data` type (the type provided - /// to [`AppLauncher::launch`]). - /// - /// [`AppLauncher::launch`]: struct.AppLauncher.html#method.launch - pub fn set_menu(&mut self, menu: MenuDesc) { - self.state.set_menu(menu); - } -} - -impl<'a, 'b> UpdateCtx<'a, 'b> { - #[deprecated(since = "0.5.0", note = "use request_paint instead")] - pub fn invalidate(&mut self) { - self.request_paint(); - } - - /// Request a [`paint`] pass. This is equivalent to calling [`request_paint_rect`] for the - /// widget's [`paint_rect`]. - /// - /// [`paint`]: trait.Widget.html#tymethod.paint - /// [`request_paint_rect`]: struct.UpdateCtx.html#method.request_paint_rect - /// [`paint_rect`]: struct.WidgetPod.html#method.paint_rect - pub fn request_paint(&mut self) { - self.request_paint_rect( - self.widget_state.paint_rect() - self.widget_state.layout_rect().origin().to_vec2(), - ); - } - - /// Request a [`paint`] pass for redrawing a rectangle, which is given relative to our layout - /// rectangle. - /// - /// [`paint`]: trait.Widget.html#tymethod.paint - pub fn request_paint_rect(&mut self, rect: Rect) { - self.widget_state.invalid.add_rect(rect); - } - - /// Request layout. - /// - /// See [`EventCtx::request_layout`] for more information. - /// - /// [`EventCtx::request_layout`]: struct.EventCtx.html#method.request_layout - pub fn request_layout(&mut self) { - self.widget_state.needs_layout = true; - } - - /// Indicate that your children have changed. - /// - /// Widgets must call this method after adding a new child. - pub fn children_changed(&mut self) { - self.widget_state.children_changed = true; - self.request_layout(); - } - - /// Request an animation frame. - pub fn request_anim_frame(&mut self) { - self.widget_state.request_anim = true; - self.request_paint(); - } - - /// Request a timer event. - /// - /// The return value is a token, which can be used to associate the - /// request with the event. - pub fn request_timer(&mut self, deadline: Duration) -> TimerToken { - self.state.request_timer(&mut self.widget_state, deadline) - } - - /// The layout size. - /// - /// This is the layout size as ultimately determined by the parent - /// container, on the previous layout pass. - /// - /// Generally it will be the same as the size returned by the child widget's - /// [`layout`] method. - /// - /// [`layout`]: trait.Widget.html#tymethod.layout - pub fn size(&self) -> Size { - self.widget_state.size() - } - - /// Submit a [`Command`] to be run after layout and paint finish. - /// - /// **Note:** - /// - /// Commands submited during an `update` call are handled *after* update, - /// layout, and paint have completed; this will trigger a new event cycle. - /// - /// [`Command`]: struct.Command.html - pub fn submit_command(&mut self, cmd: impl Into, target: impl Into>) { - self.state.submit_command(cmd.into(), target.into()); - } - - /// Set the menu of the window containing the current widget. - /// `T` must be the application's root `Data` type (the type provided - /// to [`AppLauncher::launch`]). - /// - /// [`AppLauncher::launch`]: struct.AppLauncher.html#method.launch - pub fn set_menu(&mut self, menu: MenuDesc) { - self.state.set_menu(menu) - } - - /// Get an object which can create text layouts. - pub fn text(&mut self) -> Text { - self.state.window.text() - } - - /// Returns a reference to the current `WindowHandle`. - //TODO: can we delete this? where is it used? - pub fn window(&self) -> &WindowHandle { - &self.state.window - } - - /// Get the window id. - pub fn window_id(&self) -> WindowId { - self.state.window_id - } - - /// get the `WidgetId` of the current widget. - pub fn widget_id(&self) -> WidgetId { - self.widget_state.id - } } impl LayoutCtx<'_, '_> { - /// Get an object which can create text layouts. - pub fn text(&mut self) -> Text { - self.state.window.text() - } - - /// Get the window id. - pub fn window_id(&self) -> WindowId { - self.state.window_id - } - /// Set explicit paint [`Insets`] for this widget. /// /// You are not required to set explicit paint bounds unless you need @@ -712,66 +526,6 @@ impl LayoutCtx<'_, '_> { } impl PaintCtx<'_, '_, '_> { - /// get the `WidgetId` of the current widget. - pub fn widget_id(&self) -> WidgetId { - self.widget_state.id - } - - /// Get an object which can create text layouts. - pub fn text(&mut self) -> Text { - self.state.window.text() - } - - /// Query the "hot" state of the widget. - /// - /// See [`EventCtx::is_hot`](struct.EventCtx.html#method.is_hot) for - /// additional information. - pub fn is_hot(&self) -> bool { - self.widget_state.is_hot - } - - /// Query the "active" state of the widget. - /// - /// See [`EventCtx::is_active`](struct.EventCtx.html#method.is_active) for - /// additional information. - pub fn is_active(&self) -> bool { - self.widget_state.is_active - } - - /// Returns the layout size of the current widget. - /// - /// See [`EventCtx::size`](struct.EventCtx.html#method.size) for - /// additional information. - pub fn size(&self) -> Size { - self.widget_state.size() - } - - /// The focus status of a widget. - /// - /// Returns `true` if this specific widget is focused. - /// To check if any descendants are focused use [`has_focus`]. - /// - /// See [`EventCtx::is_focused`] for more information about focus. - /// - /// [`has_focus`]: #method.has_focus - /// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused - pub fn is_focused(&self) -> bool { - self.state.focus_widget == Some(self.widget_id()) - } - - /// The (tree) focus status of a widget. - /// - /// Returns `true` if either this specific widget or any one of its descendants is focused. - /// To check if only this specific widget is focused use [`is_focused`]. - /// - /// See [`EventCtx::is_focused`] for more information about focus. - /// - /// [`is_focused`]: #method.is_focused - /// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused - pub fn has_focus(&self) -> bool { - self.widget_state.has_focus - } - /// The depth in the tree of the currently painting widget. /// /// This may be used in combination with [`paint_with_z_index`] in order From 535cdcb8c3e55c3b8cb4ef7b8d7e98f142f6ac2b Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Sun, 31 May 2020 13:06:15 -0400 Subject: [PATCH 2/2] Update druid/src/contexts.rs Co-authored-by: Leopold Luley --- druid/src/contexts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/druid/src/contexts.rs b/druid/src/contexts.rs index 7b449a2c22..1d2ed9ab1e 100644 --- a/druid/src/contexts.rs +++ b/druid/src/contexts.rs @@ -30,7 +30,7 @@ use crate::{ /// A macro for implementing methods on multiple contexts. /// -/// There are a lot of methods defined on multiple methods; this lets us only +/// There are a lot of methods defined on multiple contexts; this lets us only /// have to write them out once. macro_rules! impl_context_method { ($ty:ty, { $($method:item)+ } ) => {