Refactored to MakeWidgetWithId

This commit is contained in:
Jonathan Johnson 2023-11-30 09:14:19 -08:00
parent a826b91173
commit 8a4c66e73b
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
9 changed files with 50 additions and 42 deletions

View file

@ -2,7 +2,7 @@
//! traits or using the [`Custom`] widget with callbacks. //! traits or using the [`Custom`] widget with callbacks.
use gooey::value::Dynamic; 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::widgets::Custom;
use gooey::Run; use gooey::Run;
use kludgine::figures::units::{Lp, UPx}; 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 /// This approach was added to make it easy to create one-off widgets in a
/// hierarchy to handle events or other purpose-built functions. /// 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 // This implementation and the impl `Widget` implementation both use the
// same Dynamic value setup. // same Dynamic value setup.
let toggle = Toggle::default(); let toggle = Toggle::default();
@ -44,18 +44,26 @@ fn callback_widget() -> impl MakeWidget {
.height(Lp::inches(1)) .height(Lp::inches(1))
} }
/// A second approach is to implement [`MakeWidget`] for a type. This allows any /// A second approach is to implement [`MakeWidgetWithId`] for a type. This
/// type to be used when composing your UI that know how to create a widget. /// 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 /// This enables using callback-based widgets (or any other combination of
/// widgets) in a reusable fashion. /// 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)] #[derive(Default)]
struct ToggleMakeWidget(Toggle); struct ToggleMakeWidget(Toggle);
impl MakeWidget for ToggleMakeWidget { impl MakeWidgetWithId for ToggleMakeWidget {
fn make_widget(self) -> gooey::widget::WidgetInstance { fn make_with_id(self, id: WidgetTag) -> WidgetInstance {
// In a real code base, the contents of callback_widget() would go here // 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 /// This is the lowest-level way to implement a Widget, but it also provides the
/// most power and flexibility. /// most power and flexibility.
fn impl_widget() -> impl MakeWidget { fn impl_widget() -> impl MakeWidgetWithId {
Toggle::default() Toggle::default()
} }

View file

@ -20,7 +20,7 @@ use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearIn
use crate::context::sealed::WindowHandle; use crate::context::sealed::WindowHandle;
use crate::context::{self, WidgetContext}; use crate::context::{self, WidgetContext};
use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone}; 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}; use crate::widgets::{Radio, Select, Space, Switcher};
/// An instance of a value that provides APIs to observe and react to its /// An instance of a value that provides APIs to observe and react to its
@ -607,20 +607,20 @@ impl Dynamic<WidgetInstance> {
} }
} }
impl MakeWidget for Dynamic<WidgetInstance> { impl MakeWidgetWithId for Dynamic<WidgetInstance> {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
self.switcher().make_widget() self.switcher().make_with_id(id)
} }
} }
impl MakeWidget for Dynamic<Option<WidgetInstance>> { impl MakeWidgetWithId for Dynamic<Option<WidgetInstance>> {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
self.map_each(|widget| { self.map_each(|widget| {
widget widget
.as_ref() .as_ref()
.map_or_else(|| Space::clear().make_widget(), Clone::clone) .map_or_else(|| Space::clear().make_widget(), Clone::clone)
}) })
.make_widget() .make_with_id(id)
} }
} }

View file

@ -1077,9 +1077,9 @@ impl MakeWidget for WidgetInstance {
} }
} }
impl MakeWidget for Color { impl MakeWidgetWithId for Color {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: WidgetTag) -> WidgetInstance {
Space::colored(self).make_widget() Space::colored(self).make_with_id(id)
} }
} }

View file

@ -10,7 +10,7 @@ use kludgine::shapes::{PathBuilder, Shape, StrokeOptions};
use crate::context::{GraphicsContext, LayoutContext}; use crate::context::{GraphicsContext, LayoutContext};
use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor}; use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor};
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; 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::widgets::button::ButtonKind;
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -50,8 +50,8 @@ impl Checkbox {
} }
} }
impl MakeWidget for Checkbox { impl MakeWidgetWithId for Checkbox {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
CheckboxOrnament { CheckboxOrnament {
value: self.state.create_reader(), value: self.state.create_reader(),
} }
@ -63,7 +63,7 @@ impl MakeWidget for Checkbox {
*value = !*value; *value = !*value;
}) })
.kind(self.kind) .kind(self.kind)
.make_widget() .make_with_id(id)
} }
} }

View file

