From 267e07472d4ee0c3070f884d4be9fc9966a7a6a3 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 16 Nov 2023 13:32:19 -0700 Subject: [PATCH] Checkpoint, MenuHandle can open one --- crates/gpui2/src/elements/overlay.rs | 10 +- crates/gpui2/src/window.rs | 1 + crates/workspace2/src/dock.rs | 133 +++++++++++++++++++++++++-- 3 files changed, 136 insertions(+), 8 deletions(-) diff --git a/crates/gpui2/src/elements/overlay.rs b/crates/gpui2/src/elements/overlay.rs index a190337f04dbfe5a4acd908aaf4a646c33a49240..c45ea2a588e841e82c5b43c75dd06f832b2cd356 100644 --- a/crates/gpui2/src/elements/overlay.rs +++ b/crates/gpui2/src/elements/overlay.rs @@ -1,8 +1,8 @@ use smallvec::SmallVec; use crate::{ - point, AnyElement, BorrowWindow, Bounds, Element, LayoutId, ParentComponent, Pixels, Point, - Size, Style, + point, AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, ParentComponent, Pixels, + Point, Size, Style, }; pub struct OverlayState { @@ -48,6 +48,12 @@ impl ParentComponent for Overlay { } } +impl Component for Overlay { + fn render(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Overlay { type ElementState = OverlayState; diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index b0d9d07df2db7b3b84db7d9950d3f6364b3b8c9d..17bd4743b1b840cb2d0230f3e041f41c8c34cd75 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -574,6 +574,7 @@ impl<'a> WindowContext<'a> { result } + #[must_use] /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which /// layout is being requested, along with the layout ids of any children. This method is called during /// calls to the `Element::layout` trait method and enables any element to participate in layout. diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index eec0ce309a4c3dcbc41017a1bb81669b0155e609..f2dd2c15cf2c1e3416ebfa9162f5c901c3306ce7 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,13 +1,16 @@ use crate::{status_bar::StatusItemView, Axis, Workspace}; use gpui::{ - div, px, Action, AnyView, AppContext, Component, Div, Entity, EntityId, EventEmitter, - FocusHandle, FocusableView, ParentComponent, Render, SharedString, Styled, Subscription, View, - ViewContext, WeakView, WindowContext, + div, overlay, point, px, Action, AnyElement, AnyView, AppContext, Component, DispatchPhase, + Div, Element, ElementId, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, + InteractiveComponent, LayoutId, MouseButton, MouseDownEvent, ParentComponent, Pixels, Point, + Render, SharedString, Style, Styled, Subscription, View, ViewContext, VisualContext, WeakView, + WindowContext, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use ui::{h_stack, IconButton, InteractionState, Tooltip}; +use smallvec::SmallVec; +use std::{cell::RefCell, rc::Rc, sync::Arc}; +use ui::{h_stack, IconButton, InteractionState, Label, Tooltip}; pub enum PanelEvent { ChangePosition, @@ -656,6 +659,118 @@ impl PanelButtons { // } // } +pub struct MenuHandle { + id: ElementId, + children: SmallVec<[AnyElement; 2]>, + builder: Rc) -> AnyView + 'static>, +} + +impl ParentComponent for MenuHandle { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children + } +} + +impl MenuHandle { + fn new( + id: impl Into, + builder: impl Fn(&mut V, &mut ViewContext) -> AnyView + 'static, + ) -> Self { + Self { + id: id.into(), + children: SmallVec::new(), + builder: Rc::new(builder), + } + } +} + +pub struct MenuState { + open: Rc>, + menu: Option>, +} +// Here be dragons +impl Element for MenuHandle { + type ElementState = MenuState; + + fn element_id(&self) -> Option { + Some(self.id.clone()) + } + + fn layout( + &mut self, + view_state: &mut V, + element_state: Option, + cx: &mut crate::ViewContext, + ) -> (gpui::LayoutId, Self::ElementState) { + let mut child_layout_ids = self + .children + .iter_mut() + .map(|child| child.layout(view_state, cx)) + .collect::>(); + + let open = if let Some(element_state) = element_state { + element_state.open + } else { + Rc::new(RefCell::new(false)) + }; + + let mut menu = None; + if *open.borrow() { + let mut view = (self.builder)(view_state, cx).render(); + child_layout_ids.push(view.layout(view_state, cx)); + menu.replace(view); + } + let layout_id = cx.request_layout(&gpui::Style::default(), child_layout_ids.into_iter()); + + (layout_id, MenuState { open, menu }) + } + + fn paint( + &mut self, + bounds: crate::Bounds, + view_state: &mut V, + element_state: &mut Self::ElementState, + cx: &mut crate::ViewContext, + ) { + for child in &mut self.children { + child.paint(view_state, cx); + } + + if let Some(mut menu) = element_state.menu.as_mut() { + menu.paint(view_state, cx); + return; + } + + let open = element_state.open.clone(); + cx.on_mouse_event(move |view_state, event: &MouseDownEvent, phase, cx| { + dbg!(&event, &phase); + if phase == DispatchPhase::Bubble + && event.button == MouseButton::Right + && bounds.contains_point(&event.position) + { + *open.borrow_mut() = true; + cx.notify(); + } + }); + } +} + +impl Component for MenuHandle { + fn render(self) -> AnyElement { + AnyElement::new(self) + } +} + +struct TestMenu {} +impl Render for TestMenu { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div().child("0MG!") + } +} + +// here be kittens impl Render for PanelButtons { type Element = Div; @@ -689,7 +804,13 @@ impl Render for PanelButtons { .tooltip(move |_, cx| Tooltip::for_action(name, &*action, cx)) }; - Some(button) + Some( + MenuHandle::new( + SharedString::from(format!("{} tooltip", name)), + move |_, cx| Tooltip::text("HELLOOOOOOOOOOOOOO", cx), + ) + .child(button), + ) }); h_stack().children(buttons)