Skip to content

Commit

Permalink
feat(core): 🎸 added smooth widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo committed Nov 1, 2024
1 parent c57834c commit 04fa7bb
Show file tree
Hide file tree
Showing 18 changed files with 252 additions and 146 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Features

- **core**: Added the smooth widgets for transitioning the layout position and size. (#645 @M-Adoo)

## [0.4.0-alpha.14] - 2024-10-30

### Features
Expand Down
32 changes: 31 additions & 1 deletion core/src/animation/animate_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::convert::Infallible;
use rxrust::{observable::ObservableExt, ops::box_it::BoxOp, prelude::BoxIt};

use super::*;
use crate::state::{ModifyScope, StateWatcher, StateWriter};
use crate::prelude::*;

/// Trait to help animate update the state.
pub trait AnimateStateSetter {
Expand All @@ -19,6 +19,36 @@ pub trait AnimateStateSetter {
/// Trait to help animate calc the lerp value.
pub trait AnimateState: AnimateStateSetter {
fn calc_lerp_value(&mut self, from: &Self::Value, to: &Self::Value, rate: f32) -> Self::Value;

/// Use an animate to transition the state after it modified.
fn transition(
self, transition: impl Transition + 'static, ctx: &BuildCtx,
) -> Stateful<Animate<Self>>
where
Self: Sized,
Self::Value: PartialEq,
{
let state = self.clone_setter();
let animate = Animate::declarer()
.transition(Box::new(transition))
.from(self.get())
.state(self)
.finish(ctx);

let c_animate = animate.clone_writer();
let init_value = observable::of(state.get());
state
.animate_state_modifies()
.map(move |_| state.get())
.merge(init_value)
.distinct_until_changed()
.pairwise()
.subscribe(move |(old, _)| {
animate.write().from = old;
animate.run();
});
c_animate
}
}

/// A state with a lerp function as an animation state that use the `lerp_fn`
Expand Down
48 changes: 0 additions & 48 deletions core/src/animation/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,54 +23,6 @@ pub struct RepeatTransition<T> {
pub transition: T,
}

/// Trait help to transition the state.
pub trait TransitionState: Sized + 'static {
/// Use an animate to transition the state after it modified.
fn transition(
self, transition: impl Transition + 'static, ctx: &BuildCtx,
) -> Stateful<Animate<Self>>
where
Self: AnimateState,
{
let state = self.clone_setter();
let animate = Animate::declarer()
.transition(Box::new(transition))
.from(self.get())
.state(self)
.finish(ctx);

let c_animate = animate.clone_writer();
let init_value = observable::of(state.get());
state
.animate_state_modifies()
.map(move |_| state.get())
.merge(init_value)
.pairwise()
.subscribe(move |(old, _)| {
animate.write().from = old;
animate.run();
});
c_animate
}
}

impl<S: AnimateState + 'static> TransitionState for S {}

/// Transition the state with a lerp function.
pub trait TransitionWithFn: AnimateStateSetter + Sized {
fn transition_with<F>(
self, transition: Box<dyn Transition>, lerp_fn: F, ctx: &BuildCtx,
) -> Stateful<Animate<LerpFnState<Self, F>>>
where
F: FnMut(&Self::Value, &Self::Value, f32) -> Self::Value + 'static,
{
let animate_state = LerpFnState::new(self, lerp_fn);
animate_state.transition(transition, ctx)
}
}

impl<S> TransitionWithFn for S where S: AnimateStateSetter {}

/// Transition is a trait to help you calc the rate of change over time.
pub trait Transition {
/// Calc the rate of change of the duration from animation start.
Expand Down
2 changes: 2 additions & 0 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ mod constrained_box;
pub use constrained_box::*;
mod text_style;
pub use text_style::*;
mod smooth_layout;
pub use smooth_layout::*;

use crate::prelude::*;

Expand Down
19 changes: 3 additions & 16 deletions core/src/builtin_widgets/align.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// A enum that describe how widget align to its box.
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -77,21 +77,8 @@ impl Declare for VAlignWidget {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for HAlignWidget {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}

impl<'c> ComposeChild<'c> for VAlignWidget {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(HAlignWidget);
impl_compose_child_for_wrap_render!(VAlignWidget);

impl WrapRender for HAlignWidget {
fn perform_layout(&self, mut clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/anchor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// Specifies the horizontal position you want to anchor the widget.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -171,13 +171,7 @@ impl Declare for RelativeAnchor {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for RelativeAnchor {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(RelativeAnchor);

impl WrapRender for RelativeAnchor {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
12 changes: 3 additions & 9 deletions core/src/builtin_widgets/box_decoration.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// The BoxDecoration provides configuration options to draw the background and
/// border of a box.
Expand Down Expand Up @@ -36,19 +36,13 @@ pub struct BorderSide {
pub width: f32,
}

impl<'c> ComposeChild<'c> for BoxDecoration {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}

impl BorderSide {
#[inline]
pub fn new(width: f32, color: Brush) -> Self { Self { width, color } }
}

impl_compose_child_for_wrap_render!(BoxDecoration);

impl WrapRender for BoxDecoration {
#[inline]
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/constrained_box.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// a widget that imposes additional constraints clamp on its child.
#[derive(Clone, Default)]
Expand All @@ -12,13 +12,7 @@ impl Declare for ConstrainedBox {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for ConstrainedBox {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(ConstrainedBox);

impl WrapRender for ConstrainedBox {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/foreground.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// A widget that sets the brush for foreground elements. It's can be inherited
/// by its descendants. When meet a color of `background`, the foreground will
Expand All @@ -15,13 +15,7 @@ impl Declare for Foreground {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for Foreground {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(Foreground);

impl WrapRender for Foreground {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/ignore_pointer.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

#[derive(Declare, Clone)]
pub struct IgnorePointer {
#[declare(default = true)]
pub ignore: bool,
}

impl<'c> ComposeChild<'c> for IgnorePointer {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(IgnorePointer);

impl WrapRender for IgnorePointer {
#[inline]
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/opacity.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

#[derive(Clone)]
pub struct Opacity {
Expand All @@ -16,13 +16,7 @@ impl Default for Opacity {
fn default() -> Self { Self { opacity: 1.0 } }
}

impl<'c> ComposeChild<'c> for Opacity {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(Opacity);

impl WrapRender for Opacity {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/padding.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// A widget that insets its child by the given padding.
#[derive(Default)]
Expand All @@ -12,13 +12,7 @@ impl Declare for Padding {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for Padding {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(Padding);

impl WrapRender for Padding {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
10 changes: 2 additions & 8 deletions core/src/builtin_widgets/painting_style.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{prelude::*, wrap_render::WrapRender};
use crate::{prelude::*, wrap_render::*};

/// Explain the method for rendering shapes and paths, including filling or
/// stroking them.
Expand All @@ -24,13 +24,7 @@ impl Declare for PaintingStyleWidget {
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for PaintingStyleWidget {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}
impl_compose_child_for_wrap_render!(PaintingStyleWidget);

impl WrapRender for PaintingStyleWidget {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
Expand Down
Loading

0 comments on commit 04fa7bb

Please sign in to comment.