Fix stateful elements in Components (#3430)

No more wrapper divs for buttons

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2023-11-28 20:59:58 -07:00 committed by GitHub
commit 9e7a90a3d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 31 deletions

View file

@ -111,7 +111,7 @@ pub struct Component<C> {
pub struct CompositeElementState<C: RenderOnce> { pub struct CompositeElementState<C: RenderOnce> {
rendered_element: Option<<C::Rendered as IntoElement>::Element>, rendered_element: Option<<C::Rendered as IntoElement>::Element>,
rendered_element_state: <<C::Rendered as IntoElement>::Element as Element>::State, rendered_element_state: Option<<<C::Rendered as IntoElement>::Element as Element>::State>,
} }
impl<C> Component<C> { impl<C> Component<C> {
@ -131,20 +131,40 @@ impl<C: RenderOnce> Element for Component<C> {
cx: &mut WindowContext, cx: &mut WindowContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut element = self.component.take().unwrap().render(cx).into_element(); let mut element = self.component.take().unwrap().render(cx).into_element();
let (layout_id, state) = element.layout(state.map(|s| s.rendered_element_state), cx); if let Some(element_id) = element.element_id() {
let layout_id =
cx.with_element_state(element_id, |state, cx| element.layout(state, cx));
let state = CompositeElementState { let state = CompositeElementState {
rendered_element: Some(element), rendered_element: Some(element),
rendered_element_state: state, rendered_element_state: None,
};
(layout_id, state)
} else {
let (layout_id, state) =
element.layout(state.and_then(|s| s.rendered_element_state), cx);
let state = CompositeElementState {
rendered_element: Some(element),
rendered_element_state: Some(state),
}; };
(layout_id, state) (layout_id, state)
} }
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) { fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
state let element = state.rendered_element.take().unwrap();
.rendered_element if let Some(element_id) = element.element_id() {
.take() cx.with_element_state(element_id, |element_state, cx| {
.unwrap() let mut element_state = element_state.unwrap();
.paint(bounds, &mut state.rendered_element_state, cx); element.paint(bounds, &mut element_state, cx);
((), element_state)
});
} else {
element.paint(
bounds,
&mut state.rendered_element_state.as_mut().unwrap(),
cx,
);
}
} }
} }

View file

@ -1939,23 +1939,6 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
}) })
} }
/// Like `with_element_state`, but for situations where the element_id is optional. If the
/// id is `None`, no state will be retrieved or stored.
fn with_optional_element_state<S, R>(
&mut self,
element_id: Option<ElementId>,
f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
) -> R
where
S: 'static,
{
if let Some(element_id) = element_id {
self.with_element_state(element_id, f)
} else {
f(None, self).0
}
}
/// Obtain the current content mask. /// Obtain the current content mask.
fn content_mask(&self) -> ContentMask<Pixels> { fn content_mask(&self) -> ContentMask<Pixels> {
self.window() self.window()

View file

@ -70,8 +70,7 @@ impl RenderOnce for IconButton {
} }
} }
// HACK: Add an additional identified element wrapper to fix tooltips not showing up. button
div().id(self.id.clone()).child(button)
} }
} }