Skip to content

Commit

Permalink
fix(core): 🐛 changing flex does not relayout
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo authored and rchangelog[bot] committed Nov 8, 2024
1 parent d469c1c commit 49b47b9
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

- **core**: The `Provider` might be missing in a pipe class. (#648 @M-Adoo)
- **core**: The child generated by the class may not be mounted. (#648 @M-Adoo)
- **widgets**: Changing the `flex` of `Expanded` does not trigger a relayout. (#652 @M-Adoo)

### Breaking

Expand Down
2 changes: 1 addition & 1 deletion core/src/builtin_widgets/keep_alive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<'c> ComposeChild<'c> for KeepAlive {
let modifies = this.raw_modifies();
child
.try_unwrap_state_and_attach(this)
.on_build(|id| id.dirty_subscribe(modifies, BuildCtx::get_mut().tree_mut()))
.on_build(|id| id.dirty_on(modifies))
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/builtin_widgets/smooth_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ macro_rules! smooth_size_widget_impl {
fn_widget!{
let modifies = this.read().0.raw_modifies();
WrapRender::combine_child(this, child)
.on_build(move |id, | id.dirty_subscribe(modifies, BuildCtx::get_mut().tree_mut()) )
.on_build(move |id, | id.dirty_on(modifies) )
}.into_widget()
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ where
Err(s) => {
let modifies = s.raw_modifies();
let w = ReaderRender(s.clone_reader()).into_widget();
w.on_build(move |id| id.dirty_subscribe(modifies, BuildCtx::get_mut().tree_mut()))
w.on_build(move |id| id.dirty_on(modifies))
}
},
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<'w> Widget<'w> {
self.on_build(|id| id.attach_anonymous_data(data, BuildCtx::get_mut().tree_mut()))
}

pub(crate) fn attach_data(self, data: Box<dyn Query>) -> Self {
pub fn attach_data(self, data: Box<dyn Query>) -> Self {
self.on_build(|id| id.attach_data(data, BuildCtx::get_mut().tree_mut()))
}

Expand Down
13 changes: 8 additions & 5 deletions core/src/widget_tree/widget_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ impl WidgetId {
tree.arena.get(self.0).map(|n| &**n.get())
}

/// Subscribe the modifies `upstream` to mark the widget dirty when the
/// `upstream` emit a modify event that contains `ModifyScope::FRAMEWORK`.
pub(crate) fn dirty_subscribe(
self, upstream: CloneableBoxOp<'static, ModifyScope, Infallible>, tree: &mut WidgetTree,
) {
/// Subscribe to the modified `upstream` to mark the widget as dirty when the
/// `upstream` emits a modify event containing `ModifyScope::FRAMEWORK`.
///
/// # Panic
/// This method only works within a build process; otherwise, it will
/// result in a panic.
pub fn dirty_on(self, upstream: CloneableBoxOp<'static, ModifyScope, Infallible>) {
let tree = BuildCtx::get_mut().tree_mut();
let dirty_set = tree.dirty_set.clone();
let h = upstream
.filter(|b| b.contains(ModifyScope::FRAMEWORK))
Expand Down
6 changes: 1 addition & 5 deletions core/src/wrap_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,20 @@ pub trait WrapRender {
Self: Sized + 'static,
{
child.on_build(move |id| {
let mut modifies = None;
let tree = BuildCtx::get_mut().tree_mut();
id.wrap_node(tree, |r| match this.try_into_value() {
Ok(this) => Box::new(RenderPair { wrapper: Box::new(this), host: r }),
Err(this) => {
let reader = match this.into_reader() {
Ok(r) => r,
Err(s) => {
modifies = Some(s.raw_modifies());
id.dirty_on(s.raw_modifies());
s.clone_reader()
}
};
Box::new(RenderPair { wrapper: Box::new(reader), host: r })
}
});
if let Some(modifies) = modifies {
id.dirty_subscribe(modifies, tree);
}
})
}
}
Expand Down
42 changes: 39 additions & 3 deletions widgets/src/layout/expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@ pub struct Expanded {
impl<'c> ComposeChild<'c> for Expanded {
type Child = Widget<'c>;
#[inline]
fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
child.try_unwrap_state_and_attach(this)
fn compose_child(this: impl StateWriter<Value = Self>, mut child: Self::Child) -> Widget<'c> {
let data: Box<dyn Query> = match this.try_into_value() {
Ok(this) => Box::new(Queryable(this)),
Err(this) => {
let modifies = this.raw_modifies();
child = child.on_build(|id| id.dirty_on(modifies));
Box::new(this)
}
};

child.attach_data(data)
}
}

#[cfg(test)]
mod tests {
use ribir_core::test_helper::*;
use ribir_core::{reset_test_env, test_helper::*};
use ribir_dev_helper::*;

use super::*;
Expand Down Expand Up @@ -88,4 +97,31 @@ mod tests {
LayoutCase::new(&[0, 5]).with_rect(ribir_geom::rect(100., 50., 50., 50.)),
LayoutCase::new(&[0, 6]).with_rect(ribir_geom::rect(150., 50., 200., 50.))
);

#[test]
fn modifies_flex() {
reset_test_env!();

let (flex, w_flex) = split_value(1f32);
let widget = fn_widget! {
let expanded = @Expanded { flex: 1. };
watch!(*$flex).subscribe(move |val| $expanded.write().flex = val);

@Row {
@ $expanded { @ { Void } }
@Expanded {
flex: 1.,
@ { Void }
}
@SizedBox { size: Size::new(100., 100.) }
}
};

let mut wnd = TestWindow::new_with_size(widget, Size::new(400., 100.));
wnd.draw_frame();
LayoutCase::expect_size(&wnd, &[0, 0], Size::new(150., 0.));
*w_flex.write() = 2.;
wnd.draw_frame();
LayoutCase::expect_size(&wnd, &[0, 0], Size::new(200., 0.));
}
}

0 comments on commit 49b47b9

Please sign in to comment.