From 776f7dd5a9c99e18363984fb3e2c4cc26bb06131 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Sep 2021 12:18:31 +0200 Subject: [PATCH] Add a new `Hooks` element to invoke a callback before layout This is useful to cap the width of sidebars when dragging the resize handles beyond the maximum bounds of the sidebar. --- gpui/src/elements.rs | 2 + gpui/src/elements/hooks.rs | 79 ++++++++++++++++++++++++++++++++++++ zed/src/workspace/sidebar.rs | 15 +++++-- 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 gpui/src/elements/hooks.rs diff --git a/gpui/src/elements.rs b/gpui/src/elements.rs index abfcadc0421f239f6282621d87b08d3dbd192314..7acd5cadad127e7014ee93ec5c49a2cbe11b22e0 100644 --- a/gpui/src/elements.rs +++ b/gpui/src/elements.rs @@ -5,6 +5,7 @@ mod container; mod empty; mod event_handler; mod flex; +mod hooks; mod label; mod line_box; mod list; @@ -23,6 +24,7 @@ pub use container::*; pub use empty::*; pub use event_handler::*; pub use flex::*; +pub use hooks::*; pub use label::*; pub use line_box::*; pub use list::*; diff --git a/gpui/src/elements/hooks.rs b/gpui/src/elements/hooks.rs new file mode 100644 index 0000000000000000000000000000000000000000..6d1e86a2173ab201e921b131828d29e4b73b7a44 --- /dev/null +++ b/gpui/src/elements/hooks.rs @@ -0,0 +1,79 @@ +use crate::{ + geometry::{rect::RectF, vector::Vector2F}, + json::json, + DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, +}; + +pub struct Hooks { + child: ElementBox, + before_layout: Option>, +} + +impl Hooks { + pub fn new(child: ElementBox) -> Self { + Self { + child, + before_layout: None, + } + } + + pub fn on_before_layout( + mut self, + f: impl 'static + FnMut(SizeConstraint, &mut LayoutContext), + ) -> Self { + self.before_layout = Some(Box::new(f)); + self + } +} + +impl Element for Hooks { + type LayoutState = (); + type PaintState = (); + + fn layout( + &mut self, + constraint: SizeConstraint, + cx: &mut LayoutContext, + ) -> (Vector2F, Self::LayoutState) { + if let Some(handler) = self.before_layout.as_mut() { + handler(constraint, cx); + } + let size = self.child.layout(constraint, cx); + (size, ()) + } + + fn paint( + &mut self, + bounds: RectF, + visible_bounds: RectF, + _: &mut Self::LayoutState, + cx: &mut PaintContext, + ) { + self.child.paint(bounds.origin(), visible_bounds, cx); + } + + fn dispatch_event( + &mut self, + event: &Event, + _: RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + cx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, cx) + } + + fn debug( + &self, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + cx: &DebugContext, + ) -> serde_json::Value { + json!({ + "type": "Hooks", + "child": self.child.debug(cx), + }) + } +} diff --git a/zed/src/workspace/sidebar.rs b/zed/src/workspace/sidebar.rs index 7dbc30dfbfaa6c255f0497a810201aeebdc1d717..dca3687240ad2b6e78ab3eaa5d4ee0e3cfcfb1ea 100644 --- a/zed/src/workspace/sidebar.rs +++ b/zed/src/workspace/sidebar.rs @@ -112,12 +112,21 @@ impl Sidebar { if matches!(self.side, Side::Right) { container.add_child(self.render_resize_handle(settings, cx)); } + + let width = self.width.clone(); container.add_child( Flexible::new( 1., - ConstrainedBox::new(ChildView::new(active_item.id()).boxed()) - .with_max_width(*self.width.borrow()) - .boxed(), + Hooks::new( + ConstrainedBox::new(ChildView::new(active_item.id()).boxed()) + .with_max_width(*self.width.borrow()) + .boxed(), + ) + .on_before_layout(move |constraint, _| { + let mut width = width.borrow_mut(); + *width = width.min(constraint.max.x()); + }) + .boxed(), ) .boxed(), );