Merge branch 'gpui2' of github.com:zed-industries/zed into gpui2

This commit is contained in:
Marshall Bowers 2023-10-20 11:32:11 -04:00
commit b0b7f27f3a
12 changed files with 90 additions and 51 deletions

View File

@ -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}; use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec; pub(crate) use smallvec::SmallVec;
use std::mem; use std::mem;
@ -62,7 +62,7 @@ pub trait ParentElement: Element {
trait ElementObject<V>: 'static + Send + Sync { trait ElementObject<V>: 'static + Send + Sync {
fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>); fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId; fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
fn paint(&mut self, view_state: &mut V, offset: Option<Point<Pixels>>, cx: &mut ViewContext<V>); fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
} }
struct RenderedElement<E: Element> { struct RenderedElement<E: Element> {
@ -145,19 +145,13 @@ where
layout_id layout_id
} }
fn paint( fn paint(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) {
&mut self,
view_state: &mut E::ViewState,
offset: Option<Point<Pixels>>,
cx: &mut ViewContext<E::ViewState>,
) {
self.phase = match mem::take(&mut self.phase) { self.phase = match mem::take(&mut self.phase) {
ElementRenderPhase::LayoutRequested { ElementRenderPhase::LayoutRequested {
layout_id, layout_id,
mut frame_state, mut frame_state,
} => { } => {
let mut bounds = cx.layout_bounds(layout_id); let bounds = cx.layout_bounds(layout_id);
offset.map(|offset| bounds.origin += offset);
if let Some(id) = self.element.id() { if let Some(id) = self.element.id() {
cx.with_element_state(id, |element_state, cx| { cx.with_element_state(id, |element_state, cx| {
let mut element_state = element_state.unwrap(); let mut element_state = element_state.unwrap();
@ -192,13 +186,8 @@ impl<V: 'static + Send + Sync> AnyElement<V> {
self.0.layout(view_state, cx) self.0.layout(view_state, cx)
} }
pub fn paint( pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
&mut self, self.0.paint(view_state, cx)
view_state: &mut V,
offset: Option<Point<Pixels>>,
cx: &mut ViewContext<V>,
) {
self.0.paint(view_state, offset, cx)
} }
} }

View File

@ -277,7 +277,7 @@ where
for child_layout_id in &element_state.child_layout_ids { for child_layout_id in &element_state.child_layout_ids {
let child_bounds = cx.layout_bounds(*child_layout_id); let child_bounds = cx.layout_bounds(*child_layout_id);
child_min = child_min.min(&child_bounds.origin); 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() (child_max - child_min).into()
}; };
@ -298,9 +298,11 @@ where
style.apply_text_style(cx, |cx| { style.apply_text_style(cx, |cx| {
style.apply_overflow(bounds, cx, |cx| { style.apply_overflow(bounds, cx, |cx| {
let scroll_offset = element_state.interactive.scroll_offset(); let scroll_offset = element_state.interactive.scroll_offset();
cx.with_scroll_offset(scroll_offset, |cx| {
for child in &mut this.children { for child in &mut this.children {
child.paint(view_state, scroll_offset, cx); child.paint(view_state, cx);
} }
});
}) })
}) })
}); });

View File

@ -97,9 +97,13 @@ impl<V: 'static + Send + Sync> Element for Text<V> {
return Size::default(); return Size::default();
}; };
let line_count = lines
.iter()
.map(|line| line.wrap_count() + 1)
.sum::<usize>();
let size = Size { let size = Size {
width: lines.iter().map(|line| line.layout.width).max().unwrap(), width: lines.iter().map(|line| line.layout.width).max().unwrap(),
height: line_height * lines.len(), height: line_height * line_count,
}; };
element_state element_state

View File

@ -4,7 +4,7 @@ use refineable::Refineable;
use std::{ use std::{
cmp::{self, PartialOrd}, cmp::{self, PartialOrd},
fmt, 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)] #[derive(Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash)]
@ -67,26 +67,6 @@ where
} }
} }
impl<T> SubAssign<Size<T>> for Point<T>
where
T: Sub<Output = T> + Clone + Debug + Default,
{
fn sub_assign(&mut self, rhs: Size<T>) {
self.x = self.x.clone() - rhs.width;
self.y = self.y.clone() - rhs.height;
}
}
impl<T> AddAssign<T> for Point<T>
where
T: Add<Output = T> + Clone + Default + Debug,
{
fn add_assign(&mut self, rhs: T) {
self.x = self.x.clone() + rhs.clone();
self.y = self.y.clone() + rhs;
}
}
impl<T, S> Div<S> for Point<T> impl<T, S> Div<S> for Point<T>
where where
T: Div<S, Output = T> + Clone + Default + Debug, T: Div<S, Output = T> + Clone + Default + Debug,
@ -187,7 +167,7 @@ impl Size<Pixels> {
impl<T> Size<T> impl<T> Size<T>
where where
T: Ord + Clone + Default + Debug, T: PartialOrd + Clone + Default + Debug,
{ {
pub fn max(&self, other: &Self) -> Self { pub fn max(&self, other: &Self) -> Self {
Size { Size {

View File

@ -477,7 +477,7 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
.get_or_insert_with(Arc::default) .get_or_insert_with(Arc::default)
.clone(); .clone();
let line_height = cx.line_height(); 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| { cx.on_mouse_event(move |_, event: &ScrollWheelEvent, _, cx| {
if bounds.contains_point(&event.position) { if bounds.contains_point(&event.position) {

View File

@ -26,6 +26,10 @@ impl Line {
) )
} }
pub fn wrap_count(&self) -> usize {
self.layout.wrap_boundaries.len()
}
pub fn paint( pub fn paint(
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,

View File

@ -90,8 +90,7 @@ impl<V: 'static + Send + Sync> Element for View<V> {
element: &mut Self::ElementState, element: &mut Self::ElementState,
cx: &mut ViewContext<()>, cx: &mut ViewContext<()>,
) { ) {
self.state self.state.update(cx, |state, cx| element.paint(state, cx))
.update(cx, |state, cx| element.paint(state, None, cx))
} }
} }
@ -186,7 +185,7 @@ impl<V: Send + Sync + 'static> ViewObject for View<V> {
cx.with_element_id(self.entity_id(), |_global_id, cx| { cx.with_element_id(self.entity_id(), |_global_id, cx| {
self.state.update(cx, |state, cx| { self.state.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<V>>().unwrap(); let element = element.downcast_mut::<AnyElement<V>>().unwrap();
element.paint(state, None, cx); element.paint(state, cx);
}); });
}); });
} }

View File

@ -159,6 +159,7 @@ pub struct Window {
key_matchers: HashMap<GlobalElementId, KeyMatcher>, key_matchers: HashMap<GlobalElementId, KeyMatcher>,
z_index_stack: StackingOrder, z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>, content_mask_stack: Vec<ContentMask<Pixels>>,
scroll_offset_stack: Vec<Point<Pixels>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>, mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
key_dispatch_stack: Vec<KeyDispatchStackFrame>, key_dispatch_stack: Vec<KeyDispatchStackFrame>,
freeze_key_dispatch_stack: bool, freeze_key_dispatch_stack: bool,
@ -234,6 +235,7 @@ impl Window {
key_matchers: HashMap::default(), key_matchers: HashMap::default(),
z_index_stack: StackingOrder(SmallVec::new()), z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(), content_mask_stack: Vec::new(),
scroll_offset_stack: Vec::new(),
mouse_listeners: HashMap::default(), mouse_listeners: HashMap::default(),
key_dispatch_stack: Vec::new(), key_dispatch_stack: Vec::new(),
freeze_key_dispatch_stack: false, 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<Pixels> { pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
self.window let mut bounds = self
.window
.layout_engine .layout_engine
.layout_bounds(layout_id) .layout_bounds(layout_id)
.map(Into::into) .map(Into::into);
bounds.origin -= self.scroll_offset();
bounds
} }
pub fn scale_factor(&self) -> f32 { pub fn scale_factor(&self) -> f32 {
@ -1136,6 +1141,30 @@ pub trait BorrowWindow: BorrowAppContext {
result result
} }
fn with_scroll_offset<R>(
&mut self,
offset: Option<Point<Pixels>>,
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<Pixels> {
self.window()
.scroll_offset_stack
.last()
.copied()
.unwrap_or_default()
}
fn with_element_state<S: 'static + Send + Sync, R>( fn with_element_state<S: 'static + Send + Sync, R>(
&mut self, &mut self,
id: ElementId, id: ElementId,

View File

@ -86,7 +86,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
rendered_element: &mut Self::ElementState, rendered_element: &mut Self::ElementState,
cx: &mut gpui3::ViewContext<Self::ViewState>, cx: &mut gpui3::ViewContext<Self::ViewState>,
) { ) {
rendered_element.paint(view_state, None, cx) rendered_element.paint(view_state, cx)
} }
} }
}; };

View File

@ -1,9 +1,11 @@
mod focus; mod focus;
mod kitchen_sink; mod kitchen_sink;
mod scroll;
mod text; mod text;
mod z_index; mod z_index;
pub use focus::*; pub use focus::*;
pub use kitchen_sink::*; pub use kitchen_sink::*;
pub use scroll::*;
pub use text::*; pub use text::*;
pub use z_index::*; pub use z_index::*;

View File

@ -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()
})))
})
}
}

View File

@ -19,6 +19,7 @@ pub enum ElementStory {
Icon, Icon,
Input, Input,
Label, Label,
Scroll,
Text, Text,
ZIndex, ZIndex,
} }
@ -46,6 +47,7 @@ impl ElementStory {
Self::Label => { Self::Label => {
view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().into_any()).into_any() 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::Text => TextStory::view(cx).into_any(),
Self::ZIndex => { Self::ZIndex => {
view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().into_any()).into_any() view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().into_any()).into_any()