Skip to content

Commit

Permalink
fix(core): 🐛 use track_id track WidgetId, which may changed when crea…
Browse files Browse the repository at this point in the history
…ted by pipe or class
  • Loading branch information
wjian23 committed Nov 25, 2024
1 parent b0f97c8 commit 4f5deab
Show file tree
Hide file tree
Showing 23 changed files with 473 additions and 262 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

- **core**: inner embed anchor not work (#pr @wjian23)
- **core**: fix query render object with multi target hits (#pr @wjian23)
- **core**: Use track_id track WidgetId, which may changed when created by pipe or class. (#pr @wjian23)

## [0.4.0-alpha.15] - 2024-11-13

Expand Down
76 changes: 21 additions & 55 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
//! declare syntax, so other objects can use the builtin fields and methods like
//! self fields and methods.
use std::cell::Cell;
pub mod key;
mod painting_style;
pub use key::{Key, KeyWidget};
Expand All @@ -14,7 +13,6 @@ pub mod image_widget;
pub mod keep_alive;
pub use keep_alive::*;
mod theme;
use ribir_algo::Sc;
pub use theme::*;
mod cursor;
pub use cursor::*;
Expand Down Expand Up @@ -74,11 +72,10 @@ pub use text_style::*;
mod smooth_layout;
pub use smooth_layout::*;

use crate::prelude::*;
mod track_widget_id;
pub use track_widget_id::*;

#[derive(Clone, Default)]
/// LazyWidgetId is a widget id that will be valid after widget build.
pub struct LazyWidgetId(Sc<Cell<Option<WidgetId>>>);
use crate::prelude::*;

/// A fat object that extend the `T` object with all builtin widgets ability.
///
Expand Down Expand Up @@ -110,8 +107,7 @@ pub struct LazyWidgetId(Sc<Cell<Option<WidgetId>>>);
#[derive(Default)]
pub struct FatObj<T> {
host: T,
host_id: LazyWidgetId,
id: LazyWidgetId,
track_id: Option<State<TrackWidgetId>>,
class: Option<State<Class>>,
padding: Option<State<Padding>>,
fitted_box: Option<State<FittedBox>>,
Expand All @@ -137,35 +133,6 @@ pub struct FatObj<T> {
keep_alive_unsubscribe_handle: Option<Box<dyn Any>>,
}

impl LazyWidgetId {
/// Creates a new `LazyWidgetId` associated with a widget. You can retrieve
/// the widget's ID after the build process using this `LazyWidgetId`.
pub fn new(widget: Widget) -> (Widget, Self) {
let lazy_id = Self(<_>::default());
let w = lazy_id.clone().bind(widget);
(w, lazy_id)
}

/// Bind a widget to the LazyWidgetId, and return a widget that will set the
/// id to the LazyWidgetId after build.
pub fn bind(self, widget: Widget) -> Widget {
widget.on_build(move |id| {
assert!(self.id().is_none(), "The LazyWidgetID only allows binding to one widget.");
self.0.set(Some(id));
})
}

pub fn id(&self) -> Option<WidgetId> { self.0.get() }

pub fn assert_id(&self) -> WidgetId {
self.0.get().expect(
"The binding is not associated with a widget, or the bound widget has not been built yet.",
)
}

fn ref_count(&self) -> usize { self.0.ref_count() }
}

impl<T> FatObj<T> {
/// Create a new `FatObj` with the given host object.
pub fn new(host: T) -> Self { FatObj::<()>::default().with_child(host) }
Expand All @@ -175,8 +142,7 @@ impl<T> FatObj<T> {
pub fn map<V>(self, f: impl FnOnce(T) -> V) -> FatObj<V> {
FatObj {
host: f(self.host),
host_id: self.host_id,
id: self.id,
track_id: self.track_id,
class: self.class,
mix_builtin: self.mix_builtin,
request_focus: self.request_focus,
Expand Down Expand Up @@ -205,8 +171,7 @@ impl<T> FatObj<T> {

/// Return true if the FatObj not contains any builtin widgets.
pub fn is_empty(&self) -> bool {
self.host_id.ref_count() == 1
&& self.id.ref_count() == 1
self.track_id.is_none()
&& self.mix_builtin.is_none()
&& self.request_focus.is_none()
&& self.fitted_box.is_none()
Expand Down Expand Up @@ -240,18 +205,18 @@ impl<T> FatObj<T> {
assert!(self.is_empty(), "Unwrap a FatObj with contains builtin widgets is not allowed.");
self.host
}

/// Return the LazyWidgetId of the host widget, through which you can access
/// the WidgetId after building.
pub fn lazy_host_id(&self) -> LazyWidgetId { self.host_id.clone() }

/// Return the LazyWidgetId point to WidgetId of the root of the sub widget
/// tree after the FatObj has built.
pub fn lazy_id(&self) -> LazyWidgetId { self.id.clone() }
}

// builtin widgets accessors
impl<T> FatObj<T> {
/// Returns the `State<TrackWidgetId>` widget from the FatObj. If it doesn't
/// exist, a new one is created.
pub fn get_track_id_widget(&mut self) -> &State<TrackWidgetId> {
self
.track_id
.get_or_insert_with(|| State::value(<_>::default()))
}

/// Returns the `State<Class>` widget from the FatObj. If it doesn't exist, a
/// new one is created.
pub fn get_class_widget(&mut self) -> &State<Class> {
Expand Down Expand Up @@ -883,6 +848,12 @@ impl<T> FatObj<T> {
self
}

/// Initializes the track_id of the widget.
pub fn track_id(mut self) -> Self {
self.get_track_id_widget();
self
}

fn declare_builtin_init<V: 'static, B: 'static, const M: u8>(
mut self, init: impl DeclareInto<V, M>, get_builtin: impl FnOnce(&mut Self) -> &State<B>,
set_value: fn(&mut B, V),
Expand Down Expand Up @@ -925,12 +896,10 @@ impl<'a> FatObj<Widget<'a>> {
};
}
let mut host = self.host;
if self.host_id.0.ref_count() > 1 {
host = self.host_id.clone().bind(host);
}
compose_builtin_widgets!(
host
+ [
track_id,
class,
padding,
fitted_box,
Expand Down Expand Up @@ -959,9 +928,6 @@ impl<'a> FatObj<Widget<'a>> {
if let Some(h) = self.keep_alive_unsubscribe_handle {
host = host.attach_anonymous_data(h);
}
if self.id.0.ref_count() > 1 {
host = self.id.clone().bind(host);
}
host
}
}
Expand Down
35 changes: 28 additions & 7 deletions core/src/builtin_widgets/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ use std::{

use ribir_algo::Sc;
use smallvec::{SmallVec, smallvec};
use widget_id::RenderQueryable;
use widget_id::{DynamicWidgetId, RenderQueryable};

use crate::{
data_widget::AnonymousAttacher,
data_widget::{AnonymousAttacher, DataAttacher},
pipe::DynInfo,
prelude::*,
render_helper::{PureRender, RenderProxy},
Expand Down Expand Up @@ -195,10 +195,10 @@ impl Class {
p.query_match(&[override_cls_id, classes_id], &|id, h| {
if id == &override_cls_id {
h.downcast_ref::<OverrideClass>()
.map_or(false, |c| c.name == cls)
.is_some_and(|c| c.name == cls)
} else {
h.downcast_ref::<Classes>()
.map_or(false, |c| c.store.contains_key(&cls))
.is_some_and(|c| c.store.contains_key(&cls))
}
})
})?;
Expand Down Expand Up @@ -249,7 +249,10 @@ impl ClassChild {
inner.child_id = id;
id.wrap_node(BuildCtx::get_mut().tree_mut(), |node| {
inner.child = node;
Box::new(self.clone())
Box::new(DataAttacher::new(
Box::new(self.clone()),
Box::new(Queryable(DynamicWidgetId::new(id))),
))
});
}

Expand Down Expand Up @@ -285,6 +288,17 @@ impl ClassChild {
n_orig.dispose_subtree(tree);
}

if *child_id != new_id {
// update the DynamicWidgetId out of the class node when id changed.
let mut v = SmallVec::new();
class_node.query_all(&QueryId::of::<DynamicWidgetId>(), &mut v);
v.into_iter()
.filter_map(QueryHandle::into_ref)
.for_each(|handle: QueryRef<'_, DynamicWidgetId>| {
*handle.get_mut() = new_id;
});
}

new_id.wrap_node(tree, |node| {
*child = node;
class_node
Expand Down Expand Up @@ -320,9 +334,16 @@ impl ClassChild {
}
}

*child_id = new_id;
new_id
.query_all_iter::<DynamicWidgetId>(tree)
.for_each(|wid| {
*wid.0.write() = new_id;
});

tree.mark_dirty(new_id);
tree.mark_dirty(*orig_id);
if new_id != *orig_id && new_id.ancestor_of(*orig_id, tree) {
tree.mark_dirty(*orig_id);
}
}

#[allow(clippy::mut_from_ref)]
Expand Down
3 changes: 2 additions & 1 deletion core/src/builtin_widgets/focus_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ impl<'c> ComposeChild<'c> for RequestFocus {
let child = FatObj::new(child);
@ $child {
on_mounted: move |e| {
let handle = e.window().focus_mgr.borrow().focus_handle(e.id);
let wid = TrackId::from(e.id(), e.tree());
let handle = e.window().focus_mgr.borrow().focus_handle(wid);
$this.silent().handle = Some(handle);
}
}
Expand Down
Loading

0 comments on commit 4f5deab

Please sign in to comment.