Fix pane splitting panic (#3381)

Also opens the window on startup.

Release Notes:

-
This commit is contained in:
Mikayla Maki 2023-11-22 14:12:28 -08:00 committed by GitHub
commit f01a04a8e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 50 deletions

View file

@ -1550,7 +1550,7 @@ mod tests {
block_id: ix, block_id: ix,
editor_style: &editor::EditorStyle::default(), editor_style: &editor::EditorStyle::default(),
}) })
.element_id()? .inner_id()?
.try_into() .try_into()
.ok()?, .ok()?,

View file

@ -44,7 +44,7 @@ impl Render for DiagnosticIndicator {
}; };
h_stack() h_stack()
.id(cx.entity_id()) .id("diagnostic-indicator")
.on_action(cx.listener(Self::go_to_next_diagnostic)) .on_action(cx.listener(Self::go_to_next_diagnostic))
.rounded_md() .rounded_md()
.flex_none() .flex_none()

View file

@ -432,10 +432,6 @@ impl AnyElement {
AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>) AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>)
} }
pub fn element_id(&self) -> Option<ElementId> {
self.0.element_id()
}
pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId { pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
self.0.layout(cx) self.0.layout(cx)
} }
@ -467,6 +463,10 @@ impl AnyElement {
pub fn into_any(self) -> AnyElement { pub fn into_any(self) -> AnyElement {
AnyElement::new(self) AnyElement::new(self)
} }
pub fn inner_id(&self) -> Option<ElementId> {
self.0.element_id()
}
} }
impl Element for AnyElement { impl Element for AnyElement {
@ -490,7 +490,7 @@ impl RenderOnce for AnyElement {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> { fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self) None
} }
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {

View file

@ -248,7 +248,7 @@ impl<V: 'static + Render> RenderOnce for View<V> {
type Element = View<V>; type Element = View<V>;
fn element_id(&self) -> Option<ElementId> { fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into()) Some(ElementId::from_entity_id(self.model.entity_id))
} }
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
@ -260,7 +260,7 @@ impl RenderOnce for AnyView {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> { fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into()) Some(ElementId::from_entity_id(self.model.entity_id))
} }
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
@ -308,27 +308,23 @@ where
} }
mod any_view { mod any_view {
use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext}; use crate::{AnyElement, AnyView, Element, LayoutId, Render, WindowContext};
pub(crate) fn layout<V: 'static + Render>( pub(crate) fn layout<V: 'static + Render>(
view: &AnyView, view: &AnyView,
cx: &mut WindowContext, cx: &mut WindowContext,
) -> (LayoutId, AnyElement) { ) -> (LayoutId, AnyElement) {
cx.with_element_id(Some(view.model.entity_id), |cx| {
let view = view.clone().downcast::<V>().unwrap(); let view = view.clone().downcast::<V>().unwrap();
let mut element = view.update(cx, |view, cx| view.render(cx).into_any()); let mut element = view.update(cx, |view, cx| view.render(cx).into_any());
let layout_id = element.layout(cx); let layout_id = element.layout(cx);
(layout_id, element) (layout_id, element)
})
} }
pub(crate) fn paint<V: 'static + Render>( pub(crate) fn paint<V: 'static + Render>(
view: &AnyView, _view: &AnyView,
element: AnyElement, element: AnyElement,
cx: &mut WindowContext, cx: &mut WindowContext,
) { ) {
cx.with_element_id(Some(view.model.entity_id), |cx| {
element.paint(cx); element.paint(cx);
})
} }
} }

View file

