From a06dc9a9c139585700531f2cd731b882fec7436c Mon Sep 17 00:00:00 2001 From: Adoo Date: Fri, 25 Aug 2023 18:48:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ribir):=20=F0=9F=92=A1=20remove=20`Dyn?= =?UTF-8?q?Widget`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/test_helper.rs | 7 +- core/src/window.rs | 1 - ribir/src/app.rs | 1 + widgets/src/scrollbar.rs | 269 +++++++++++++++++---------------------- 4 files changed, 124 insertions(+), 154 deletions(-) diff --git a/core/src/test_helper.rs b/core/src/test_helper.rs index 16d874592..2025ddaf1 100644 --- a/core/src/test_helper.rs +++ b/core/src/test_helper.rs @@ -1,4 +1,4 @@ -use crate::timer::Timer; +pub use crate::timer::Timer; use std::{ rc::Rc, sync::atomic::{AtomicU64, Ordering}, @@ -22,8 +22,8 @@ pub struct TestWindow(pub Rc); #[macro_export] macro_rules! reset_test_env { () => { - let _ = rxrust::scheduler::NEW_TIMER_FN.set(Timer::new_timer_future); - let _guard = unsafe { AppCtx::new_lock_scope() }; + let _ = $crate::prelude::NEW_TIMER_FN.set(Timer::new_timer_future); + let _guard = unsafe { $crate::prelude::AppCtx::new_lock_scope() }; }; } @@ -76,7 +76,6 @@ impl TestWindow { pub fn draw_frame(&mut self) { // Test window not have a eventloop, manually wake-up every frame. Timer::wake_timeout_futures(); - AppCtx::run_until_stalled(); self.run_frame_tasks(); self.0.draw_frame(); diff --git a/core/src/window.rs b/core/src/window.rs index c4887cb61..5e43547a9 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -91,7 +91,6 @@ impl Window { pub fn processes_native_event(&self, event: WindowEvent) { let ratio = self.device_pixel_ratio() as f64; self.dispatcher.borrow_mut().dispatch(event, ratio); - self.run_frame_tasks(); } /// Request switch the focus to next widget. diff --git a/ribir/src/app.rs b/ribir/src/app.rs index 80da0aa70..f25dfbb6d 100644 --- a/ribir/src/app.rs +++ b/ribir/src/app.rs @@ -123,6 +123,7 @@ impl App { wnd.processes_native_event(event); } } + wnd.run_frame_tasks(); } Event::MainEventsCleared => { AppCtx::run_until_stalled(); diff --git a/widgets/src/scrollbar.rs b/widgets/src/scrollbar.rs index a5f2bc76e..d42546bcc 100644 --- a/widgets/src/scrollbar.rs +++ b/widgets/src/scrollbar.rs @@ -1,11 +1,9 @@ -use std::time::Duration; - use crate::layout::{Container, Stack, StackFit}; use ribir_core::prelude::*; /// A control widget that enables the user to access horizontal parts child that /// is larger than the box rect. -#[derive(Declare, Clone)] +#[derive(Declare, Declare2, Clone)] pub struct HScrollBar { /// Scrolled pixels of child content. #[declare(default)] @@ -32,12 +30,8 @@ pub struct HScrollBarThumbDecorator { impl ComposeDecorator for HScrollBarThumbDecorator { type Host = Widget; - fn compose_decorator(this: State, host: Self::Host) -> Widget { - widget! { - states { this: this.into_readonly() } - DynWidget { left_anchor: this.offset, dyns: host } - } - .into() + fn compose_decorator(mut this: State, host: Self::Host) -> Widget { + fn_widget! { @$host { left_anchor: pipe!($this.offset) } }.into() } } @@ -51,48 +45,39 @@ pub struct VScrollBarThumbDecorator { impl ComposeDecorator for VScrollBarThumbDecorator { type Host = Widget; - fn compose_decorator(this: State, host: Self::Host) -> Widget { - widget! { - states { this: this.into_readonly() } - DynWidget { - top_anchor: this.offset, - dyns: host - } - } - .into() + fn compose_decorator(mut this: State, host: Self::Host) -> Widget { + fn_widget! { @$host { top_anchor: pipe!($this.offset) } }.into() } } impl ComposeChild for HScrollBar { type Child = Widget; - fn compose_child(this: State, child: Self::Child) -> Widget { - widget! { - states { this: this.into_writable() } - Stack { + fn compose_child(mut this: State, child: Self::Child) -> Widget { + fn_widget! { + let mut scrolling = @ScrollableWidget { + scrollable: Scrollable::X, + scroll_pos: Point::new($this.offset, 0.), + }; + let scrollbar = @HRawScrollbar { + scrolling: scrolling.get_builtin_scrollable_widget(ctx!()).clone_state(), + v_align: VAlign::Bottom, + }; + + // `scrolling` and `this` have same lifetime, so we needn't unsubscribe. + watch!($scrolling.scroll_pos.x) + .distinct_until_changed() + .subscribe(move |v| $this.offset = v); + watch!($this.offset) + .distinct_until_changed() + .subscribe(move |v| { + let y = $scrolling.scroll_pos.y; + $scrolling.jump_to(Point::new(v, y)); + }); + + @Stack { fit: StackFit::Passthrough, - ScrollableWidget { - id: scrolling, - scrollable: Scrollable::X, - scroll_pos: Point::new(this.offset, 0.), - DynWidget { dyns: child } - } - HRawScrollbar { - scrolling: scrolling.clone_stateful(), - v_align: VAlign::Bottom, - } - } - finally ctx => { - let_watch!(scrolling.scroll_pos.x) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| this.offset = v); - let_watch!(this.offset) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| { - let y = scrolling.scroll_pos.y; - scrolling.jump_to(Point::new(v, y)); - }); + @ $scrolling { @{ child } } + @ { scrollbar } } } .into() @@ -110,34 +95,33 @@ pub struct VScrollBar { impl ComposeChild for VScrollBar { type Child = Widget; - fn compose_child(this: State, child: Self::Child) -> Widget { - widget! { - states { this: this.into_writable() } - Stack { + fn compose_child(mut this: State, child: Self::Child) -> Widget { + fn_widget! { + let mut scrolling = @ScrollableWidget { + scrollable: Scrollable::Y, + scroll_pos: Point::new(0., $this.offset), + }; + + let scrollbar = @VRawScrollbar { + scrolling: scrolling.get_builtin_scrollable_widget(ctx!()).clone_state(), + h_align: HAlign::Right + }; + + // `scrolling` and `this` have same lifetime, so we needn't unsubscribe. + watch!($scrolling.scroll_pos.y) + .distinct_until_changed() + .subscribe(move |v| $this.offset = v); + watch!($this.offset) + .distinct_until_changed() + .subscribe(move |v| { + let x = $scrolling.scroll_pos.x; + $scrolling.jump_to(Point::new(x, v)); + }); + + @Stack { fit: StackFit::Passthrough, - ScrollableWidget { - id: scrolling, - scrollable: Scrollable::Y, - scroll_pos: Point::new(0., this.offset), - DynWidget { dyns: child } - } - VRawScrollbar { - scrolling: scrolling.clone_stateful(), - h_align: HAlign::Right - } - } - finally ctx => { - let_watch!(scrolling.scroll_pos.y) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| this.offset = v); - let_watch!(this.offset) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| { - let x = scrolling.scroll_pos.x; - scrolling.jump_to(Point::new(x, v)); - }); + @ $scrolling { @{ child } } + @ { scrollbar } } } .into() @@ -145,7 +129,7 @@ impl ComposeChild for VScrollBar { } /// A control widget that enables the user to access horizontal parts child that /// is larger than the box rect. -#[derive(Declare, Clone)] +#[derive(Declare, Declare2, Clone)] pub struct BothScrollbar { /// Scrolled pixels of child content. #[declare(default)] @@ -154,41 +138,35 @@ pub struct BothScrollbar { impl ComposeChild for BothScrollbar { type Child = Widget; - fn compose_child(this: State, child: Self::Child) -> Widget { - widget! { - states { this: this.into_writable() } - Stack { + fn compose_child(mut this: State, child: Self::Child) -> Widget { + fn_widget! { + let mut scrolling = @ScrollableWidget { + scrollable: Scrollable::Both, + scroll_pos: $this.offset, + }; + let mut h_bar = @HRawScrollbar { + scrolling: scrolling.get_builtin_scrollable_widget(ctx!()).clone_state(), + v_align: VAlign::Bottom, + }; + let mut v_bar = @VRawScrollbar { + scrolling: scrolling.get_builtin_scrollable_widget(ctx!()).clone_state(), + h_align: HAlign::Right, + margin: EdgeInsets::only_bottom($h_bar.layout_height()) + }; + + // `scrolling` and `this` have same lifetime, so we needn't unsubscribe. + watch!($scrolling.scroll_pos) + .distinct_until_changed() + .subscribe(move |v| $this.offset = v); + watch!($this.offset) + .distinct_until_changed() + .subscribe(move |v| $scrolling.jump_to(v) ); + + @Stack{ fit: StackFit::Passthrough, - ScrollableWidget { - id: scrolling, - scrollable: Scrollable::Both, - scroll_pos: this.offset, - DynWidget { dyns: child } - } - HRawScrollbar { - id: h_bar, - scrolling: scrolling.clone_stateful(), - v_align: VAlign::Bottom, - margin: EdgeInsets::only_right(v_bar.layout_width()) - } - VRawScrollbar { - id: v_bar, - scrolling: scrolling.clone_stateful(), - h_align: HAlign::Right, - margin: EdgeInsets::only_bottom(h_bar.layout_height()) - } - } - finally ctx => { - let_watch!(scrolling.scroll_pos) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| this.offset = v); - let_watch!(this.offset) - .distinct_until_changed() - .debounce(Duration::ZERO, ctx.window().frame_scheduler()) - .subscribe(move |v| { - scrolling.jump_to(v); - }); + @ $scrolling { @{ child } } + @ $h_bar{ margin: EdgeInsets::only_right($v_bar.layout_width()) } + @ { v_bar } } } .into() @@ -197,7 +175,7 @@ impl ComposeChild for BothScrollbar { /// A widget that display the horizontal scrolling information of the /// `scrolling` widget. -#[derive(Declare)] +#[derive(Declare, Declare2)] pub struct HRawScrollbar { scrolling: Stateful, } @@ -249,7 +227,7 @@ impl Compose for HRawScrollbar { /// A widget that display the vertical scrolling information of the /// `scrolling` widget. -#[derive(Declare)] +#[derive(Declare, Declare2)] pub struct VRawScrollbar { scrolling: Stateful, } @@ -316,10 +294,9 @@ impl CustomStyle for ScrollBarStyle { #[cfg(test)] mod test { - use crate::layout::{Column, ConstrainedBox}; - use super::*; - use ribir_core::test_helper::*; + use crate::layout::{Column, ConstrainedBox}; + use ribir_core::{reset_test_env, test_helper::*}; use ribir_dev_helper::*; fn content_expand_so_all_view_can_scroll() -> Widget { @@ -352,57 +329,51 @@ mod test { #[test] fn scrollable() { - let _guard = unsafe { AppCtx::new_lock_scope() }; - - let offset = Stateful::new(Point::zero()); - let v_offset = Stateful::new(0.); - let h_offset = Stateful::new(0.); - let w = widget! { - states { offset: offset.clone(), v_offset: v_offset.clone(), h_offset: h_offset.clone() } - Column { - Container { + reset_test_env!(); + + let mut offset = Stateful::new(Point::zero()); + let mut v_offset = Stateful::new(0.); + let mut h_offset = Stateful::new(0.); + let c_offset = offset.clone(); + let c_v_offset = v_offset.clone(); + let c_h_offset = h_offset.clone(); + let w = fn_widget! { + let mut both_bar = @BothScrollbar { offset: pipe!(*$offset) }; + let mut h_bar = @HScrollBar { offset: pipe!($both_bar.offset.x) }; + let mut v_bar = @VScrollBar { offset: pipe!($both_bar.offset.y) }; + + watch!($v_bar.offset) + .subscribe(move|v| *$v_offset = v); + watch!($h_bar.offset) + .subscribe(move|v| *$h_offset = v); + + let container_size = Size::new(100., 100.); + @Column { + @Container { size: Size::new(30., 30.), - BothScrollbar { - id: both_bar, - offset: *offset, - Container { size: Size::new(100., 100.) } - } + @$both_bar { @Container { size: container_size } } } - Container { + @Container { size: Size::new(30., 30.), - HScrollBar { - id: h_bar, - offset: both_bar.offset.x, - Container { size: Size::new(100., 100.) } - } + @$h_bar { @Container { size: container_size } } } - Container { + @Container { size: Size::new(30., 30.), - VScrollBar { - id: v_bar, - offset: both_bar.offset.y, - Container { size: Size::new(100., 100.) } - } + @$v_bar { @Container { size: container_size } } } } - - finally { - let_watch!(v_bar.offset) - .subscribe(move|v| *v_offset = v); - let_watch!(h_bar.offset) - .subscribe(move|v| *h_offset = v); - } }; let mut wnd = TestWindow::new_with_size(w, Size::new(1024., 1024.)); + wnd.draw_frame(); { - *offset.state_ref() = Point::new(-10., -10.); + *c_offset.state_ref() = Point::new(-10., -10.); } { - *offset.state_ref() = Point::new(-20., -20.); + *c_offset.state_ref() = Point::new(-20., -20.); } wnd.draw_frame(); - assert_eq!(*v_offset.state_ref(), offset.state_ref().y); - assert_eq!(*h_offset.state_ref(), offset.state_ref().x); + assert_eq!(*c_v_offset.state_ref(), c_offset.state_ref().y); + assert_eq!(*c_h_offset.state_ref(), c_offset.state_ref().x); } }