Skip to content

Commit

Permalink
Add common traits to views and related (e.g. Animatable)
Browse files Browse the repository at this point in the history
Also remove `WithState` trait as it's unnecessary and can be added in `ViewExt`
  • Loading branch information
Philipp-M committed Mar 10, 2024
1 parent 41831c0 commit f11f1ac
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::ops::Range;
/// Most often used by widgets to describe
/// the direction in which they grow as their number of children increases.
/// Has some methods for manipulating geometry with respect to the axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Axis {
/// The x axis
Horizontal,
Expand Down
44 changes: 43 additions & 1 deletion src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod text;
mod use_state;
mod weighted_linear_layout;

use std::marker::PhantomData;
use std::{marker::PhantomData, sync::Arc};

use ratatui::style::{Color, Style};
pub use xilem_core::{Id, IdPath, VecSplice};
Expand Down Expand Up @@ -61,6 +61,48 @@ pub trait ViewExt<T, A>: View<T, A> + Sized {
}
}

/// Compose a view with added local state.
/// The local state is added within a closure additional to the app state via a tuple.
/// It's initialized with the first closure.
///
/// # Examples
///
/// ```ignore
/// fn with_counter<T, V: View<T> + Clickable>(view: V) -> impl View<T> {
/// view.with_state(
/// || 42,
/// |view, local_state| {
/// v_stack((
/// format!("Click the view below to increment this: {local_state}"),
/// view.on_click(|(_app_state, local_state): &mut (Handle<T>, i32)| {
/// *local_state += 1;
/// }),
/// ))
/// },
/// )
/// }
/// ```
fn with_state<Vi, S, Finit, Vo, F>(
self,
init: Finit,
view_factory: F,
) -> WithLocalState<Finit, F, Vi, Vo>
where
Vi: View<T, A>,
Self: Into<Arc<Vi>>,
S: Send,
Finit: Fn() -> S + Send + Sync,
Vo: View<(Handle<T>, S), A>,
F: Fn(HandleState<Vi>, &mut S) -> Vo + Send + Sync,
{
WithLocalState {
init,
view: self.into(),
view_factory,
phantom: PhantomData,
}
}

/// # Examples
/// ```
/// # use trui::*;
Expand Down
7 changes: 5 additions & 2 deletions src/view/animatables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub trait Animatable<V>: Send + Sync {
) -> MessageResult<()>; // TODO different type (AnimationMessage?)
}

