From 8a4c66e73bf9445fce1087278af392ca97c8955b Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Thu, 30 Nov 2023 09:14:19 -0800 Subject: [PATCH] Refactored to MakeWidgetWithId --- examples/custom-widgets.rs | 24 ++++++++++++++++-------- src/value.rs | 14 +++++++------- src/widget.rs | 6 +++--- src/widgets/checkbox.rs | 8 ++++---- src/widgets/label.rs | 8 ++++---- src/widgets/progress.rs | 8 ++++---- src/widgets/radio.rs | 8 ++++---- src/widgets/select.rs | 8 ++++---- src/widgets/validated.rs | 8 ++++---- 9 files changed, 50 insertions(+), 42 deletions(-) diff --git a/examples/custom-widgets.rs b/examples/custom-widgets.rs index 3c46410..8c35b43 100644 --- a/examples/custom-widgets.rs +++ b/examples/custom-widgets.rs @@ -2,7 +2,7 @@ //! traits or using the [`Custom`] widget with callbacks. use gooey::value::Dynamic; -use gooey::widget::{MakeWidget, Widget, HANDLED}; +use gooey::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance, WidgetTag, HANDLED}; use gooey::widgets::Custom; use gooey::Run; use kludgine::figures::units::{Lp, UPx}; @@ -29,7 +29,7 @@ fn main() -> gooey::Result { /// /// This approach was added to make it easy to create one-off widgets in a /// hierarchy to handle events or other purpose-built functions. -fn callback_widget() -> impl MakeWidget { +fn callback_widget() -> impl MakeWidgetWithId { // This implementation and the impl `Widget` implementation both use the // same Dynamic value setup. let toggle = Toggle::default(); @@ -44,18 +44,26 @@ fn callback_widget() -> impl MakeWidget { .height(Lp::inches(1)) } -/// A second approach is to implement [`MakeWidget`] for a type. This allows any -/// type to be used when composing your UI that know how to create a widget. +/// A second approach is to implement [`MakeWidgetWithId`] for a type. This +/// allows any type to be used when composing your UI that know how to create a +/// widget. /// /// This enables using callback-based widgets (or any other combination of /// widgets) in a reusable fashion. +/// +/// [`MakeWidget`] is implemented automatically for all types that implement +/// [`MakeWidgetWithId`]. The difference between the traits is purely whether +/// allowing a caller instantiating your custom widget to provide an id for the +/// widget. These IDs are used when configuring custom tab orders, so if your +/// widget or any of its children aren't focusable, implementing [`MakeWidget`] +/// directly will make more sense. #[derive(Default)] struct ToggleMakeWidget(Toggle); -impl MakeWidget for ToggleMakeWidget { - fn make_widget(self) -> gooey::widget::WidgetInstance { +impl MakeWidgetWithId for ToggleMakeWidget { + fn make_with_id(self, id: WidgetTag) -> WidgetInstance { // In a real code base, the contents of callback_widget() would go here - callback_widget().make_widget() + callback_widget().make_with_id(id) } } @@ -63,7 +71,7 @@ impl MakeWidget for ToggleMakeWidget { /// /// This is the lowest-level way to implement a Widget, but it also provides the /// most power and flexibility. -fn impl_widget() -> impl MakeWidget { +fn impl_widget() -> impl MakeWidgetWithId { Toggle::default() } diff --git a/src/value.rs b/src/value.rs index 133f81e..cf76caa 100644 --- a/src/value.rs +++ b/src/value.rs @@ -20,7 +20,7 @@ use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearIn use crate::context::sealed::WindowHandle; use crate::context::{self, WidgetContext}; use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone}; -use crate::widget::{Children, MakeWidget, WidgetId, WidgetInstance}; +use crate::widget::{Children, MakeWidget, MakeWidgetWithId, WidgetId, WidgetInstance}; use crate::widgets::{Radio, Select, Space, Switcher}; /// An instance of a value that provides APIs to observe and react to its @@ -607,20 +607,20 @@ impl Dynamic { } } -impl MakeWidget for Dynamic { - fn make_widget(self) -> WidgetInstance { - self.switcher().make_widget() +impl MakeWidgetWithId for Dynamic { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { + self.switcher().make_with_id(id) } } -impl MakeWidget for Dynamic> { - fn make_widget(self) -> WidgetInstance { +impl MakeWidgetWithId for Dynamic> { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { self.map_each(|widget| { widget .as_ref() .map_or_else(|| Space::clear().make_widget(), Clone::clone) }) - .make_widget() + .make_with_id(id) } } diff --git a/src/widget.rs b/src/widget.rs index 24e00f2..1da6715 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1077,9 +1077,9 @@ impl MakeWidget for WidgetInstance { } } -impl MakeWidget for Color { - fn make_widget(self) -> WidgetInstance { - Space::colored(self).make_widget() +impl MakeWidgetWithId for Color { + fn make_with_id(self, id: WidgetTag) -> WidgetInstance { + Space::colored(self).make_with_id(id) } } diff --git a/src/widgets/checkbox.rs b/src/widgets/checkbox.rs index 0fa3105..a2b7981 100644 --- a/src/widgets/checkbox.rs +++ b/src/widgets/checkbox.rs @@ -10,7 +10,7 @@ use kludgine::shapes::{PathBuilder, Shape, StrokeOptions}; use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; -use crate::widget::{MakeWidget, Widget, WidgetInstance}; +use crate::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance}; use crate::widgets::button::ButtonKind; use crate::ConstraintLimit; @@ -50,8 +50,8 @@ impl Checkbox { } } -impl MakeWidget for Checkbox { - fn make_widget(self) -> WidgetInstance { +impl MakeWidgetWithId for Checkbox { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { CheckboxOrnament { value: self.state.create_reader(), } @@ -63,7 +63,7 @@ impl MakeWidget for Checkbox { *value = !*value; }) .kind(self.kind) - .make_widget() + .make_with_id(id) } } diff --git a/src/widgets/label.rs b/src/widgets/label.rs index 7d3ddc4..d3236ea 100644 --- a/src/widgets/label.rs +++ b/src/widgets/label.rs @@ -8,7 +8,7 @@ use kludgine::{Color, DrawableExt}; use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::TextColor; use crate::value::{Dynamic, Generation, IntoValue, Value}; -use crate::widget::{MakeWidget, Widget, WidgetInstance}; +use crate::widget::{Widget, WidgetInstance}; use crate::ConstraintLimit; /// A read-only text widget. @@ -90,9 +90,9 @@ impl Widget for Label { macro_rules! impl_make_widget { ($($type:ty),*) => { - $(impl MakeWidget for $type { - fn make_widget(self) -> WidgetInstance { - Label::new(self).make_widget() + $(impl crate::widget::MakeWidgetWithId for $type { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { + Label::new(self).make_with_id(id) } })* }; diff --git a/src/widgets/progress.rs b/src/widgets/progress.rs index 75c3c24..d6ec71d 100644 --- a/src/widgets/progress.rs +++ b/src/widgets/progress.rs @@ -10,7 +10,7 @@ use crate::animation::{ AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne, }; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; -use crate::widget::{MakeWidget, WidgetInstance}; +use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance}; use crate::widgets::slider::Slidable; use crate::widgets::Data; @@ -47,8 +47,8 @@ pub enum Progress { Percent(T), } -impl MakeWidget for ProgressBar { - fn make_widget(self) -> WidgetInstance { +impl MakeWidgetWithId for ProgressBar { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { let start = Dynamic::new(ZeroToOne::ZERO); let end = Dynamic::new(ZeroToOne::ZERO); let value = (&start, &end).map_each(|(start, end)| *start..=*end); @@ -61,7 +61,7 @@ impl MakeWidget for ProgressBar { &end, ); - let slider = value.slider().knobless().non_interactive(); + let slider = value.slider().knobless().non_interactive().make_with_id(id); match self.progress { Value::Dynamic(progress) => { progress.for_each(move |progress| { diff --git a/src/widgets/radio.rs b/src/widgets/radio.rs index cf218f8..120251f 100644 --- a/src/widgets/radio.rs +++ b/src/widgets/radio.rs @@ -10,7 +10,7 @@ use kludgine::DrawableExt; use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; -use crate::widget::{MakeWidget, Widget, WidgetInstance}; +use crate::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance}; use crate::widgets::button::ButtonKind; use crate::ConstraintLimit; @@ -50,11 +50,11 @@ impl Radio { } } -impl MakeWidget for Radio +impl MakeWidgetWithId for Radio where T: Clone + Debug + Eq + UnwindSafe + Send + 'static, { - fn make_widget(self) -> WidgetInstance { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { RadioOrnament { value: self.value.clone(), state: self.state.create_reader(), @@ -66,7 +66,7 @@ where self.state.set(self.value.clone()); }) .kind(self.kind) - .make_widget() + .make_with_id(id) } } diff --git a/src/widgets/select.rs b/src/widgets/select.rs index 44b02eb..a4c321a 100644 --- a/src/widgets/select.rs +++ b/src/widgets/select.rs @@ -7,7 +7,7 @@ use kludgine::Color; use crate::styles::components::OutlineColor; use crate::styles::{Component, DynamicComponent}; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; -use crate::widget::{MakeWidget, WidgetInstance}; +use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance}; use crate::widgets::button::{ButtonBackground, ButtonHoverBackground, ButtonKind}; /// A selectable, labeled widget representing a value. @@ -45,11 +45,11 @@ impl Select { } } -impl MakeWidget for Select +impl MakeWidgetWithId for Select where T: Clone + Debug + Eq + RefUnwindSafe + UnwindSafe + Send + Sync + 'static, { - fn make_widget(self) -> WidgetInstance { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { let selected = self.state.map_each({ let value = self.value.clone(); move |state| state == &value @@ -79,7 +79,7 @@ where .kind(kind) .with_dynamic(&ButtonBackground, selected_color.clone()) .with_dynamic(&ButtonHoverBackground, selected_color) - .make_widget() + .make_with_id(id) } } diff --git a/src/widgets/validated.rs b/src/widgets/validated.rs index e41749f..34dc976 100644 --- a/src/widgets/validated.rs +++ b/src/widgets/validated.rs @@ -5,7 +5,7 @@ use kludgine::Color; use crate::styles::components::{LineHeight, OutlineColor, TextColor, TextSize}; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Validation, Value}; -use crate::widget::{MakeWidget, WidgetInstance, WidgetRef, WrapperWidget}; +use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance, WidgetRef, WrapperWidget}; /// A widget that displays validation information around another widget. /// @@ -42,8 +42,8 @@ impl Validated { } } -impl MakeWidget for Validated { - fn make_widget(self) -> WidgetInstance { +impl MakeWidgetWithId for Validated { + fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { let message = match self.hint { Value::Constant(hint) => self .validation @@ -81,7 +81,7 @@ impl MakeWidget for Validated { error_color, default_color, } - .make_widget() + .make_with_id(id) } }