mirror of
https://github.com/danbulant/cushy
synced 2026-06-23 00:22:39 +00:00
More fluent APIs
This commit is contained in:
parent
46a0758d09
commit
dd38fa7bf4
11 changed files with 189 additions and 131 deletions
|
|
@ -1,7 +1,6 @@
|
|||
use gooey::value::Dynamic;
|
||||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::button::ButtonKind;
|
||||
use gooey::widgets::{Button, Checkbox};
|
||||
use gooey::Run;
|
||||
|
||||
fn main() -> gooey::Result {
|
||||
|
|
@ -18,35 +17,39 @@ fn main() -> gooey::Result {
|
|||
clicked_label
|
||||
.clone()
|
||||
.and(
|
||||
Button::new("Normal Button")
|
||||
"Normal Button"
|
||||
.into_button()
|
||||
.on_click(
|
||||
clicked_label.with_clone(|label| {
|
||||
move |_| label.set(String::from("Clicked Normal Button"))
|
||||
}),
|
||||
)
|
||||
.and(
|
||||
Button::new("Outline Button")
|
||||
"Outline Button"
|
||||
.into_button()
|
||||
.on_click(clicked_label.with_clone(|label| {
|
||||
move |_| label.set(String::from("Clicked Outline Button"))
|
||||
}))
|
||||
.kind(ButtonKind::Outline),
|
||||
)
|
||||
.and(
|
||||
Button::new("Transparent Button")
|
||||
"Transparent Button"
|
||||
.into_button()
|
||||
.on_click(clicked_label.with_clone(|label| {
|
||||
move |_| label.set(String::from("Clicked Transparent Button"))
|
||||
}))
|
||||
.kind(ButtonKind::Transparent),
|
||||
)
|
||||
.and(
|
||||
Button::new("Default Button")
|
||||
"Default Button"
|
||||
.into_button()
|
||||
.on_click(clicked_label.with_clone(|label| {
|
||||
move |_| label.set(String::from("Clicked Default Button"))
|
||||
}))
|
||||
.kind(default_button_style)
|
||||
.into_default(),
|
||||
)
|
||||
.and(Checkbox::new(default_is_outline, "Set Default to Outline"))
|
||||
.and("Set Default to Outline".into_checkbox(default_is_outline))
|
||||
.into_columns(),
|
||||
)
|
||||
.into_rows()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use gooey::value::Dynamic;
|
||||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::checkbox::CheckboxState;
|
||||
use gooey::widgets::Checkbox;
|
||||
use gooey::widgets::checkbox::{Checkable, CheckboxState};
|
||||
use gooey::Run;
|
||||
|
||||
fn main() -> gooey::Result {
|
||||
let checkbox_state = Dynamic::new(CheckboxState::Checked);
|
||||
let label = checkbox_state.map_each(|state| format!("Check Me! Current: {state:?}"));
|
||||
|
||||
Checkbox::new(checkbox_state.clone(), label)
|
||||
checkbox_state
|
||||
.clone()
|
||||
.into_checkbox(label)
|
||||
.and("Maybe".into_button().on_click(move |()| {
|
||||
checkbox_state.update(CheckboxState::Indeterminant);
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use gooey::value::Dynamic;
|
|||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::input::InputValue;
|
||||
use gooey::widgets::slider::Slidable;
|
||||
use gooey::widgets::{Checkbox, Custom};
|
||||
use gooey::widgets::Custom;
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::Lp;
|
||||
|
||||
|
|
@ -14,10 +14,7 @@ fn main() -> gooey::Result {
|
|||
.and(Dynamic::<u8>::default().slider_between(0_u8, 100_u8))
|
||||
.and("Range Slider")
|
||||
.and(Dynamic::new(10..=30).slider_between(0_u8, 100_u8))
|
||||
.and(Checkbox::new(
|
||||
allow_blur.clone(),
|
||||
"Allow Custom Widget to Lose Focus",
|
||||
))
|
||||
.and("Allow Custom Widget to Lose Focus".into_checkbox(allow_blur.clone()))
|
||||
.and(
|
||||
Custom::empty()
|
||||
.on_accept_focus(|_| true)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use gooey::value::Dynamic;
|
||||
use gooey::widget::{MakeWidget, HANDLED, IGNORED};
|
||||
use gooey::widgets::input::InputValue;
|
||||
use gooey::widgets::Space;
|
||||
use gooey::Run;
|
||||
use kludgine::app::winit::event::ElementState;
|
||||
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
||||
|
|
@ -15,7 +14,7 @@ fn main() -> gooey::Result {
|
|||
.clone()
|
||||
.vertical_scroll()
|
||||
.expand()
|
||||
.and(Space::colored(Color::RED).expand_weighted(2))
|
||||
.and(Color::RED.expand_weighted(2))
|
||||
.into_columns()
|
||||
.expand()
|
||||
.and(chat_message.clone().into_input().on_key(move |input| {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use gooey::value::{Dynamic, MapEach};
|
|||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::progress::Progressable;
|
||||
use gooey::widgets::slider::Slidable;
|
||||
use gooey::widgets::Checkbox;
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::figures::Size;
|
||||
|
|
@ -17,7 +16,7 @@ fn main() -> gooey::Result {
|
|||
.clone()
|
||||
.slider()
|
||||
.and(progress.clone().progress_bar())
|
||||
.and(Checkbox::new(indeterminant.clone(), "Indeterminant"))
|
||||
.and("Indeterminant".into_checkbox(indeterminant))
|
||||
.into_rows()
|
||||
.fit_horizontally()
|
||||
.expand()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use gooey::animation::ZeroToOne;
|
||||
use gooey::styles::components::{TextColor, WidgetBackground};
|
||||
use gooey::styles::{
|
||||
ColorScheme, ColorSource, ColorTheme, FixedTheme, SurfaceTheme, Theme, ThemePair,
|
||||
|
|
@ -7,7 +6,6 @@ use gooey::value::{Dynamic, MapEach};
|
|||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::input::InputValue;
|
||||
use gooey::widgets::slider::Slidable;
|
||||
use gooey::widgets::{Slider, Stack};
|
||||
use gooey::window::ThemeMode;
|
||||
use gooey::Run;
|
||||
use kludgine::Color;
|
||||
|
|
@ -100,13 +98,12 @@ fn color_editor(
|
|||
|
||||
(
|
||||
color,
|
||||
Stack::rows(
|
||||
label
|
||||
.and(hue.slider_between(0., 360.))
|
||||
.and(hue_text.into_input())
|
||||
.and(Slider::<ZeroToOne>::from_value(saturation))
|
||||
.and(saturation_text.into_input()),
|
||||
),
|
||||
label
|
||||
.and(hue.slider_between(0., 360.))
|
||||
.and(hue_text.into_input())
|
||||
.and(saturation.slider())
|
||||
.and(saturation_text.into_input())
|
||||
.into_rows(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -179,83 +176,80 @@ fn theme(theme: Dynamic<Theme>, mode: ThemeMode) -> impl MakeWidget {
|
|||
fn surface_theme(theme: Dynamic<SurfaceTheme>) -> impl MakeWidget {
|
||||
let color = theme.map_each(|theme| theme.color);
|
||||
let on_color = theme.map_each(|theme| theme.on_color);
|
||||
Stack::rows(
|
||||
Stack::columns(
|
||||
swatch(color.clone(), "Surface", on_color.clone())
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.bright_color),
|
||||
"Bright Surface",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.dim_color),
|
||||
"Dim Surface",
|
||||
on_color.clone(),
|
||||
)),
|
||||
)
|
||||
|
||||
swatch(color.clone(), "Surface", on_color.clone())
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.bright_color),
|
||||
"Bright Surface",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.dim_color),
|
||||
"Dim Surface",
|
||||
on_color.clone(),
|
||||
))
|
||||
.into_columns()
|
||||
.contain()
|
||||
.expand()
|
||||
.and(
|
||||
Stack::columns(
|
||||
swatch(
|
||||
theme.map_each(|theme| theme.lowest_container),
|
||||
"Lowest Container",
|
||||
on_color.clone(),
|
||||
)
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.low_container),
|
||||
"Low Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.container),
|
||||
"Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.high_container),
|
||||
"High Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.highest_container),
|
||||
"Highest Container",
|
||||
on_color.clone(),
|
||||
)),
|
||||
swatch(
|
||||
theme.map_each(|theme| theme.lowest_container),
|
||||
"Lowest Container",
|
||||
on_color.clone(),
|
||||
)
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.low_container),
|
||||
"Low Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.container),
|
||||
"Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.high_container),
|
||||
"High Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.highest_container),
|
||||
"Highest Container",
|
||||
on_color.clone(),
|
||||
))
|
||||
.into_columns()
|
||||
.contain()
|
||||
.expand(),
|
||||
)
|
||||
.and(
|
||||
Stack::columns(
|
||||
swatch(on_color.clone(), "On Surface", color.clone())
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.on_color_variant),
|
||||
"On Color Variant",
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.outline),
|
||||
"Outline",
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.outline_variant),
|
||||
"Outline Variant",
|
||||
color,
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.opaque_widget),
|
||||
"Opaque Widget",
|
||||
on_color,
|
||||
)),
|
||||
)
|
||||
.contain()
|
||||
.expand(),
|
||||
),
|
||||
)
|
||||
.contain()
|
||||
.expand()
|
||||
swatch(on_color.clone(), "On Surface", color.clone())
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.on_color_variant),
|
||||
"On Color Variant",
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.outline),
|
||||
"Outline",
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.outline_variant),
|
||||
"Outline Variant",
|
||||
color,
|
||||
))
|
||||
.and(swatch(
|
||||
theme.map_each(|theme| theme.opaque_widget),
|
||||
"Opaque Widget",
|
||||
on_color,
|
||||
))
|
||||
.into_columns()
|
||||
.contain()
|
||||
.expand(),
|
||||
)
|
||||
.into_rows()
|
||||
.contain()
|
||||
.expand()
|
||||
}
|
||||
|
||||
fn color_theme(theme: Dynamic<ColorTheme>, label: &str) -> impl MakeWidget {
|
||||
|
|
@ -265,36 +259,36 @@ fn color_theme(theme: Dynamic<ColorTheme>, label: &str) -> impl MakeWidget {
|
|||
let on_color = theme.map_each(|theme| theme.on_color);
|
||||
let container = theme.map_each(|theme| theme.container);
|
||||
let on_container = theme.map_each(|theme| theme.on_container);
|
||||
Stack::rows(
|
||||
swatch(color.clone(), label, on_color.clone())
|
||||
.and(swatch(
|
||||
dim_color.clone(),
|
||||
&format!("{label} Dim"),
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
bright_color.clone(),
|
||||
&format!("{label} bright"),
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
on_color.clone(),
|
||||
&format!("On {label}"),
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
container.clone(),
|
||||
&format!("{label} Container"),
|
||||
on_container.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
on_container,
|
||||
&format!("On {label} Container"),
|
||||
container,
|
||||
)),
|
||||
)
|
||||
.contain()
|
||||
.expand()
|
||||
|
||||
swatch(color.clone(), label, on_color.clone())
|
||||
.and(swatch(
|
||||
dim_color.clone(),
|
||||
&format!("{label} Dim"),
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
bright_color.clone(),
|
||||
&format!("{label} bright"),
|
||||
on_color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
on_color.clone(),
|
||||
&format!("On {label}"),
|
||||
color.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
container.clone(),
|
||||
&format!("{label} Container"),
|
||||
on_container.clone(),
|
||||
))
|
||||
.and(swatch(
|
||||
on_container,
|
||||
&format!("On {label} Container"),
|
||||
container,
|
||||
))
|
||||
.into_rows()
|
||||
.contain()
|
||||
.expand()
|
||||
}
|
||||
|
||||
fn swatch(background: Dynamic<Color>, label: &str, text: Dynamic<Color>) -> impl MakeWidget {
|
||||
|
|
|
|||
|
|
@ -293,6 +293,12 @@ pub trait AnimationTarget: Sized + Send + Sync {
|
|||
fn over(self, duration: Duration) -> Animation<Self, Linear> {
|
||||
Animation::new(self, duration)
|
||||
}
|
||||
|
||||
/// Returns a pending animation that transitions to the target values after
|
||||
/// no delay.
|
||||
fn immediately(self) -> Animation<Self, Linear> {
|
||||
self.over(Duration::ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
/// The target of an [`Animate`] implementor.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ pub use self::tick::{InputState, Tick};
|
|||
pub enum ConstraintLimit {
|
||||
/// The widget is expected to occupy a known size.
|
||||
Fill(UPx),
|
||||
/// The widget is expected to resize itself to fit within the size provided.
|
||||
/// The widget is expected to resize itself to fit its contents, trying to
|
||||
/// stay within the size given.
|
||||
SizeToFit(UPx),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@ use crate::styles::{
|
|||
};
|
||||
use crate::tree::Tree;
|
||||
use crate::utils::IgnorePoison;
|
||||
use crate::value::{IntoValue, Value};
|
||||
use crate::value::{IntoDynamic, IntoValue, Value};
|
||||
use crate::widgets::checkbox::{Checkable, CheckboxState};
|
||||
use crate::widgets::{
|
||||
Align, Button, Container, Expand, Resize, Scroll, Stack, Style, Themed, ThemedMode,
|
||||
Align, Button, Checkbox, Container, Expand, Resize, Scroll, Space, Stack, Style, Themed,
|
||||
ThemedMode,
|
||||
};
|
||||
use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior};
|
||||
use crate::{ConstraintLimit, Run};
|
||||
|
|
@ -743,11 +745,16 @@ pub trait MakeWidget: Sized {
|
|||
Resize::from_height(height, self)
|
||||
}
|
||||
|
||||
/// Returns this string as a clickable button.
|
||||
/// Returns this widget as the contents of a clickable button.
|
||||
fn into_button(self) -> Button {
|
||||
Button::new(self)
|
||||
}
|
||||
|
||||
/// Returns this widget as the label of a Checkbox.
|
||||
fn into_checkbox(self, value: impl IntoDynamic<CheckboxState>) -> Checkbox {
|
||||
value.into_checkbox(self)
|
||||
}
|
||||
|
||||
/// Aligns `self` to the center vertically and horizontally.
|
||||
#[must_use]
|
||||
fn centered(self) -> Align {
|
||||
|
|
@ -875,6 +882,18 @@ impl MakeWidget for WidgetInstance {
|
|||
}
|
||||
}
|
||||
|
||||
impl MakeWidget for Color {
|
||||
fn make_widget(self) -> WidgetInstance {
|
||||
Space::colored(self).make_widget()
|
||||
}
|
||||
}
|
||||
|
||||
impl MakeWidget for () {
|
||||
fn make_widget(self) -> WidgetInstance {
|
||||
Space::clear().make_widget()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that represents whether an event has been handled or ignored.
|
||||
pub type EventHandling = ControlFlow<EventHandled, EventIgnored>;
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,26 @@ impl From<bool> for CheckboxState {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CheckboxState> for Option<bool> {
|
||||
fn from(value: CheckboxState) -> Self {
|
||||
match value {
|
||||
CheckboxState::Indeterminant => None,
|
||||
CheckboxState::Unchecked => Some(false),
|
||||
CheckboxState::Checked => Some(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<bool>> for CheckboxState {
|
||||
fn from(value: Option<bool>) -> Self {
|
||||
match value {
|
||||
Some(true) => CheckboxState::Checked,
|
||||
Some(false) => CheckboxState::Unchecked,
|
||||
None => CheckboxState::Indeterminant,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CheckboxState> for bool {
|
||||
type Error = CheckboxToBoolError;
|
||||
|
||||
|
|
@ -127,6 +147,15 @@ impl IntoDynamic<CheckboxState> for Dynamic<bool> {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoDynamic<CheckboxState> for Dynamic<Option<bool>> {
|
||||
fn into_dynamic(self) -> Dynamic<CheckboxState> {
|
||||
self.linked(
|
||||
|bool| CheckboxState::from(*bool),
|
||||
|tri_state: &CheckboxState| bool::try_from(*tri_state).ok(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`CheckboxState::Indeterminant`] was encountered when converting to a
|
||||
/// `bool`.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
|
|
@ -222,3 +251,13 @@ impl WrapperWidget for CheckboxLabel {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that can be used as a checkbox.
|
||||
pub trait Checkable: IntoDynamic<CheckboxState> + Sized {
|
||||
/// Returns a new checkbox using `self` as the value and `label`.
|
||||
fn into_checkbox(self, label: impl MakeWidget) -> Checkbox {
|
||||
Checkbox::new(self.into_dynamic(), label)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Checkable for T where T: IntoDynamic<CheckboxState> {}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ fn update_progress_bar(
|
|||
start.transition_to(ZeroToOne::ZERO),
|
||||
end.transition_to(ZeroToOne::ZERO),
|
||||
)
|
||||
.over(Duration::ZERO)
|
||||
.immediately()
|
||||
.and_then(
|
||||
end.transition_to(ZeroToOne::new(0.66))
|
||||
.over(Duration::from_millis(500))
|
||||
|
|
|
|||
Loading…
Reference in a new issue