@ -230,9 +230,15 @@ pub struct Window {
pub(crate) focus: Option<FocusId>, pub(crate) focus: Option<FocusId>,
} }
pub(crate) struct ElementStateBox {
inner: Box<dyn Any>,
#[cfg(debug_assertions)]
type_name: &'static str,
}
// #[derive(Default)] // #[derive(Default)]
pub(crate) struct Frame { pub(crate) struct Frame {
pub(crate) element_states: HashMap<GlobalElementId, Box<dyn Any>>, pub(crate) element_states: HashMap<GlobalElementId, ElementStateBox>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>, mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
pub(crate) dispatch_tree: DispatchTree, pub(crate) dispatch_tree: DispatchTree,
pub(crate) focus_listeners: Vec<AnyFocusListener>, pub(crate) focus_listeners: Vec<AnyFocusListener>,
@ -1815,10 +1821,37 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
.remove(&global_id) .remove(&global_id)
}) })
{ {
let ElementStateBox {
inner,
#[cfg(debug_assertions)]
type_name
} = any;
// Using the extra inner option to avoid needing to reallocate a new box. // Using the extra inner option to avoid needing to reallocate a new box.
let mut state_box = any let mut state_box = inner
.downcast::<Option<S>>() .downcast::<Option<S>>()
.expect("invalid element state type for id"); .map_err(|_| {
#[cfg(debug_assertions)]
{
anyhow!(
"invalid element state type for id, requested_type {:?}, actual type: {:?}",
std::any::type_name::<S>(),
type_name
)
}
#[cfg(not(debug_assertions))]
{
anyhow!(
"invalid element state type for id, requested_type {:?}",
std::any::type_name::<S>(),
)
}
})
.unwrap();
// Actual: Option<AnyElement> <- View
// Requested: () <- AnyElemet
let state = state_box let state = state_box
.take() .take()
.expect("element state is already on the stack"); .expect("element state is already on the stack");
@ -1827,14 +1860,27 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
cx.window_mut() cx.window_mut()
.current_frame .current_frame
.element_states .element_states
.insert(global_id, state_box); .insert(global_id, ElementStateBox {
inner: state_box,
#[cfg(debug_assertions)]
type_name
});
result result
} else { } else {
let (result, state) = f(None, cx); let (result, state) = f(None, cx);
cx.window_mut() cx.window_mut()
.current_frame .current_frame
.element_states .element_states
.insert(global_id, Box::new(Some(state))); .insert(global_id,
ElementStateBox {
inner: Box::new(Some(state)),
#[cfg(debug_assertions)]
type_name: std::any::type_name::<S>()
}
);
result result
} }
}) })
@ -2599,6 +2645,12 @@ pub enum ElementId {
FocusHandle(FocusId), FocusHandle(FocusId),
} }
impl ElementId {
pub(crate) fn from_entity_id(entity_id: EntityId) -> Self {
ElementId::View(entity_id)
}
}
impl TryInto<SharedString> for ElementId { impl TryInto<SharedString> for ElementId {
type Error = anyhow::Error; type Error = anyhow::Error;
@ -2611,12 +2663,6 @@ impl TryInto<SharedString> for ElementId {
} }
} }
impl From<EntityId> for ElementId {
fn from(id: EntityId) -> Self {
ElementId::View(id)
}
}
impl From<usize> for ElementId { impl From<usize> for ElementId {
fn from(id: usize) -> Self { fn from(id: usize) -> Self {
ElementId::Integer(id) ElementId::Integer(id)

View file

@ -717,12 +717,9 @@ impl Render for PanelButtons {
&& panel.position_is_valid(position, cx) && panel.position_is_valid(position, cx)
{ {
let panel = panel.clone(); let panel = panel.clone();
menu = menu.entry( menu = menu.entry(position.to_label(), move |_, cx| {
format!("Dock {}", position.to_label()),
move |_, cx| {
panel.set_position(position, cx); panel.set_position(position, cx);
}, })
)
} }
} }
menu menu

View file

@ -1350,7 +1350,7 @@ impl Pane {
let id = item.item_id(); let id = item.item_id();
div() div()
.id(item.item_id()) .id(ix)
.invisible() .invisible()
.group_hover("", |style| style.visible()) .group_hover("", |style| style.visible())
.child( .child(
@ -1382,7 +1382,7 @@ impl Pane {
div() div()
.group("") .group("")
.id(item.item_id()) .id(ix)
.cursor_pointer() .cursor_pointer()
.when_some(item.tab_tooltip_text(cx), |div, text| { .when_some(item.tab_tooltip_text(cx), |div, text| {
div.tooltip(move |cx| cx.build_view(|cx| Tooltip::new(text.clone())).into()) div.tooltip(move |cx| cx.build_view(|cx| Tooltip::new(text.clone())).into())

View file

@ -210,7 +210,7 @@ impl Member {
// Some(pane) // Some(pane)
// }; // };
div().size_full().child(pane.clone()) div().size_full().child(pane.clone()).into_any()
// Stack::new() // Stack::new()
// .with_child(pane_element.contained().with_border(leader_border)) // .with_child(pane_element.contained().with_border(leader_border))
@ -226,7 +226,8 @@ impl Member {
// .bg(cx.theme().colors().editor) // .bg(cx.theme().colors().editor)
// .children(); // .children();
} }
Member::Axis(axis) => axis.render( Member::Axis(axis) => axis
.render(
project, project,
basis + 1, basis + 1,
follower_states, follower_states,
@ -234,7 +235,8 @@ impl Member {
zoomed, zoomed,
app_state, app_state,
cx, cx,
), )
.into_any(),
} }
// enum FollowIntoExternalProject {} // enum FollowIntoExternalProject {}
@ -551,7 +553,6 @@ impl PaneAxis {
project: &Model<Project>, project: &Model<Project>,
basis: usize, basis: usize,
follower_states: &HashMap<View<Pane>, FollowerState>, follower_states: &HashMap<View<Pane>, FollowerState>,
active_pane: &View<Pane>, active_pane: &View<Pane>,
zoomed: Option<&AnyWeakView>, zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,