Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): 🎸 added smooth widgets #645

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading