From 1409fc0da358c156cbf0e92bf9648455efd07f53 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 20 Oct 2023 17:31:42 +0200 Subject: [PATCH] Checkpoint --- crates/gpui3/src/element.rs | 23 +++++----------- crates/gpui3/src/elements/div.rs | 10 ++++--- crates/gpui3/src/elements/text.rs | 6 ++++- crates/gpui3/src/geometry.rs | 24 ++--------------- crates/gpui3/src/interactive.rs | 2 +- crates/gpui3/src/text_system/line.rs | 4 +++ crates/gpui3/src/view.rs | 5 ++-- crates/gpui3/src/window.rs | 33 +++++++++++++++++++++-- crates/gpui3_macros/src/derive_element.rs | 2 +- crates/storybook2/src/stories.rs | 2 ++ crates/storybook2/src/stories/scroll.rs | 28 +++++++++++++++++++ crates/storybook2/src/story_selector.rs | 2 ++ 12 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 crates/storybook2/src/stories/scroll.rs diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index f360ae6231..1fd72554eb 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,4 +1,4 @@ -use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext}; +use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::mem; @@ -62,7 +62,7 @@ pub trait ParentElement: Element { trait ElementObject: 'static + Send + Sync { fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext); fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId; - fn paint(&mut self, view_state: &mut V, offset: Option>, cx: &mut ViewContext); + fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); } struct RenderedElement { @@ -145,19 +145,13 @@ where layout_id } - fn paint( - &mut self, - view_state: &mut E::ViewState, - offset: Option>, - cx: &mut ViewContext, - ) { + fn paint(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, mut frame_state, } => { - let mut bounds = cx.layout_bounds(layout_id); - offset.map(|offset| bounds.origin += offset); + let bounds = cx.layout_bounds(layout_id); if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let mut element_state = element_state.unwrap(); @@ -192,13 +186,8 @@ impl AnyElement { self.0.layout(view_state, cx) } - pub fn paint( - &mut self, - view_state: &mut V, - offset: Option>, - cx: &mut ViewContext, - ) { - self.0.paint(view_state, offset, cx) + pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { + self.0.paint(view_state, cx) } } diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 634a1b6611..e955309112 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -277,7 +277,7 @@ where for child_layout_id in &element_state.child_layout_ids { let child_bounds = cx.layout_bounds(*child_layout_id); child_min = child_min.min(&child_bounds.origin); - child_max = child_min.max(&child_bounds.lower_right()); + child_max = child_max.max(&child_bounds.lower_right()); } (child_max - child_min).into() }; @@ -298,9 +298,11 @@ where style.apply_text_style(cx, |cx| { style.apply_overflow(bounds, cx, |cx| { let scroll_offset = element_state.interactive.scroll_offset(); - for child in &mut this.children { - child.paint(view_state, scroll_offset, cx); - } + cx.with_scroll_offset(scroll_offset, |cx| { + for child in &mut this.children { + child.paint(view_state, cx); + } + }); }) }) }); diff --git a/crates/gpui3/src/elements/text.rs b/crates/gpui3/src/elements/text.rs index 70d642baeb..ff1a9e2335 100644 --- a/crates/gpui3/src/elements/text.rs +++ b/crates/gpui3/src/elements/text.rs @@ -97,9 +97,13 @@ impl Element for Text { return Size::default(); }; + let line_count = lines + .iter() + .map(|line| line.wrap_count() + 1) + .sum::(); let size = Size { width: lines.iter().map(|line| line.layout.width).max().unwrap(), - height: line_height * lines.len(), + height: line_height * line_count, }; element_state diff --git a/crates/gpui3/src/geometry.rs b/crates/gpui3/src/geometry.rs index 2ac4c21b80..08602352ee 100644 --- a/crates/gpui3/src/geometry.rs +++ b/crates/gpui3/src/geometry.rs @@ -4,7 +4,7 @@ use refineable::Refineable; use std::{ cmp::{self, PartialOrd}, fmt, - ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign}, + ops::{Add, Div, Mul, MulAssign, Sub}, }; #[derive(Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash)] @@ -67,26 +67,6 @@ where } } -impl SubAssign> for Point -where - T: Sub + Clone + Debug + Default, -{ - fn sub_assign(&mut self, rhs: Size) { - self.x = self.x.clone() - rhs.width; - self.y = self.y.clone() - rhs.height; - } -} - -impl AddAssign for Point -where - T: Add + Clone + Default + Debug, -{ - fn add_assign(&mut self, rhs: T) { - self.x = self.x.clone() + rhs.clone(); - self.y = self.y.clone() + rhs; - } -} - impl Div for Point where T: Div + Clone + Default + Debug, @@ -187,7 +167,7 @@ impl Size { impl Size where - T: Ord + Clone + Default + Debug, + T: PartialOrd + Clone + Default + Debug, { pub fn max(&self, other: &Self) -> Self { Size { diff --git a/crates/gpui3/src/interactive.rs b/crates/gpui3/src/interactive.rs index f4a2f99844..437071d95d 100644 --- a/crates/gpui3/src/interactive.rs +++ b/crates/gpui3/src/interactive.rs @@ -477,7 +477,7 @@ pub trait ElementInteraction: 'static + Send + Sync { .get_or_insert_with(Arc::default) .clone(); let line_height = cx.line_height(); - let scroll_max = content_size - bounds.size; + let scroll_max = (content_size - bounds.size).max(&Size::default()); cx.on_mouse_event(move |_, event: &ScrollWheelEvent, _, cx| { if bounds.contains_point(&event.position) { diff --git a/crates/gpui3/src/text_system/line.rs b/crates/gpui3/src/text_system/line.rs index deb87e9796..bfd1487d91 100644 --- a/crates/gpui3/src/text_system/line.rs +++ b/crates/gpui3/src/text_system/line.rs @@ -26,6 +26,10 @@ impl Line { ) } + pub fn wrap_count(&self) -> usize { + self.layout.wrap_boundaries.len() + } + pub fn paint( &self, origin: Point, diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index e299e2c5de..92914b7279 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -90,8 +90,7 @@ impl Element for View { element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) { - self.state - .update(cx, |state, cx| element.paint(state, None, cx)) + self.state.update(cx, |state, cx| element.paint(state, cx)) } } @@ -186,7 +185,7 @@ impl ViewObject for View { cx.with_element_id(self.entity_id(), |_global_id, cx| { self.state.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); - element.paint(state, None, cx); + element.paint(state, cx); }); }); } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 7609aae29f..16c22ec797 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -159,6 +159,7 @@ pub struct Window { key_matchers: HashMap, z_index_stack: StackingOrder, content_mask_stack: Vec>, + scroll_offset_stack: Vec>, mouse_listeners: HashMap>, key_dispatch_stack: Vec, freeze_key_dispatch_stack: bool, @@ -234,6 +235,7 @@ impl Window { key_matchers: HashMap::default(), z_index_stack: StackingOrder(SmallVec::new()), content_mask_stack: Vec::new(), + scroll_offset_stack: Vec::new(), mouse_listeners: HashMap::default(), key_dispatch_stack: Vec::new(), freeze_key_dispatch_stack: false, @@ -443,10 +445,13 @@ impl<'a, 'w> WindowContext<'a, 'w> { } pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds { - self.window + let mut bounds = self + .window .layout_engine .layout_bounds(layout_id) - .map(Into::into) + .map(Into::into); + bounds.origin -= self.scroll_offset(); + bounds } pub fn scale_factor(&self) -> f32 { @@ -1136,6 +1141,30 @@ pub trait BorrowWindow: BorrowAppContext { result } + fn with_scroll_offset( + &mut self, + offset: Option>, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + let Some(offset) = offset else { + return f(self); + }; + + let offset = self.scroll_offset() + offset; + self.window_mut().scroll_offset_stack.push(offset); + let result = f(self); + self.window_mut().scroll_offset_stack.pop(); + result + } + + fn scroll_offset(&self) -> Point { + self.window() + .scroll_offset_stack + .last() + .copied() + .unwrap_or_default() + } + fn with_element_state( &mut self, id: ElementId, diff --git a/crates/gpui3_macros/src/derive_element.rs b/crates/gpui3_macros/src/derive_element.rs index d7510faf99..41861836ba 100644 --- a/crates/gpui3_macros/src/derive_element.rs +++ b/crates/gpui3_macros/src/derive_element.rs @@ -86,7 +86,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream { rendered_element: &mut Self::ElementState, cx: &mut gpui3::ViewContext, ) { - rendered_element.paint(view_state, None, cx) + rendered_element.paint(view_state, cx) } } }; diff --git a/crates/storybook2/src/stories.rs b/crates/storybook2/src/stories.rs index 758797e71f..2517522bc3 100644 --- a/crates/storybook2/src/stories.rs +++ b/crates/storybook2/src/stories.rs @@ -1,9 +1,11 @@ mod focus; mod kitchen_sink; +mod scroll; mod text; mod z_index; pub use focus::*; pub use kitchen_sink::*; +pub use scroll::*; pub use text::*; pub use z_index::*; diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs new file mode 100644 index 0000000000..bbe7d45f6d --- /dev/null +++ b/crates/storybook2/src/stories/scroll.rs @@ -0,0 +1,28 @@ +use crate::themes::rose_pine; +use gpui3::{div, view, Context, ParentElement, Styled, View, WindowContext}; + +pub struct ScrollStory { + text: View<()>, +} + +impl ScrollStory { + pub fn view(cx: &mut WindowContext) -> View<()> { + let theme = rose_pine(); + + view(cx.entity(|cx| ()), move |_, cx| { + div() + .id("parent") + .bg(theme.lowest.base.default.background) + .size_full() + .overflow_x_scroll() + .child(div().w_96().flex().flex_row().children((0..3).map(|ix| { + let bg = if ix % 2 == 0 { + theme.middle.positive.default.background + } else { + theme.middle.warning.default.background + }; + div().bg(bg).flex_1().h_20() + }))) + }) + } +} diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 0056d69764..14edce568e 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -19,6 +19,7 @@ pub enum ElementStory { Icon, Input, Label, + Scroll, Text, ZIndex, } @@ -46,6 +47,7 @@ impl ElementStory { Self::Label => { view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().into_any()).into_any() } + Self::Scroll => ScrollStory::view(cx).into_any(), Self::Text => TextStory::view(cx).into_any(), Self::ZIndex => { view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().into_any()).into_any()