From 32f4a586c7862a9210abf7545743dcd699ba2b5b Mon Sep 17 00:00:00 2001 From: wjian23 Date: Fri, 13 Dec 2024 14:23:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20=F0=9F=90=9B=20Added=20DeclarerWit?= =?UTF-8?q?hSubscription=20to=20let=20Widget=20`Expanded`=20accept=20pipe?= =?UTF-8?q?=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 ++- core/src/builtin_widgets.rs | 68 ++++++++++++++++++++++++++++++++++ widgets/src/layout/expanded.rs | 46 ++++++++++++++++++++--- 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad1b1c130..f24dd3e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,10 +27,11 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he ### Features -- **core**: Added `grab_pointer` to grabs all the pointer input. (#pr @wjian23) +- **core**: Added `grab_pointer` to grabs all the pointer input. (#pr @wjian23) ### Fixed -- **core**: fix mismatch of providers (#pr @wjian23) +- **core**: fix mismatch of providers. (#pr @wjian23) +- **core**: Added DeclarerWithSubscription to let Widget `Expanded` accept pipe value. (#pr @wjian23) ## [0.4.0-alpha.18] - 2024-12-11 diff --git a/core/src/builtin_widgets.rs b/core/src/builtin_widgets.rs index cd40a16f5..5d112a811 100644 --- a/core/src/builtin_widgets.rs +++ b/core/src/builtin_widgets.rs @@ -7,6 +7,8 @@ pub mod key; mod painting_style; +use std::ops::DerefMut; + pub use key::{Key, KeyWidget}; pub use painting_style::*; pub mod image_widget; @@ -999,3 +1001,69 @@ impl std::ops::DerefMut for FatObj { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.host } } + +/// DeclarerWithSubscription, a declarer with subscriptions +/// +/// Used to wraps a declarer to make it the widget auto unsubscribe when +/// disposed. Normally you should not use this directly, most Widget types +/// derive with Declare attribute has support builtin widgets has the ability +/// of unsubscribing when disposed. +pub struct DeclarerWithSubscription { + inner: T, + subscribes: Vec>, +} + +impl DeclarerWithSubscription { + pub fn new(host: T, subscribes: Vec>) -> Self { + Self { inner: host, subscribes } + } +} + +impl Deref for DeclarerWithSubscription { + type Target = T; + + fn deref(&self) -> &Self::Target { &self.inner } +} + +impl DerefMut for DeclarerWithSubscription { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } +} + +impl DeclarerWithSubscription { + fn map(self, f: impl FnOnce(T) -> M) -> DeclarerWithSubscription { + DeclarerWithSubscription { inner: f(self.inner), subscribes: self.subscribes } + } +} + +impl<'w, T, const M: usize> IntoWidgetStrict<'w, M> for DeclarerWithSubscription +where + T: IntoWidget<'w, M>, +{ + fn into_widget_strict(self) -> Widget<'w> { + let DeclarerWithSubscription { inner: host, subscribes } = self; + let w = host.into_widget(); + if subscribes.is_empty() { + w + } else { + fn_widget! { + let w = FatObj::new(w); + @ $w { + on_disposed: move |_| { + subscribes.into_iter().for_each(|u| u.unsubscribe()); + } + } + } + .into_widget() + } + } +} + +impl<'w, T, C, const N: usize, const M: usize> WithChild<'w, C, N, M> + for DeclarerWithSubscription +where + T: WithChild<'w, C, N, M> + 'w, + C: 'w, +{ + type Target = DeclarerWithSubscription; + fn with_child(self, c: C) -> Self::Target { self.map(|w| w.with_child(c)) } +} diff --git a/widgets/src/layout/expanded.rs b/widgets/src/layout/expanded.rs index bced17c2e..e927703ea 100644 --- a/widgets/src/layout/expanded.rs +++ b/widgets/src/layout/expanded.rs @@ -4,15 +4,51 @@ use ribir_core::prelude::*; /// available space. If multiple children are expanded, the available space is /// divided among them according to the flex factor. #[derive(Clone, PartialEq)] -// `Expand` should not support `FatObj`, as this may cause the `Expanded` to be invisible to its -// parent. `@Expanded { margin: EdgeInsets::all(10.) }` actually expands as `@Margin { @Expanded { -// .. } }`. -#[simple_declare] +// `Expand` should not support `FatObj`, as this may cause the `Expanded` to be +// invisible to its parent. `@Expanded { margin: EdgeInsets::all(10.) }` +// actually expands as `@Margin { @Expanded { .. } }`. pub struct Expanded { - #[declare(default = 1.)] pub flex: f32, } +impl Default for Expanded { + fn default() -> Self { Self { flex: 1. } } +} + +#[derive(Default)] +pub struct FlexDeclarer { + flex: Option>, +} + +impl FlexDeclarer { + pub fn flex(mut self, flex: impl DeclareInto) -> Self { + self.flex = Some(flex.declare_into()); + self + } +} + +impl Declare for Expanded { + type Builder = FlexDeclarer; + + fn declarer() -> Self::Builder { FlexDeclarer::default() } +} + +impl ObjDeclarer for FlexDeclarer { + type Target = DeclarerWithSubscription>; + + fn finish(self) -> Self::Target { + let (v, u) = self.flex.map(|v| v.unzip()).unwrap_or((1., None)); + let host = State::value(Expanded { flex: v }); + let mut subscribes = Vec::new(); + if let Some(o) = u { + let host = host.clone_writer(); + let u = o.subscribe(move |(_, v)| host.write().flex = v); + subscribes.push(u) + } + DeclarerWithSubscription::new(host, subscribes) + } +} + impl<'c> ComposeChild<'c> for Expanded { type Child = Widget<'c>; #[inline]