Skip to content

Commit

Permalink
refactor: [tmp] state split as reader and writer
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo committed Sep 8, 2023
1 parent 4691848 commit 171892c
Show file tree
Hide file tree
Showing 64 changed files with 1,921 additions and 1,727 deletions.
89 changes: 39 additions & 50 deletions core/src/animation/animate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ where
pub transition: T,
#[declare(strict)]
pub state: S,
pub from: <S::State as Share>::V,
pub from: <S::State as StateReader>::Value,
#[declare(skip)]
running_info: Option<AnimateInfo<<S::State as Share>::V>>,
running_info: Option<AnimateInfo<<S::State as StateReader>::Value>>,
#[declare(skip, default = ctx.window().id())]
window_id: WindowId,
}

pub trait AnimateState {
type State: Share;
fn state(&mut self) -> &mut Self::State;
type State: StateWriter;
fn state(&self) -> &Self::State;

fn calc_lerp_value(
&mut self,
from: &<Self::State as Share>::V,
to: &<Self::State as Share>::V,
from: &<Self::State as StateReader>::Value,
to: &<Self::State as StateReader>::Value,
rate: f32,
) -> <Self::State as Share>::V;
) -> <Self::State as StateReader>::Value;
}

/// A state with a lerp function as an animation state that use the `lerp_fn`
Expand Down Expand Up @@ -55,47 +55,50 @@ impl<T, S> State<Animate<T, S>>
where
T: Roc + 'static,
S: AnimateState + 'static,
<S::State as Share>::V: Clone,
<S::State as StateReader>::Value: Clone,
{
pub fn run(&mut self) {
let mut animate_ref = self.state_ref();
let mut animate_ref = self.write();
let this = &mut *animate_ref;
let wnd_id = this.window_id;
let new_to = this.state.state().state_ref().clone();
let new_to = this.state.state().read().clone();

if let Some(AnimateInfo { from, to, last_progress, .. }) = &mut this.running_info {
*from = this.state.calc_lerp_value(from, to, last_progress.value());
*to = new_to;
} else if let Some(wnd) = AppCtx::get_window(wnd_id) {
drop(animate_ref);

let animate = self.clone_state();
let animate = self.clone_writer();
let ticker = wnd.frame_ticker.frame_tick_stream();
let unsub = ticker.subscribe(move |msg| {
match msg {
FrameMsg::NewFrame(time) => {
let p = animate.state_ref().shallow().rate_at_instant(time);
let p = animate.read().running_info.as_ref().unwrap().last_progress;
// Stop the animate at the next frame of animate finished, to ensure draw the
// last frame of the animate.
if matches!(p, AnimateProgress::Finish) {
let wnd = AppCtx::get_window(wnd_id).unwrap();
let animate = animate.clone_state();
let animate = animate.clone_writer();
wnd
.frame_spawn(async move { animate.state_ref().silent().stop() })
.frame_spawn(async move { animate.silent().stop() })
.unwrap();
} else {
animate.shallow().lerp_by_instant(time);
}
}
FrameMsg::LayoutReady(_) => {}
// use silent_ref because the state of animate change, bu no need to effect the framework.
FrameMsg::Finish(_) => {
let mut animate = animate.state_ref();
let animate = &mut **animate.silent();
let animate = &mut *animate.silent();
let info = animate.running_info.as_mut().unwrap();
**animate.state.state().state_ref().shallow() = info.to.clone();
*animate.state.state().shallow() = info.to.clone();
info.already_lerp = false;
}
}
});
let guard = BoxSubscription::new(unsub).unsubscribe_when_dropped();
let animate = &mut *self.state_ref();
let animate = &mut *self.write();
animate.running_info = Some(AnimateInfo {
from: animate.from.clone(),
to: new_to,
Expand All @@ -113,9 +116,9 @@ impl<T: Roc, S> Animate<T, S>
where
S: AnimateState + 'static,
{
fn rate_at_instant(&mut self, now: Instant) -> AnimateProgress
fn lerp_by_instant(&mut self, now: Instant) -> AnimateProgress
where
<S::State as Share>::V: Clone,
<S::State as StateReader>::Value: Clone,
{
let AnimateInfo {
from,
Expand All @@ -139,12 +142,12 @@ where
match progress {
AnimateProgress::Between(rate) => {
let value = self.state.calc_lerp_value(from, to, rate);
let state = &mut self.state.state().state_ref();
let state = &mut self.state.state().shallow();
// the state may change during animate.
*to = state.clone();
**state.shallow() = value;
**state = value;
}
AnimateProgress::Dismissed => **self.state.state().state_ref().shallow() = from.clone(),
AnimateProgress::Dismissed => *self.state.state().shallow() = from.clone(),
AnimateProgress::Finish => {}
}

Expand Down Expand Up @@ -180,48 +183,34 @@ where
}
}

impl<S> AnimateState for S
impl<V, S> AnimateState for S
where
S: Share,
S::V: Lerp,
S: StateWriter<Value = V>,
V: Lerp,
{
type State = S;

fn state(&mut self) -> &mut Self::State { self }
fn state(&self) -> &Self::State { self }

fn calc_lerp_value(
&mut self,
from: &<Self::State as Share>::V,
to: &<Self::State as Share>::V,
rate: f32,
) -> <Self::State as Share>::V {
from.lerp(to, rate)
}
fn calc_lerp_value(&mut self, from: &V, to: &V, rate: f32) -> V { from.lerp(to, rate) }
}

impl<S, F> AnimateState for LerpFnState<S, F>
impl<V, S, F> AnimateState for LerpFnState<S, F>
where
S: Share,
F: FnMut(&<S as Share>::V, &<S as Share>::V, f32) -> <S as Share>::V,
S: StateWriter<Value = V>,
F: FnMut(&V, &V, f32) -> V,
{
type State = S;

fn state(&mut self) -> &mut Self::State { &mut self.state }
fn state(&self) -> &Self::State { &self.state }

fn calc_lerp_value(
&mut self,
from: &<Self::State as Share>::V,
to: &<Self::State as Share>::V,
rate: f32,
) -> <Self::State as Share>::V {
(self.lerp_fn)(from, to, rate)
}
fn calc_lerp_value(&mut self, from: &V, to: &V, rate: f32) -> V { (self.lerp_fn)(from, to, rate) }
}

impl<S, F> LerpFnState<S, F>
impl<V, S, F> LerpFnState<S, F>
where
S: Share,
F: FnMut(&<S as Share>::V, &<S as Share>::V, f32) -> <S as Share>::V,
S: StateReader<Value = V>,
F: FnMut(&V, &V, f32) -> V,
{
#[inline]
pub fn new(state: S, lerp_fn: F) -> Self { Self { state, lerp_fn } }
Expand Down
52 changes: 23 additions & 29 deletions core/src/animation/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,30 @@ pub struct Transition<E: 'static> {
/// Trait help to transition the state.
pub trait TransitionState: Sized + 'static {
/// Use an animate to transition the state after it modified.
fn transition<T: Roc + 'static>(
mut self,
transition: T,
ctx: &BuildCtx,
) -> State<Animate<T, Self>>
fn transition<T: Roc + 'static>(self, transition: T, ctx: &BuildCtx) -> Writer<Animate<T, Self>>
where
Self: AnimateState,
<Self::State as Share>::V: Clone,
<Self::State as StateReader>::Value: Clone,
{
let state = self.state().clone_state();

let from = state.state_ref().clone();
let state = self.state().clone_writer();
let from = state.read().clone();
let mut animate: State<Animate<T, Self>> = Animate::declare2_builder()
.transition(transition)
.from(from)
.state(self)
.build_declare(ctx);

let c_animate = animate.clone_state();
let h = state
let c_animate = animate.clone_writer();
let init_value = observable::of(state.read().clone());
state
.modifies()
.map(move |_| state.state_ref().clone())
.map(move |_| state.read().clone())
.merge(init_value)
.pairwise()
.subscribe(move |(old, _)| {
animate.state_ref().from = old;
animate.write().from = old;
animate.run();
})
.unsubscribe_when_dropped();
c_animate.own_data(h);
});
c_animate
}

Expand All @@ -56,11 +51,11 @@ pub trait TransitionState: Sized + 'static {
transition: T,
lerp_fn: F,
ctx: &BuildCtx,
) -> State<Animate<T, LerpFnState<Self, F>>>
) -> Writer<Animate<T, LerpFnState<Self, F>>>
where
Self: Share,
Self::V: Clone,
F: FnMut(&Self::V, &Self::V, f32) -> Self::V + 'static,
Self: StateWriter,
Self::Value: Clone,
F: FnMut(&Self::Value, &Self::Value, f32) -> Self::Value + 'static,
T: Roc + 'static,
{
let animate_state = LerpFnState::new(self, lerp_fn);
Expand Down Expand Up @@ -101,20 +96,19 @@ impl<E: Easing> Roc for Transition<E> {
}
}

impl<T: Share> Roc for T
impl<T: StateReader> Roc for T
where
T::V: Roc,
T::Value: Roc,
{
fn rate_of_change(&self, dur: Duration) -> AnimateProgress {
self.state_ref().rate_of_change(dur)
}
fn rate_of_change(&self, dur: Duration) -> AnimateProgress { self.read().rate_of_change(dur) }
}

impl<S: Share + 'static> TransitionState for S {}
impl<S, F> TransitionState for LerpFnState<S, F>
impl<S: StateWriter + 'static> TransitionState for S {}

impl<V, S, F> TransitionState for LerpFnState<S, F>
where
S: Share + 'static,
F: FnMut(&<S as Share>::V, &<S as Share>::V, f32) -> <S as Share>::V + 'static,
S: StateWriter<Value = V> + 'static,
F: FnMut(&V, &V, f32) -> V + 'static,
{
}

Expand Down
12 changes: 6 additions & 6 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ pub mod key;
pub use key::{Key, KeyWidget};
pub mod image_widget;
pub use image_widget::*;
pub mod delay_drop_widget;
pub use delay_drop_widget::DelayDropWidget;
pub mod delay_drop;
pub use delay_drop::DelayDrop;
mod theme;
pub use theme::*;
mod cursor;
Expand Down Expand Up @@ -158,7 +158,7 @@ impl_builtin_obj!(
Visibility,
Opacity,
LifecycleListener,
DelayDropWidget
DelayDrop
);

/// A fat object that extend the `T` object with all builtin widgets ability. A
Expand Down Expand Up @@ -198,7 +198,7 @@ impl<T: ComposeChild + 'static> ComposeChild for FatObj<State<T>> {
type Child = T::Child;

fn compose_child(this: State<Self>, child: Self::Child) -> Widget {
let this = this.into_inner_value();
let this = this.into_value();
let Self { host, builtin } = this;
FnWidget::new(move |ctx| {
let this = host.with_child(child, ctx);
Expand All @@ -212,7 +212,7 @@ impl<T: ComposeChild + 'static> ComposeChild for FatObj<T> {
type Child = T::Child;

fn compose_child(this: State<Self>, child: Self::Child) -> Widget {
let this = this.into_inner_value();
let this = this.into_value();
let Self { host, builtin } = this;
FnWidget::new(move |ctx| {
let this = host.with_child(child, ctx);
Expand Down Expand Up @@ -242,7 +242,7 @@ impl ComposeChild for BuiltinObj {
type Child = Widget;

fn compose_child(this: State<Self>, child: Self::Child) -> Widget {
let this = this.into_inner_value();
let this = this.into_value();
fn_widget! { this.compose_with_host(child, ctx!()) }.into()
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/builtin_widgets/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl ComposeChild for Cursor {
&& e.mouse_buttons() == MouseButtons::empty()
{
let wnd = e.window();
*$save_cursor = wnd.get_cursor();
*$save_cursor.write() = wnd.get_cursor();
wnd.set_cursor($this.get_cursor());
}
},
Expand Down
29 changes: 29 additions & 0 deletions core/src/builtin_widgets/delay_drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::{impl_query_self_only, prelude::*};

/// A widget that can delay drop its child until the `delay_drop_until` field be
/// set to `true`.
///
/// This widget not effect the widget lifecycle, if the widget is dispose but
/// the `delay_drop_until` is `false`, it's not part of the widget tree anymore
/// but not drop immediately, is disposed in `logic`, but not release resource.
/// It's be isolated from the widget tree and can layout and paint normally.
///
/// Once the `delay_drop_until` field be set to `true`, the widget will be
/// dropped.
///
/// It's useful when you need run a leave animation for a widget.
#[derive(Declare, Declare2)]
pub struct DelayDrop {
#[declare(builtin)]
pub delay_drop_until: bool,
}

impl ComposeChild for DelayDrop {
type Child = Widget;
#[inline]
fn compose_child(this: State<Self>, child: Self::Child) -> Widget {
DataWidget::attach(child, this.into_writable())
}
}

impl_query_self_only!(DelayDrop);
17 changes: 0 additions & 17 deletions core/src/builtin_widgets/delay_drop_widget.rs

This file was deleted.

4 changes: 2 additions & 2 deletions core/src/builtin_widgets/fitted_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ mod tests {
expected_scale,
} = self;
let fit = Stateful::new(FittedBox { box_fit, scale_cache: <_>::default() });
let c_fit = fit.clone();
let c_fit = fit.clone_reader();
let w = fn_widget! {
@$fit { @MockBox { size } }
};
let mut wnd = TestWindow::new_with_size(w, WND_SIZE);
wnd.draw_frame();

assert_layout_result_by_path!(wnd, {path = [0], size == expect,} );
assert_eq!(c_fit.state_ref().scale_cache.get(), expected_scale);
assert_eq!(c_fit.read().scale_cache.get(), expected_scale);
}
}

Expand Down
Loading

0 comments on commit 171892c

Please sign in to comment.