Skip to content

Commit

Permalink
More combinators
Browse files Browse the repository at this point in the history
Maybe I went overboard.
  • Loading branch information
ecton committed Nov 9, 2023
1 parent 8e26861 commit 22fb955
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 86 deletions.
14 changes: 8 additions & 6 deletions examples/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use std::time::Duration;

use gooey::animation::{AnimationHandle, AnimationTarget, IntoAnimate, Spawn};
use gooey::value::Dynamic;
use gooey::widget::MakeWidget;
use gooey::widgets::{Button, Label, Stack};
use gooey::{children, Run, WithClone};
use gooey::{Run, WithClone};

fn main() -> gooey::Result {
let animation = Dynamic::new(AnimationHandle::new());
Expand All @@ -17,11 +18,12 @@ fn main() -> gooey::Result {
.on_complete(|| println!("Gooey animations are neat!"))
.launch();

Stack::columns(children![
Button::new("To 0").on_click(animate_to(&animation, &value, 0)),
Label::new(label),
Button::new("To 100").on_click(animate_to(&animation, &value, 100)),
])
Stack::columns(
Button::new("To 0")
.on_click(animate_to(&animation, &value, 0))
.and(Label::new(label))
.and(Button::new("To 100").on_click(animate_to(&animation, &value, 100))),
)
.run()
}

Expand Down
33 changes: 18 additions & 15 deletions examples/counter.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
use std::string::ToString;

use gooey::value::Dynamic;
use gooey::widgets::{Align, Button, Expand, Label, Resize, Stack};
use gooey::{children, Run};
use gooey::widget::MakeWidget;
use gooey::widgets::{Button, Label, Resize, Stack};
use gooey::Run;
use kludgine::figures::units::Lp;

fn main() -> gooey::Result {
let counter = Dynamic::new(0i32);
let label = counter.map_each(ToString::to_string);
Expand::new(Align::centered(Stack::columns(children![
Resize::width(Lp::points(100), Label::new(label)),
Button::new("+").on_click(counter.with_clone(|counter| {
move |_| {
counter.set(counter.get() + 1);
}
})),
Button::new("-").on_click(counter.with_clone(|counter| {
move |_| {
counter.set(counter.get() - 1);
}
})),
])))
Stack::columns(
Resize::width(Lp::points(100), Label::new(label))
.and(Button::new("+").on_click(counter.with_clone(|counter| {
move |_| {
counter.set(counter.get() + 1);
}
})))
.and(Button::new("-").on_click(counter.with_clone(|counter| {
move |_| {
counter.set(counter.get() - 1);
}
}))),
)
.centered()
.expand()
.run()
}
29 changes: 15 additions & 14 deletions examples/gameui.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use gooey::value::Dynamic;
use gooey::widget::{MakeWidget, HANDLED, IGNORED};
use gooey::widgets::{Canvas, Expand, Input, Label, Scroll, Stack};
use gooey::{children, Run};
use gooey::widgets::{Canvas, Input, Label, Stack};
use gooey::Run;
use kludgine::app::winit::event::ElementState;
use kludgine::app::winit::keyboard::Key;
use kludgine::figures::{Point, Rect};
Expand All @@ -12,11 +12,9 @@ fn main() -> gooey::Result {
let chat_log = Dynamic::new("Chat log goes here.\n".repeat(100));
let chat_message = Dynamic::new(String::new());

Expand::new(Stack::rows(children![
Expand::new(Stack::columns(children![
Expand::new(Scroll::vertical(Label::new(chat_log.clone()))),
Expand::weighted(
2,
Stack::rows(
Stack::columns(
Label::new(chat_log.clone()).vertical_scroll().expand().and(
Canvas::new(|context| {
let entire_canvas = Rect::from(context.graphics.size());
context.graphics.draw_shape(
Expand All @@ -26,10 +24,12 @@ fn main() -> gooey::Result {
None,
);
})
)
])),
Input::new(chat_message.clone())
.on_key(move |input| match (input.state, input.logical_key) {
.expand_weighted(2),
),
)
.expand()
.and(Input::new(chat_message.clone()).on_key(move |input| {
match (input.state, input.logical_key) {
(ElementState::Pressed, Key::Enter) => {
let new_message = chat_message.map_mut(|text| std::mem::take(text));
chat_log.map_mut(|chat_log| {
Expand All @@ -39,8 +39,9 @@ fn main() -> gooey::Result {
HANDLED
}
_ => IGNORED,
})
.make_widget(),
]))
}
})),
)
.expand()
.run()
}
5 changes: 3 additions & 2 deletions examples/input.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use gooey::widgets::{Expand, Input};
use gooey::widget::MakeWidget;
use gooey::widgets::Input;
use gooey::Run;

fn main() -> gooey::Result {
Expand::new(Input::new("Hello")).run()
Input::new("Hello").expand().run()
}
67 changes: 37 additions & 30 deletions examples/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::process::exit;

use gooey::value::{Dynamic, MapEach};
use gooey::widget::MakeWidget;
use gooey::widgets::{Align, Button, Expand, Input, Label, Resize, Stack};
use gooey::{children, Run};
use gooey::widgets::{Button, Expand, Input, Label, Resize, Stack};
use gooey::Run;
use kludgine::figures::units::Lp;

fn main() -> gooey::Result {
Expand All @@ -13,42 +13,49 @@ fn main() -> gooey::Result {
let valid =
(&username, &password).map_each(|(username, password)| validate(username, password));

Expand::new(Align::centered(Resize::width(
Resize::width(
// TODO We need a min/max range for the Resize widget
Lp::points(400),
Stack::rows(children![
Stack::columns(children![
Label::new("Username"),
Expand::new(Align::centered(Input::new(username.clone())).fit_horizontally()),
]),
Stack::columns(children![
Label::new("Password"),
Expand::new(
Align::centered(
// TODO secure input
Input::new(password.clone())
)
.fit_horizontally()
Stack::rows(
Stack::columns(
Label::new("Username").and(
Input::new(username.clone())
.centered()
.fit_horizontally()
.expand(),
),
]),
Stack::columns(children![
)
.and(Stack::columns(
Label::new("Password").and(
// TODO secure input
Input::new(password.clone())
.centered()
.fit_horizontally()
.expand(),
),
))
.and(Stack::columns(
Button::new("Cancel")
.on_click(|_| {
eprintln!("Login cancelled");
exit(0)
})
.into_escape(),
Expand::empty(),
Button::new("Log In")
.enabled(valid)
.on_click(move |_| {
println!("Welcome, {}", username.get());
exit(0);
})
.into_default(),
]),
]),
)))
.into_escape()
.and(Expand::empty())
.and(
Button::new("Log In")
.enabled(valid)
.on_click(move |_| {
println!("Welcome, {}", username.get());
exit(0);
})
.into_default(),
),
)),
),
)
.centered()
.expand()
.run()
}

Expand Down
7 changes: 5 additions & 2 deletions examples/scroll.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use gooey::widgets::{Label, Scroll};
use gooey::widget::MakeWidget;
use gooey::widgets::Label;
use gooey::Run;

fn main() -> gooey::Result {
Scroll::new(Label::new(include_str!("../src/widgets/scroll.rs"))).run()
Label::new(include_str!("../src/widgets/scroll.rs"))
.scroll()
.run()
}
15 changes: 4 additions & 11 deletions examples/style.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
use gooey::styles::components::TextColor;
use gooey::styles::Styles;
use gooey::widget::{Children, MakeWidget, Widget};
use gooey::widget::{MakeWidget, Widget};
use gooey::widgets::stack::Stack;
use gooey::widgets::{Button, Style};
use gooey::window::Window;
use gooey::{styles, Run};
use kludgine::Color;

fn main() -> gooey::Result {
Window::for_widget(
Stack::rows(
Children::new()
.with_widget(Button::new("Default"))
.with_widget(red_text(Button::new("Styled"))),
)
.with_styles(Styles::new().with(&TextColor, Color::GREEN)),
)
.run()
Stack::rows(Button::new("Green").and(red_text(Button::new("Red"))))
.with_styles(Styles::new().with(&TextColor, Color::GREEN))
.run()
}

/// Creating reusable style helpers that work with any Widget is straightfoward
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub trait Run: Sized {
/// Creates a [`Children`](crate::widget::Children) instance with the given list
/// of widgets.
#[macro_export]
#[deprecated = "use MakeWidget.and()/Children.and() to chain widgets without a macro"]
macro_rules! children {
() => {
$crate::widget::Children::new()
Expand Down
4 changes: 2 additions & 2 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,8 @@ impl TreeData {
let node = &self.nodes[&perspective];
if let Some(styles) = &node.styles {
query.retain(|name| {
if let Some(component) = styles.get(name) {
resolved.insert(name, component.clone());
if let Some(component) = styles.get(dbg!(name)) {
resolved.insert(name, dbg!(component.clone()));
false
} else {
true
Expand Down
26 changes: 24 additions & 2 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,14 +752,36 @@ macro_rules! impl_tuple_for_each {
//
[$type:ident $field:tt $var:ident, $($rtype:ident $rfield:tt $rvar:ident),+]
) => {

impl_tuple_for_each!(
invoke
$self $for_each
$type $field $var
[$($ltype $lfield $lvar,)* $type $field $var, $($rtype $rfield $rvar),+]
[$($ltype $lfield $lvar,)* $($rtype $rfield $rvar),+]
)
);
impl_tuple_for_each!(
invoke
$self $for_each
[$($ltype $lfield $lvar,)* $type $field $var]
[$($rtype $rfield $rvar),+]
);
};
(
invoke
// Identifiers used from the outer method
$self:ident $for_each:ident
// List of all tuple fields that have already been positioned as the focused call
[$($ltype:ident $lfield:tt $lvar:ident),+]
//
[$type:ident $field:tt $var:ident]
) => {
impl_tuple_for_each!(
invoke
$self $for_each
$type $field $var
[$($ltype $lfield $lvar,)+ $type $field $var]
[$($ltype $lfield $lvar),+]
);
};
(
invoke
Expand Down
49 changes: 47 additions & 2 deletions src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::styles::components::VisualOrder;
use crate::styles::Styles;
use crate::tree::Tree;
use crate::value::{IntoValue, Value};
use crate::widgets::Style;
use crate::widgets::{Align, Expand, Scroll, Style};
use crate::window::{RunningWindow, Window, WindowBehavior};
use crate::{ConstraintLimit, Run};

Expand Down Expand Up @@ -479,6 +479,51 @@ pub trait MakeWidget: Sized {
fn into_escape(self) -> WidgetInstance {
self.make_widget().into_escape()
}

/// Returns a collection of widgets using `self` and `other`.
fn and(self, other: impl MakeWidget) -> Children {
let mut children = Children::new();
children.push(self);
children.push(other);
children
}

/// Expands `self` to grow to fill its parent.
#[must_use]
fn expand(self) -> Expand {
Expand::new(self)
}

/// Expands `self` to grow to fill its parent proportionally with other
/// weighted siblings.
#[must_use]
fn expand_weighted(self, weight: u8) -> Expand {
Expand::weighted(weight, self)
}

/// Aligns `self` to the center vertically and horizontally.
#[must_use]
fn centered(self) -> Align {
Align::centered(self)
}

/// Allows scrolling `self` both vertically and horizontally.
#[must_use]
fn scroll(self) -> Scroll {
Scroll::new(self)
}

/// Allows scrolling `self` vertically.
#[must_use]
fn vertical_scroll(self) -> Scroll {
Scroll::vertical(self)
}

/// Allows scrolling `self` horizontally.
#[must_use]
fn horizontal_scroll(self) -> Scroll {
Scroll::horizontal(self)
}
}

/// A type that can create a [`WidgetInstance`] with a preallocated
Expand Down Expand Up @@ -945,7 +990,7 @@ impl Children {
}

/// Adds `widget` to self and returns the updated list.
pub fn with_widget<W>(mut self, widget: W) -> Self
pub fn and<W>(mut self, widget: W) -> Self
where
W: MakeWidget,
{
Expand Down
Loading

0 comments on commit 22fb955

Please sign in to comment.