mirror of
https://github.com/danbulant/cushy
synced 2026-06-20 15:01:11 +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.
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
|||
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::{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<WidgetInstance> {
|
|||
}
|
||||
}
|
||||
|
||||
impl MakeWidget for Dynamic<WidgetInstance> {
|
||||
fn make_widget(self) -> WidgetInstance {
|
||||
self.switcher().make_widget()
|
||||
impl MakeWidgetWithId for Dynamic<WidgetInstance> {
|
||||
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
|
||||
self.switcher().make_with_id(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl MakeWidget for Dynamic<Option<WidgetInstance>> {
|
||||
fn make_widget(self) -> WidgetInstance {
|
||||
impl MakeWidgetWithId for Dynamic<Option<WidgetInstance>> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})*
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<T = ZeroToOne> {
|
|||
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| {
|
||||
|
|
|
|||
|
|
@ -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<T> Radio<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> MakeWidget for Radio<T>
|
||||
impl<T> MakeWidgetWithId for Radio<T>
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<T> Select<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> MakeWidget for Select<T>
|
||||
impl<T> MakeWidgetWithId for Select<T>
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue