Fix remaining compile errors and runtime panics
This commit is contained in:
parent
7c6e6971da
commit
5183dbb5be
11 changed files with 293 additions and 216 deletions
|
@ -107,6 +107,21 @@ impl<M: ManagedView> PopoverMenu<M> {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn with_element_state<R>(
|
||||
&mut self,
|
||||
cx: &mut ElementContext,
|
||||
f: impl FnOnce(&mut Self, &mut PopoverMenuElementState<M>, &mut ElementContext) -> R,
|
||||
) -> R {
|
||||
cx.with_element_state::<PopoverMenuElementState<M>, _>(
|
||||
self.element_id(),
|
||||
|element_state, cx| {
|
||||
let mut element_state = element_state.unwrap().unwrap_or_default();
|
||||
let result = f(self, &mut element_state, cx);
|
||||
(result, Some(element_state))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`PopoverMenu`]
|
||||
|
@ -121,104 +136,116 @@ pub fn popover_menu<M: ManagedView>(id: impl Into<ElementId>) -> PopoverMenu<M>
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PopoverMenuState<M> {
|
||||
pub struct PopoverMenuElementState<M> {
|
||||
menu: Rc<RefCell<Option<View<M>>>>,
|
||||
child_bounds: Option<Bounds<Pixels>>,
|
||||
}
|
||||
|
||||
impl<M> Clone for PopoverMenuElementState<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
menu: Rc::clone(&self.menu),
|
||||
child_bounds: self.child_bounds,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> Default for PopoverMenuElementState<M> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
menu: Rc::default(),
|
||||
child_bounds: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PopoverMenuFrameState {
|
||||
child_layout_id: Option<LayoutId>,
|
||||
child_element: Option<AnyElement>,
|
||||
child_bounds: Option<Bounds<Pixels>>,
|
||||
menu_element: Option<AnyElement>,
|
||||
menu: Rc<RefCell<Option<View<M>>>>,
|
||||
}
|
||||
|
||||
impl<M: ManagedView> Element for PopoverMenu<M> {
|
||||
type FrameState = PopoverMenuState<M>;
|
||||
type FrameState = PopoverMenuFrameState;
|
||||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
element_state: Option<Self::FrameState>,
|
||||
cx: &mut ElementContext,
|
||||
) -> (gpui::LayoutId, Self::FrameState) {
|
||||
let mut menu_layout_id = None;
|
||||
fn request_layout(&mut self, cx: &mut ElementContext) -> (gpui::LayoutId, Self::FrameState) {
|
||||
self.with_element_state(cx, |this, element_state, cx| {
|
||||
let mut menu_layout_id = None;
|
||||
|
||||
let (menu, child_bounds) = if let Some(element_state) = element_state {
|
||||
(element_state.menu, element_state.child_bounds)
|
||||
} else {
|
||||
(Rc::default(), None)
|
||||
};
|
||||
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
||||
let mut overlay = overlay().snap_to_window().anchor(this.anchor);
|
||||
|
||||
let menu_element = menu.borrow_mut().as_mut().map(|menu| {
|
||||
let mut overlay = overlay().snap_to_window().anchor(self.anchor);
|
||||
if let Some(child_bounds) = element_state.child_bounds {
|
||||
overlay = overlay.position(
|
||||
this.resolved_attach().corner(child_bounds) + this.resolved_offset(cx),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(child_bounds) = child_bounds {
|
||||
overlay = overlay.position(
|
||||
self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
|
||||
);
|
||||
}
|
||||
let mut element = overlay.child(menu.clone()).into_any();
|
||||
menu_layout_id = Some(element.request_layout(cx));
|
||||
element
|
||||
});
|
||||
|
||||
let mut element = overlay.child(menu.clone()).into_any();
|
||||
menu_layout_id = Some(element.request_layout(cx));
|
||||
element
|
||||
});
|
||||
let mut child_element = this.child_builder.take().map(|child_builder| {
|
||||
(child_builder)(element_state.menu.clone(), this.menu_builder.clone())
|
||||
});
|
||||
|
||||
let mut child_element = self
|
||||
.child_builder
|
||||
.take()
|
||||
.map(|child_builder| (child_builder)(menu.clone(), self.menu_builder.clone()));
|
||||
let child_layout_id = child_element
|
||||
.as_mut()
|
||||
.map(|child_element| child_element.request_layout(cx));
|
||||
|
||||
let child_layout_id = child_element
|
||||
.as_mut()
|
||||
.map(|child_element| child_element.request_layout(cx));
|
||||
let layout_id = cx.request_layout(
|
||||
&gpui::Style::default(),
|
||||
menu_layout_id.into_iter().chain(child_layout_id),
|
||||
);
|
||||
|
||||
let layout_id = cx.request_layout(
|
||||
&gpui::Style::default(),
|
||||
menu_layout_id.into_iter().chain(child_layout_id),
|
||||
);
|
||||
|
||||
(
|
||||
layout_id,
|
||||
PopoverMenuState {
|
||||
menu,
|
||||
child_element,
|
||||
child_layout_id,
|
||||
menu_element,
|
||||
child_bounds,
|
||||
},
|
||||
)
|
||||
(
|
||||
layout_id,
|
||||
PopoverMenuFrameState {
|
||||
child_element,
|
||||
child_layout_id,
|
||||
menu_element,
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: Bounds<gpui::Pixels>,
|
||||
element_state: &mut Self::FrameState,
|
||||
frame_state: &mut Self::FrameState,
|
||||
cx: &mut ElementContext,
|
||||
) {
|
||||
if let Some(mut child) = element_state.child_element.take() {
|
||||
child.paint(cx);
|
||||
}
|
||||
|
||||
if let Some(child_layout_id) = element_state.child_layout_id.take() {
|
||||
element_state.child_bounds = Some(cx.layout_bounds(child_layout_id));
|
||||
}
|
||||
|
||||
if let Some(mut menu) = element_state.menu_element.take() {
|
||||
menu.paint(cx);
|
||||
|
||||
if let Some(child_bounds) = element_state.child_bounds {
|
||||
let interactive_bounds = InteractiveBounds {
|
||||
bounds: child_bounds,
|
||||
stacking_order: cx.stacking_order().clone(),
|
||||
};
|
||||
|
||||
// Mouse-downing outside the menu dismisses it, so we don't
|
||||
// want a click on the toggle to re-open it.
|
||||
cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& interactive_bounds.visibly_contains(&e.position, cx)
|
||||
{
|
||||
cx.stop_propagation()
|
||||
}
|
||||
})
|
||||
self.with_element_state(cx, |_this, element_state, cx| {
|
||||
if let Some(mut child) = frame_state.child_element.take() {
|
||||
child.paint(cx);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(child_layout_id) = frame_state.child_layout_id.take() {
|
||||
element_state.child_bounds = Some(cx.layout_bounds(child_layout_id));
|
||||
}
|
||||
|
||||
if let Some(mut menu) = frame_state.menu_element.take() {
|
||||
menu.paint(cx);
|
||||
|
||||
if let Some(child_bounds) = element_state.child_bounds {
|
||||
let interactive_bounds = InteractiveBounds {
|
||||
bounds: child_bounds,
|
||||
stacking_order: cx.stacking_order().clone(),
|
||||
};
|
||||
|
||||
// Mouse-downing outside the menu dismisses it, so we don't
|
||||
// want a click on the toggle to re-open it.
|
||||
cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& interactive_bounds.visibly_contains(&e.position, cx)
|
||||
{
|
||||
cx.stop_propagation()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue