Added to_ variants for into_ functions

This commit is contained in:
Jonathan Johnson 2024-01-02 15:05:52 -08:00
parent 8bcbad959b
commit 244797110e
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
20 changed files with 122 additions and 51 deletions

View file

@ -36,8 +36,7 @@ fn main() -> cushy::Result {
// Create a new label displaying `count` // Create a new label displaying `count`
count count
.clone() .to_label()
.into_label()
// Use the label as the contents of a button // Use the label as the contents of a button
.into_button() .into_button()
// Set the `on_click` callback to a closure that increments the counter. // Set the `on_click` callback to a closure that increments the counter.

View file

@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Label` has been refactored to accept any `Display` type. As a result of this, - `Label` has been refactored to accept any `Display` type. As a result of this,
`Label::text` is now named `display` and `Label::new()` now accepts an `Label::text` is now named `display` and `Label::new()` now accepts an
`IntoReadOnly<T>` instead of `IntoValue<String>`. `IntoReadOnly<T>` instead of `IntoValue<String>`.
- `Dynamic<Children>::wrap` has been renamed to `into_wrap` for consistency.
### Fixed ### Fixed
@ -110,6 +111,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`Mutex`. `Owned<T>` implements `Source<T>` and `Destination<T>`. `Mutex`. `Owned<T>` implements `Source<T>` and `Destination<T>`.
- `GenerationalValue<T>` now implements `Default` when `T` does. - `GenerationalValue<T>` now implements `Default` when `T` does.
- `Value<T>` now implements `From<Dynamic<T>>`. - `Value<T>` now implements `From<Dynamic<T>>`.
- Most `into_` functions that create widgets now have `to_` variations that
clone `self` before calling the `into_` function. This has only been done in
situations where it is known or likely that the clone being performed is
cheap.
[99]: https://github.com/khonsulabs/cushy/issues/99 [99]: https://github.com/khonsulabs/cushy/issues/99
[120]: https://github.com/khonsulabs/cushy/issues/120 [120]: https://github.com/khonsulabs/cushy/issues/120

View file

@ -38,8 +38,7 @@ fn main() -> cushy::Result {
// Create a new label displaying `count` // Create a new label displaying `count`
count count
.clone() .to_label()
.into_label()
// Use the label as the contents of a button // Use the label as the contents of a button
.into_button() .into_button()
// Set the `on_click` callback to a closure that increments the counter. // Set the `on_click` callback to a closure that increments the counter.

View file

@ -9,8 +9,7 @@ fn main() -> cushy::Result {
// Create a new label displaying `count` // Create a new label displaying `count`
count count
.clone() .to_label()
.into_label()
// Use the label as the contents of a button // Use the label as the contents of a button
.into_button() .into_button()
// Set the `on_click` callback to a closure that increments the counter. // Set the `on_click` callback to a closure that increments the counter.

View file

@ -9,7 +9,7 @@ fn main() -> cushy::Result {
checkbox_state checkbox_state
.clone() .clone()
.into_checkbox(label) .to_checkbox(label)
.and("Maybe".into_button().on_click(move |()| { .and("Maybe".into_button().on_click(move |()| {
checkbox_state.set(CheckboxState::Indeterminant); checkbox_state.set(CheckboxState::Indeterminant);
})) }))

View file

@ -10,8 +10,7 @@ fn main() -> cushy::Result {
let collapse = Dynamic::new(false); let collapse = Dynamic::new(false);
collapse collapse
.clone() .to_checkbox("Collapse")
.into_checkbox("Collapse")
.and( .and(
"Content Above" "Content Above"
.contain() .contain()

View file

@ -76,11 +76,11 @@ fn edit_contact_form(contact: &Contact, db: &Dynamic<HashMap<u64, Contact>>) ->
let title = Dynamic::new(contact.title.clone()); let title = Dynamic::new(contact.title.clone());
"First Name" "First Name"
.and(first.clone().into_input()) .and(first.to_input())
.and("Last Name") .and("Last Name")
.and(last.clone().into_input()) .and(last.to_input())
.and("Title") .and("Title")
.and(title.clone().into_input()) .and(title.to_input())
.and( .and(
"Save" "Save"
.into_button() .into_button()

View file

@ -7,8 +7,7 @@ fn main() -> cushy::Result {
let counter = Dynamic::new(0i32); let counter = Dynamic::new(0i32);
counter counter
.clone() .to_label()
.into_label()
.width(Lp::points(100)) .width(Lp::points(100))
.and("+".into_button().on_click(counter.with_clone(|counter| { .and("+".into_button().on_click(counter.with_clone(|counter| {
move |_| { move |_| {

View file

@ -22,15 +22,9 @@ fn main() -> cushy::Result {
let (cancel_tag, cancel_id) = WidgetTag::new(); let (cancel_tag, cancel_id) = WidgetTag::new();
let (username_tag, username_id) = WidgetTag::new(); let (username_tag, username_id) = WidgetTag::new();
let username_row = ( let username_row = ("Username", username.to_input().make_with_tag(username_tag));
"Username",
username.clone().into_input().make_with_tag(username_tag),
);
let password_row = ( let password_row = ("Password", password.to_input().with_next_focus(login_id));
"Password",
password.clone().into_input().with_next_focus(login_id),
);
let buttons = "Cancel" let buttons = "Cancel"
.into_button() .into_button()

View file

@ -17,19 +17,21 @@ fn main() -> cushy::Result {
.and(Color::RED.expand_weighted(2)) .and(Color::RED.expand_weighted(2))
.into_columns() .into_columns()
.expand() .expand()
.and(chat_message.clone().into_input().on_key(move |input| { .and(
match (input.state, input.logical_key) { chat_message
(ElementState::Pressed, Key::Named(NamedKey::Enter)) => { .to_input()
let new_message = chat_message.take(); .on_key(move |input| match (input.state, input.logical_key) {
chat_log.map_mut(|mut chat_log| { (ElementState::Pressed, Key::Named(NamedKey::Enter)) => {
chat_log.push_str(&new_message); let new_message = chat_message.take();
chat_log.push('\n'); chat_log.map_mut(|mut chat_log| {
}); chat_log.push_str(&new_message);
HANDLED chat_log.push('\n');
} });
_ => IGNORED, HANDLED
} }
})) _ => IGNORED,
}),
)
.into_rows() .into_rows()
.expand() .expand()
.run() .run()

View file

@ -18,8 +18,7 @@ fn main() -> cushy::Result {
.align_left() .align_left()
.and( .and(
username username
.clone() .to_input()
.into_input()
.placeholder("Username") .placeholder("Username")
.validation(validations.validate(&username, |u: &String| { .validation(validations.validate(&username, |u: &String| {
if u.is_empty() { if u.is_empty() {
@ -40,8 +39,7 @@ fn main() -> cushy::Result {
.align_left() .align_left()
.and( .and(
password password
.clone() .to_input()
.into_input()
.placeholder("Password") .placeholder("Password")
.validation( .validation(
validations.validate(&password, |u: &MaskedString| match u.len() { validations.validate(&password, |u: &MaskedString| match u.len() {

View file

@ -206,8 +206,7 @@ fn optional_editor(label: &str, color: &Dynamic<ColorSource>) -> (Dynamic<bool>,
( (
enabled.clone(), enabled.clone(),
enabled enabled
.clone() .to_checkbox(swatch_label(label, color))
.into_checkbox(swatch_label(label, color))
.and(color_editor(color).collapse_vertically(hide_editor)) .and(color_editor(color).collapse_vertically(hide_editor))
.into_rows(), .into_rows(),
) )

View file

@ -194,7 +194,6 @@ fn square(row: usize, column: usize, game: &Dynamic<GameState>) -> impl MakeWidg
}); });
label label
.clone()
.into_button() .into_button()
.kind(ButtonKind::Outline) .kind(ButtonKind::Outline)
.on_click(move |_| game.lock().play(row, column)) .on_click(move |_| game.lock().play(row, column))

View file

@ -10,15 +10,13 @@ fn main() -> cushy::Result {
"Hinted" "Hinted"
.and( .and(
text.clone() text.to_input()
.into_input()
.validation(validations.validate(&text, validate_input)) .validation(validations.validate(&text, validate_input))
.hint("* required"), .hint("* required"),
) )
.and("Not Hinted") .and("Not Hinted")
.and( .and(
text.clone() text.to_input()
.into_input()
.validation(validations.validate(&text, validate_input)), .validation(validations.validate(&text, validate_input)),
) )
.and( .and(

View file

@ -345,6 +345,14 @@ pub trait IntoAnimate: Sized + Send + Sync {
/// Return this change as a running animation. /// Return this change as a running animation.
fn into_animate(self) -> Self::Animate; fn into_animate(self) -> Self::Animate;
/// Returns a clone of this change as a running animation.
fn to_animate(&self) -> Self::Animate
where
Self: Clone,
{
self.clone().into_animate()
}
/// Returns an combined animation that performs `self` and `other` in /// Returns an combined animation that performs `self` and `other` in
/// sequence. /// sequence.
fn and_then<Other: IntoAnimate>(self, other: Other) -> Chain<Self, Other> { fn and_then<Other: IntoAnimate>(self, other: Other) -> Chain<Self, Other> {
@ -674,7 +682,7 @@ where
} }
if self.keep_cycling() { if self.keep_cycling() {
self.running = Some(self.animation.clone().into_animate()); self.running = Some(self.animation.to_animate());
} else { } else {
self.running = None; self.running = None;
return ControlFlow::Break(elapsed); return ControlFlow::Break(elapsed);

View file

@ -1164,9 +1164,32 @@ impl Dynamic<WidgetInstance> {
/// Returns a new [`Switcher`] widget whose contents is the value of this /// Returns a new [`Switcher`] widget whose contents is the value of this
/// dynamic. /// dynamic.
#[must_use] #[must_use]
pub fn into_switcher(self) -> Switcher {
self.into_reader().into_switcher()
}
/// Returns a new [`Switcher`] widget whose contents is the value of this
/// dynamic.
#[must_use]
pub fn to_switcher(&self) -> Switcher {
self.create_reader().into_switcher()
}
}
impl DynamicReader<WidgetInstance> {
/// Returns a new [`Switcher`] widget whose contents is the value of this
/// dynamic reader.
#[must_use]
pub fn into_switcher(self) -> Switcher { pub fn into_switcher(self) -> Switcher {
Switcher::new(self) Switcher::new(self)
} }
/// Returns a new [`Switcher`] widget whose contents is the value of this
/// dynamic reader.
#[must_use]
pub fn to_switcher(&self) -> Switcher {
Switcher::new(self.clone())
}
} }
impl MakeWidgetWithTag for Dynamic<WidgetInstance> { impl MakeWidgetWithTag for Dynamic<WidgetInstance> {
@ -2261,6 +2284,15 @@ pub trait IntoReader<T> {
{ {
Label::new(self.into_reader()) Label::new(self.into_reader())
} }
/// Returns `self` being `Display`ed in a [`Label`] widget.
fn to_label(&self) -> Label<T>
where
Self: Clone,
T: Debug + Display + Send + 'static,
{
self.clone().into_label()
}
} }
impl<T> IntoReader<T> for Dynamic<T> { impl<T> IntoReader<T> for Dynamic<T> {

View file

@ -2074,12 +2074,24 @@ impl Dynamic<Children> {
Stack::rows(self) Stack::rows(self)
} }
/// Returns `self` as a vertical [`Stack`] of rows.
#[must_use]
pub fn to_rows(&self) -> Stack {
self.clone().into_rows()
}
/// Returns `self` as a horizontal [`Stack`] of columns. /// Returns `self` as a horizontal [`Stack`] of columns.
#[must_use] #[must_use]
pub fn into_columns(self) -> Stack { pub fn into_columns(self) -> Stack {
Stack::columns(self) Stack::columns(self)
} }
/// Returns `self` as a horizontal [`Stack`] of columns.
#[must_use]
pub fn to_columns(&self) -> Stack {
self.clone().into_columns()
}
/// Returns `self` as [`Layers`], with the widgets being stacked in the Z /// Returns `self` as [`Layers`], with the widgets being stacked in the Z
/// direction. /// direction.
#[must_use] #[must_use]
@ -2087,12 +2099,26 @@ impl Dynamic<Children> {
Layers::new(self) Layers::new(self)
} }
/// Returns `self` as [`Layers`], with the widgets being stacked in the Z
/// direction.
#[must_use]
pub fn to_layers(&self) -> Layers {
self.clone().into_layers()
}
/// Returns a [`Wrap`] that lays the children out horizontally, wrapping /// Returns a [`Wrap`] that lays the children out horizontally, wrapping
/// into additional rows as needed. /// into additional rows as needed.
#[must_use] #[must_use]
pub fn wrap(self) -> Wrap { pub fn into_wrap(self) -> Wrap {
Wrap::new(self) Wrap::new(self)
} }
/// Returns a [`Wrap`] that lays the children out horizontally, wrapping
/// into additional rows as needed.
#[must_use]
pub fn to_wrap(&self) -> Wrap {
self.clone().into_wrap()
}
} }
impl<W> FromIterator<W> for Children impl<W> FromIterator<W> for Children

View file

@ -257,6 +257,14 @@ pub trait Checkable: IntoDynamic<CheckboxState> + Sized {
fn into_checkbox(self, label: impl MakeWidget) -> Checkbox { fn into_checkbox(self, label: impl MakeWidget) -> Checkbox {
Checkbox::new(self.into_dynamic(), label) Checkbox::new(self.into_dynamic(), label)
} }
/// Returns a new checkbox using `self` as the value and `label`.
fn to_checkbox(&self, label: impl MakeWidget) -> Checkbox
where
Self: Clone,
{
self.clone().into_checkbox(label)
}
} }
impl<T> Checkable for T where T: IntoDynamic<CheckboxState> {} impl<T> Checkable for T where T: IntoDynamic<CheckboxState> {}

View file

@ -1351,6 +1351,13 @@ where
fn into_input(self) -> Input<Storage> { fn into_input(self) -> Input<Storage> {
Input::new(self.into_dynamic()) Input::new(self.into_dynamic())
} }
/// Returns this string as a text input widget.
fn to_input(&self) -> Input<Storage>
where
Self: Clone,
{
self.clone().into_input()
}
} }
impl<T> InputValue<String> for T where T: IntoDynamic<String> {} impl<T> InputValue<String> for T where T: IntoDynamic<String> {}

View file

@ -3,7 +3,7 @@ use std::fmt::Debug;
use figures::Size; use figures::Size;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, Source}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoReader, Source};
use crate::widget::{WidgetInstance, WidgetRef, WrapperWidget}; use crate::widget::{WidgetInstance, WidgetRef, WrapperWidget};
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -36,8 +36,8 @@ impl Switcher {
/// Returns a new widget that replaces its contents with the result of /// Returns a new widget that replaces its contents with the result of
/// `widget_factory` each time `value` changes. /// `widget_factory` each time `value` changes.
#[must_use] #[must_use]
pub fn new(source: impl IntoDynamic<WidgetInstance>) -> Self { pub fn new(source: impl IntoReader<WidgetInstance>) -> Self {
let source = source.into_dynamic().into_reader(); let source = source.into_reader();
let child = WidgetRef::new(source.get()); let child = WidgetRef::new(source.get());
Self { source, child } Self { source, child }
} }