@ -8,7 +8,7 @@ use kludgine::{Color, DrawableExt};
use crate::context::{GraphicsContext, LayoutContext}; use crate::context::{GraphicsContext, LayoutContext};
use crate::styles::components::TextColor; use crate::styles::components::TextColor;
use crate::value::{Dynamic, Generation, IntoValue, Value}; use crate::value::{Dynamic, Generation, IntoValue, Value};
use crate::widget::{MakeWidget, Widget, WidgetInstance}; use crate::widget::{Widget, WidgetInstance};
use crate::ConstraintLimit; use crate::ConstraintLimit;
/// A read-only text widget. /// A read-only text widget.
@ -90,9 +90,9 @@ impl Widget for Label {
macro_rules! impl_make_widget { macro_rules! impl_make_widget {
($($type:ty),*) => { ($($type:ty),*) => {
$(impl MakeWidget for $type { $(impl crate::widget::MakeWidgetWithId for $type {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
Label::new(self).make_widget() Label::new(self).make_with_id(id)
} }
})* })*
}; };

View file

@ -10,7 +10,7 @@ use crate::animation::{
AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne, AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne,
}; };
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; 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::slider::Slidable;
use crate::widgets::Data; use crate::widgets::Data;
@ -47,8 +47,8 @@ pub enum Progress<T = ZeroToOne> {
Percent(T), Percent(T),
} }
impl MakeWidget for ProgressBar { impl MakeWidgetWithId for ProgressBar {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
let start = Dynamic::new(ZeroToOne::ZERO); let start = Dynamic::new(ZeroToOne::ZERO);
let end = Dynamic::new(ZeroToOne::ZERO); let end = Dynamic::new(ZeroToOne::ZERO);
let value = (&start, &end).map_each(|(start, end)| *start..=*end); let value = (&start, &end).map_each(|(start, end)| *start..=*end);
@ -61,7 +61,7 @@ impl MakeWidget for ProgressBar {
&end, &end,
); );
let slider = value.slider().knobless().non_interactive(); let slider = value.slider().knobless().non_interactive().make_with_id(id);
match self.progress { match self.progress {
Value::Dynamic(progress) => { Value::Dynamic(progress) => {
progress.for_each(move |progress| { progress.for_each(move |progress| {

View file

@ -10,7 +10,7 @@ use kludgine::DrawableExt;
use crate::context::{GraphicsContext, LayoutContext}; use crate::context::{GraphicsContext, LayoutContext};
use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor}; use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor};
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; 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::widgets::button::ButtonKind;
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -50,11 +50,11 @@ impl<T> Radio<T> {
} }
} }
impl<T> MakeWidget for Radio<T> impl<T> MakeWidgetWithId for Radio<T>
where where
T: Clone + Debug + Eq + UnwindSafe + Send + 'static, T: Clone + Debug + Eq + UnwindSafe + Send + 'static,
{ {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
RadioOrnament { RadioOrnament {
value: self.value.clone(), value: self.value.clone(),
state: self.state.create_reader(), state: self.state.create_reader(),
@ -66,7 +66,7 @@ where
self.state.set(self.value.clone()); self.state.set(self.value.clone());
}) })
.kind(self.kind) .kind(self.kind)
.make_widget() .make_with_id(id)
} }
} }

View file

@ -7,7 +7,7 @@ use kludgine::Color;
use crate::styles::components::OutlineColor; use crate::styles::components::OutlineColor;
use crate::styles::{Component, DynamicComponent}; use crate::styles::{Component, DynamicComponent};
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; 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}; use crate::widgets::button::{ButtonBackground, ButtonHoverBackground, ButtonKind};
/// A selectable, labeled widget representing a value. /// A selectable, labeled widget representing a value.
@ -45,11 +45,11 @@ impl<T> Select<T> {
} }
} }
impl<T> MakeWidget for Select<T> impl<T> MakeWidgetWithId for Select<T>
where where
T: Clone + Debug + Eq + RefUnwindSafe + UnwindSafe + Send + Sync + 'static, 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 selected = self.state.map_each({
let value = self.value.clone(); let value = self.value.clone();
move |state| state == &value move |state| state == &value
@ -79,7 +79,7 @@ where
.kind(kind) .kind(kind)
.with_dynamic(&ButtonBackground, selected_color.clone()) .with_dynamic(&ButtonBackground, selected_color.clone())
.with_dynamic(&ButtonHoverBackground, selected_color) .with_dynamic(&ButtonHoverBackground, selected_color)
.make_widget() .make_with_id(id)
} }
} }

View file

@ -5,7 +5,7 @@ use kludgine::Color;
use crate::styles::components::{LineHeight, OutlineColor, TextColor, TextSize}; use crate::styles::components::{LineHeight, OutlineColor, TextColor, TextSize};
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Validation, Value}; 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. /// A widget that displays validation information around another widget.
/// ///
@ -42,8 +42,8 @@ impl Validated {
} }
} }
impl MakeWidget for Validated { impl MakeWidgetWithId for Validated {
fn make_widget(self) -> WidgetInstance { fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
let message = match self.hint { let message = match self.hint {
Value::Constant(hint) => self Value::Constant(hint) => self
.validation .validation
@ -81,7 +81,7 @@ impl MakeWidget for Validated {
error_color, error_color,
default_color, default_color,
} }
.make_widget() .make_with_id(id)
} }
} }