#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Lerp<T, R> {
tweenable: T,
ratio: R,
Expand Down Expand Up @@ -108,7 +108,7 @@ impl<V, T: Tweenable<V>, R: Animatable<f64>> Animatable<V> for Lerp<T, R> {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct LowPassIIR<AT> {
decay: f64,
target: AT,
Expand Down Expand Up @@ -463,6 +463,7 @@ impl_tweenable_for_tuple!(T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6, 7
impl_tweenable_for_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8; 0, 1, 2, 3, 4, 5, 6, 7, 8);
impl_tweenable_for_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Map<T, V, VO> {
input: T,
f: fn(&V) -> VO,
Expand Down Expand Up @@ -505,6 +506,7 @@ impl<V: Send + Sync + 'static, VO: Send + Sync + 'static, T: Tweenable<V>> Tween
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct MapEase<T> {
input: T,
f: fn(f64) -> f64,
Expand Down Expand Up @@ -548,6 +550,7 @@ impl<V, T: Tweenable<V>> Tweenable<V> for MapEase<T> {
// TODO should this also be used within other animatables directly (not just Tweenable)?
// TODO Duration could be animated too
/// Overrides the duration of any tweenable it composes
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct WithDuration<T> {
pub(crate) tweenable: T,
pub(crate) duration: Duration,
Expand Down
2 changes: 1 addition & 1 deletion src/view/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::{BorderKind, Borders, Cx, Styleable, View, ViewMarker};
use ratatui::style::{Color, Style};
use xilem_core::MessageResult;

#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Border<V, T, A> {
pub(crate) content: V,
pub(crate) borders: Borders,
Expand Down
7 changes: 7 additions & 0 deletions src/view/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ impl<T, A, E: Clone + 'static, E1: EventHandler<T, A, E>, E2: EventHandler<T, A,
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum StreamMessage<E> {
Begin(E),
Update(E),
Expand Down Expand Up @@ -200,6 +201,7 @@ impl<E: Send + 'static> StreamEventHandlerState<E> {
}
}

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct StreamEventHandler<T, A, E, S, SF, UF> {
#[allow(clippy::complexity)]
phantom: PhantomData<fn() -> (T, A, E, S)>,
Expand Down Expand Up @@ -281,6 +283,7 @@ where
}
}

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DeferEventHandler<T, A, FO, F, FF, CF> {
#[allow(clippy::complexity)]
phantom: PhantomData<fn() -> (T, A, FO, F)>,
Expand Down Expand Up @@ -376,6 +379,7 @@ impl_callback_event_handler!(widget::MouseEvent);

// TODO some description
// TODO Is this view useful at all? Should this be already abstracted (e.g. via the other views such as Hoverable, or Clickable)
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct OnMouse<V, EH> {
pub(crate) view: V,
pub(crate) catch_event: CatchMouseButton,
Expand Down Expand Up @@ -462,6 +466,7 @@ where
macro_rules! styled_event_views {
($($name:ident),*) => {
$(
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct $name<V> {
pub(crate) view: V,
pub(crate) style: Style,
Expand Down Expand Up @@ -630,6 +635,7 @@ styled_event_views!(StyleOnHover, StyleOnPressed);
macro_rules! event_views {
($($name:ident),*) => {
$(
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct $name<V, EH> {
pub(crate) view: V,
pub(crate) event_handler: EH,
Expand Down Expand Up @@ -742,6 +748,7 @@ macro_rules! event_views {
event_views!(OnHover, OnHoverLost);

// TODO this should probably be generated by the macro above (but for better IDE experience and easier prototyping this not yet)
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct OnClick<V, EH> {
pub(crate) view: V,
pub(crate) event_handler: EH,
Expand Down
2 changes: 2 additions & 0 deletions src/view/fill_max_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
Animatable, Cx, Fill, View, ViewMarker,
};

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FillMaxSize<V, P, T, A> {
pub(crate) content: V,
// TODO making this animatable would be great too
Expand Down Expand Up @@ -113,6 +114,7 @@ impl<T, A, P: Animatable<f64>, V: View<T, A>> View<T, A> for FillMaxSize<V, P, T
}
}

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FillMaxSizeStyle<P> {
pub fill: Fill,
pub percent: P,
Expand Down
1 change: 1 addition & 0 deletions src/view/linear_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
use std::{any::Any, marker::PhantomData};
use xilem_core::{Id, VecSplice};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LinearLayout<T, A, VT> {
children: VT,
axis: Axis,
Expand Down
2 changes: 2 additions & 0 deletions src/view/margin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
Cx, Position, View, ViewMarker,
};

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Margin<V, T, A> {
pub(crate) content: V,
pub(crate) amount: u16,
Expand Down Expand Up @@ -61,6 +62,7 @@ impl<T, A, V: View<T, A>> View<T, A> for Margin<V, T, A> {
}
}

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MarginStyle {
pub amount: u16,
pub position: Position,
Expand Down
1 change: 1 addition & 0 deletions src/view/scroll_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use xilem_core::{Id, MessageResult};

use super::{Cx, ViewMarker, ViewSequence};

#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ScrollView<T, A, C> {
child: C,
phantom: PhantomData<fn() -> (T, A)>,
Expand Down
55 changes: 8 additions & 47 deletions src/view/use_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{widget::ChangeFlags, Cx, View, ViewMarker};
/// This Handle is a workaround to erase the lifetime of &mut T,
/// it can only be constructed in contexts,
/// where it is actually safe to use (such as UseState)
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct Handle<T>(*mut T);

impl<T> Deref for Handle<T> {
Expand All @@ -37,6 +38,7 @@ impl<T> DerefMut for Handle<T> {
/// not rebuild). The second callback takes that state as an argument. It
/// is not passed the app state, but since that state is `Rc`, it would be
/// natural to clone it and capture it in a `move` closure.
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct UseState<T, A, S, V, FInit, F> {
f_init: FInit,
f: F,
Expand Down Expand Up @@ -126,49 +128,7 @@ where
UseState::new(f_init, f)
}

pub trait WithState<T, A, Vi: View<T, A>>: Into<Arc<Vi>> {
/// Compose a view with added local state.
/// The local state is added within a closure additional to the app state via a tuple.
/// It's initialized with the first closure.
///
/// # Examples
///
/// ```ignore
/// fn with_counter<T, V: View<T> + Clickable>(view: V) -> impl View<T> {
/// view.with_state(
/// || 42,
/// |view, local_state| {
/// v_stack((
/// format!("Click the view below to increment this: {local_state}"),
/// view.on_click(|(_app_state, local_state): &mut (Handle<T>, i32)| {
/// *local_state += 1;
/// }),
/// ))
/// },
/// )
/// }
/// ```
fn with_state<
S: Send,
Finit: Fn() -> S + Send + Sync,
Vo: View<(Handle<T>, S), A>,
F: Fn(HandleState<Vi>, &mut S) -> Vo + Send + Sync,
>(
self,
init: Finit,
view_factory: F,
) -> WithLocalState<Finit, F, Vi, Vo> {
WithLocalState {
init,
view: self.into(),
view_factory,
phantom: PhantomData,
}
}
}

impl<T, A, Vi: View<T, A>, V: Into<Arc<Vi>>> WithState<T, A, Vi> for V {}

#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)]
pub struct HandleState<V>(Arc<V>);

impl<V> ViewMarker for HandleState<V> {}
Expand Down Expand Up @@ -204,11 +164,12 @@ impl<T, A, V: View<T, A>, S> View<(Handle<T>, S), A> for HandleState<V> {
}
}

#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WithLocalState<Finit, F, Vi, Vo> {
init: Finit,
view: Arc<Vi>,
view_factory: F,
phantom: PhantomData<fn() -> (Vi, Vo)>,
pub(crate) init: Finit,
pub(crate) view: Arc<Vi>,
pub(crate) view_factory: F,
pub(crate) phantom: PhantomData<fn() -> (Vi, Vo)>,
}

impl<Vi, Vo, Finit, F> ViewMarker for WithLocalState<Finit, F, Vi, Vo> {}
Expand Down

0 comments on commit f11f1ac

Please sign in to comment.