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`
count
.clone()
.into_label()
.to_label()
// Use the label as the contents of a button
.into_button()
// 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::text` is now named `display` and `Label::new()` now accepts an
`IntoReadOnly<T>` instead of `IntoValue<String>`.
- `Dynamic<Children>::wrap` has been renamed to `into_wrap` for consistency.
### 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>`.
- `GenerationalValue<T>` now implements `Default` when `T` does.
- `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
[120]: https://github.com/khonsulabs/cushy/issues/120

View file

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

View file

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

View file

@ -10,8 +10,7 @@ fn main() -> cushy::Result {
let collapse = Dynamic::new(false);
collapse
.clone()
.into_checkbox("Collapse")
.to_checkbox("Collapse")
.and(
"Content Above"
.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());
"First Name"
.and(first.clone().into_input())
.and(first.to_input())
.and("Last Name")
.and(last.clone().into_input())
.and(last.to_input())
.and("Title")
.and(title.clone().into_input())
.and(title.to_input())
.and(
"Save"
.into_button()

View file

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

View file

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

View file

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

View file

@ -18,8 +18,7 @@ fn main() -> cushy::Result {
.align_left()
.and(
username
.clone()
.into_input()
.to_input()
.placeholder("Username")
.validation(validations.validate(&username, |u: &String| {
if u.is_empty() {
@ -40,8 +39,7 @@ fn main() -> cushy::Result {
.align_left()
.and(
password
.clone()
.into_input()
.to_input()
.placeholder("Password")
.validation(
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()
.into_checkbox(swatch_label(label, color))
.to_checkbox(swatch_label(label, color))
.and(color_editor(color).collapse_vertically(hide_editor))
.into_rows(),
)

View file

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

View file

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

View file

@ -345,6 +345,14 @@ pub trait IntoAnimate: Sized + Send + Sync {
/// Return this change as a running animation.
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
/// sequence.
fn and_then<Other: IntoAnimate>(self, other: Other) -> Chain<Self, Other> {
@ -674,7 +682,7 @@ where
}
if self.keep_cycling() {
self.running = Some(self.animation.clone().into_animate());
self.running = Some(self.animation.to_animate());
} else {
self.running = None;
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
/// dynamic.
#[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 {
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> {
@ -2261,6 +2284,15 @@ pub trait IntoReader<T> {
{
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> {

View file

@ -2074,12 +2074,24 @@ impl Dynamic<Children> {
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.
#[must_use]
pub fn into_columns(self) -> Stack {
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
/// direction.
#[must_use]
@ -2087,12 +2099,26 @@ impl Dynamic<Children> {
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
/// into additional rows as needed.
#[must_use]
pub fn wrap(self) -> Wrap {
pub fn into_wrap(self) -> Wrap {
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

View file

@ -257,6 +257,14 @@ pub trait Checkable: IntoDynamic<CheckboxState> + Sized {
fn into_checkbox(self, label: impl MakeWidget) -> Checkbox {
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> {}

View file

@ -1351,6 +1351,13 @@ where
fn into_input(self) -> Input<Storage> {
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> {}

View file

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