Skip to content

Commit

Permalink
Replace WidgetMut methods with free functions. (#705)
Browse files Browse the repository at this point in the history
See discussion here #663 and [on
zulip](https://xi.zulipchat.com/#narrow/channel/317477-masonry/topic/Improving.20docs.20for.20WidgetMut).

Basically, previous code was using `WidgetMut<MyWidget>` as a receiver.
This can be done when WidgetMut is a local type, but external users
wouldn't be able to do it. The result would be that users importing
Masonry as a dependency but copy-pasting code from one of our widgets
would get compile errors.

This PR switches to a syntax that external crates will be able to use
when declaring widgets. It's a more verbose, less readable syntax, but
it's unambiguous and doesn't require clever tricks.

We can consider switching back to WidgetMut-as-a-receiver when
`#![feature(arbitrary_self_types)]` or some equivalent gets stabilized.
See
rust-lang/rust#44874 (comment)
for current progress.
  • Loading branch information
PoignardAzur authored Oct 22, 2024
1 parent 9c397da commit f322894
Show file tree
Hide file tree
Showing 36 changed files with 672 additions and 577 deletions.
6 changes: 3 additions & 3 deletions masonry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ impl AppDriver for Driver {
match action {
Action::ButtonPressed(_) => {
let mut root: WidgetMut<RootWidget<Portal<Flex>>> = ctx.get_root();
let mut root = root.child_mut();
let mut flex = root.child_mut();
flex.add_child(Label::new(self.next_task.clone()));
let mut portal = RootWidget::child_mut(&mut root);
let mut flex = Portal::child_mut(&mut portal);
Flex::add_child(&mut flex, Label::new(self.next_task.clone()));
}
Action::TextChanged(new_text) => {
self.next_task = new_text.clone();
Expand Down
19 changes: 9 additions & 10 deletions masonry/examples/calc_masonry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl Widget for CalcButton {
let color = self.active_color;
// See on_status_change for why we use `mutate_later` here.
ctx.mutate_later(&mut self.inner, move |mut inner| {
inner.set_background(color);
SizedBox::set_background(&mut inner, color);
});
ctx.capture_pointer();
trace!("CalcButton {:?} pressed", ctx.widget_id());
Expand All @@ -158,7 +158,7 @@ impl Widget for CalcButton {
let color = self.base_color;
// See on_status_change for why we use `mutate_later` here.
ctx.mutate_later(&mut self.inner, move |mut inner| {
inner.set_background(color);
SizedBox::set_background(&mut inner, color);
});
ctx.submit_action(Action::Other(Box::new(self.action)));
trace!("CalcButton {:?} released", ctx.widget_id());
Expand Down Expand Up @@ -190,15 +190,15 @@ impl Widget for CalcButton {
match event {
Update::HoveredChanged(true) => {
ctx.mutate_later(&mut self.inner, move |mut inner| {
inner.set_border(Color::WHITE, 3.0);
SizedBox::set_border(&mut inner, Color::WHITE, 3.0);
});
// FIXME - This is a monkey-patch for a problem where the mutate pass isn't run after this.
// Should be fixed once the pass spec RFC is implemented.
ctx.request_anim_frame();
}
Update::HoveredChanged(false) => {
ctx.mutate_later(&mut self.inner, move |mut inner| {
inner.set_border(Color::TRANSPARENT, 3.0);
SizedBox::set_border(&mut inner, Color::TRANSPARENT, 3.0);
});
// FIXME - This is a monkey-patch for a problem where the mutate pass isn't run after this.
// Should be fixed once the pass spec RFC is implemented.
Expand Down Expand Up @@ -254,12 +254,11 @@ impl AppDriver for CalcState {
_ => unreachable!(),
}

ctx.get_root::<RootWidget<Flex>>()
.child_mut()
.child_mut(1)
.unwrap()
.downcast::<Label>()
.set_text(&*self.value);
let mut root = ctx.get_root::<RootWidget<Flex>>();
let mut flex = RootWidget::child_mut(&mut root);
let mut label = Flex::child_mut(&mut flex, 1).unwrap();
let mut label = label.downcast::<Label>();
Label::set_text(&mut label, &*self.value);
}
}

Expand Down
6 changes: 3 additions & 3 deletions masonry/examples/grid_masonry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ impl AppDriver for Driver {
self.grid_spacing += 0.5;
}

ctx.get_root::<RootWidget<Grid>>()
.child_mut()
.set_spacing(self.grid_spacing);
let mut root = ctx.get_root::<RootWidget<Grid>>();
let mut grid = RootWidget::child_mut(&mut root);
Grid::set_spacing(&mut grid, self.grid_spacing);
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions masonry/examples/to_do_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ impl AppDriver for Driver {
match action {
Action::ButtonPressed(_) => {
let mut root: WidgetMut<RootWidget<Portal<Flex>>> = ctx.get_root();
let mut root = root.child_mut();
let mut flex = root.child_mut();
flex.add_child(Label::new(self.next_task.clone()));
let mut portal = RootWidget::child_mut(&mut root);
let mut flex = Portal::child_mut(&mut portal);
Flex::add_child(&mut flex, Label::new(self.next_task.clone()));

let mut first_row = flex.child_mut(0).unwrap();
let mut first_row = Flex::child_mut(&mut flex, 0).unwrap();
let mut first_row = first_row.downcast::<Flex>();
let mut textbox = first_row.child_mut(0).unwrap();
let mut textbox = Flex::child_mut(&mut first_row, 0).unwrap();
let mut textbox = textbox.downcast::<Textbox>();
textbox.reset_text(String::new());
Textbox::reset_text(&mut textbox, String::new());
}
Action::TextChanged(new_text) => {
self.next_task = new_text.clone();
Expand Down
6 changes: 3 additions & 3 deletions masonry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
//! match action {
//! Action::ButtonPressed(_) => {
//! let mut root: WidgetMut<RootWidget<Portal<Flex>>> = ctx.get_root();
//! let mut root = root.child_mut();
//! let mut flex = root.child_mut();
//! flex.add_child(Label::new(self.next_task.clone()));
//! let mut portal = RootWidget::child_mut(&mut root);
//! let mut flex = Portal::child_mut(&mut portal);
//! Flex::add_child(&mut flex, Label::new(self.next_task.clone()));
//! }
//! Action::TextChanged(new_text) => {
//! self.next_task = new_text.clone();
Expand Down
16 changes: 8 additions & 8 deletions masonry/src/widget/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ impl Button {
}

// --- MARK: WIDGETMUT ---
impl WidgetMut<'_, Button> {
impl Button {
/// Set the text.
pub fn set_text(&mut self, new_text: impl Into<ArcStr>) {
self.label_mut().set_text(new_text);
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) {
Label::set_text(&mut Self::label_mut(this), new_text);
}

pub fn label_mut(&mut self) -> WidgetMut<'_, Label> {
self.ctx.get_mut(&mut self.widget.label)
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
this.ctx.get_mut(&mut this.widget.label)
}
}

Expand Down Expand Up @@ -264,10 +264,10 @@ mod tests {

harness.edit_root_widget(|mut button| {
let mut button = button.downcast::<Button>();
button.set_text("The quick brown fox jumps over the lazy dog");
Button::set_text(&mut button, "The quick brown fox jumps over the lazy dog");

let mut label = button.label_mut();
label.set_text_properties(|props| {
let mut label = Button::label_mut(&mut button);
Label::set_text_properties(&mut label, |props| {
props.set_brush(PRIMARY_LIGHT);
props.set_text_size(20.0);
});
Expand Down
31 changes: 17 additions & 14 deletions masonry/src/widget/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ impl Checkbox {
}

// --- MARK: WIDGETMUT ---
impl WidgetMut<'_, Checkbox> {
pub fn set_checked(&mut self, checked: bool) {
self.widget.checked = checked;
impl Checkbox {
pub fn set_checked(this: &mut WidgetMut<'_, Self>, checked: bool) {
this.widget.checked = checked;
// Checked state impacts appearance and accessibility node
self.ctx.request_render();
this.ctx.request_render();
}

/// Set the text.
///
/// We enforce this to be an `ArcStr` to make the allocation explicit.
pub fn set_text(&mut self, new_text: ArcStr) {
self.label_mut().set_text(new_text);
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: ArcStr) {
Label::set_text(&mut Checkbox::label_mut(this), new_text);
}

pub fn label_mut(&mut self) -> WidgetMut<'_, Label> {
self.ctx.get_mut(&mut self.widget.label)
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
this.ctx.get_mut(&mut this.widget.label)
}
}

Expand Down Expand Up @@ -286,12 +286,15 @@ mod tests {

harness.edit_root_widget(|mut checkbox| {
let mut checkbox = checkbox.downcast::<Checkbox>();
checkbox.set_checked(true);
checkbox.set_text(ArcStr::from("The quick brown fox jumps over the lazy dog"));

let mut label = checkbox.label_mut();
label.set_text_brush(PRIMARY_LIGHT);
label.set_text_size(20.0);
Checkbox::set_checked(&mut checkbox, true);
Checkbox::set_text(
&mut checkbox,
ArcStr::from("The quick brown fox jumps over the lazy dog"),
);

let mut label = Checkbox::label_mut(&mut checkbox);
Label::set_text_brush(&mut label, PRIMARY_LIGHT);
Label::set_text_size(&mut label, 20.0);
});

harness.render()
Expand Down
Loading

0 comments on commit f322894

Please sign in to comment.