mirror of
https://github.com/danbulant/cushy
synced 2026-07-07 20:20:46 +00:00
Refactored to MakeWidgetWithId
This commit is contained in:
parent
a826b91173
commit
8a4c66e73b
9 changed files with 50 additions and 42 deletions
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
src/value.rs
14
src/value.rs
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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| {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue