Checkpoint

Mikayla created

Change summary

crates/gpui2/src/app.rs                 |  8 +-
crates/gpui2/src/elements/list.rs       | 18 ++++++-
crates/gpui2/src/elements/text.rs       |  1 
crates/gpui2/src/text_system/line.rs    |  7 +-
crates/gpui2/src/window.rs              |  2 
crates/picker2/src/picker2.rs           | 24 ++++++----
crates/storybook2/src/stories/picker.rs | 58 +++++++++++++++++++++-----
7 files changed, 85 insertions(+), 33 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -48,15 +48,15 @@ pub struct AppCell {
 impl AppCell {
     #[track_caller]
     pub fn borrow(&self) -> AppRef {
-        let thread_id = std::thread::current().id();
-        eprintln!("borrowed {thread_id:?}");
+        // let thread_id = std::thread::current().id();
+        // eprintln!("borrowed {thread_id:?}");
         AppRef(self.app.borrow())
     }
 
     #[track_caller]
     pub fn borrow_mut(&self) -> AppRefMut {
-        let thread_id = std::thread::current().id();
-        eprintln!("borrowed {thread_id:?}");
+        // let thread_id = std::thread::current().id();
+        // eprintln!("borrowed {thread_id:?}");
         AppRefMut(self.app.borrow_mut())
     }
 }

crates/gpui2/src/elements/list.rs 🔗

@@ -1,4 +1,4 @@
-use std::ops::Range;
+use std::{cmp, ops::Range};
 
 use smallvec::SmallVec;
 
@@ -113,14 +113,24 @@ impl<V: 'static> Element<V> for List<V> {
 
         if self.item_count > 0 {
             let item_height = self.measure_item_height(view_state, padded_bounds, cx);
-            let visible_item_count = (padded_bounds.size.height / item_height) as usize;
-            let visible_range = 0..visible_item_count;
+            let visible_item_count = (padded_bounds.size.height / item_height).ceil() as usize;
+            let visible_range = 0..cmp::min(visible_item_count, self.item_count);
 
             let mut items = (self.render_items)(view_state, visible_range, cx);
 
+            dbg!(items.len(), self.item_count, visible_item_count);
+
             for (ix, item) in items.iter_mut().enumerate() {
                 item.initialize(view_state, cx);
-                item.layout(view_state, cx);
+
+                let layout_id = item.layout(view_state, cx);
+                cx.compute_layout(
+                    layout_id,
+                    Size {
+                        width: AvailableSpace::Definite(bounds.size.width),
+                        height: AvailableSpace::Definite(item_height),
+                    },
+                );
                 let offset = padded_bounds.origin + point(px(0.), item_height * ix);
                 cx.with_element_offset(Some(offset), |cx| item.paint(view_state, cx))
             }

crates/gpui2/src/elements/text.rs 🔗

@@ -127,6 +127,7 @@ impl<V: 'static> Element<V> for Text<V> {
         let element_state = element_state
             .as_ref()
             .expect("measurement has not been performed");
+
         let line_height = element_state.line_height;
         let mut line_origin = bounds.origin;
         for line in &element_state.lines {

crates/gpui2/src/text_system/line.rs 🔗

@@ -78,7 +78,6 @@ impl Line {
                     glyph_origin.y += line_height;
                 }
                 prev_glyph_position = glyph.position;
-                let glyph_origin = glyph_origin + baseline_offset;
 
                 let mut finished_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
                 if glyph.index >= run_end {
@@ -129,20 +128,22 @@ impl Line {
                 if max_glyph_bounds.intersects(&content_mask.bounds) {
                     if glyph.is_emoji {
                         cx.paint_emoji(
-                            glyph_origin,
+                            glyph_origin + baseline_offset,
                             run.font_id,
                             glyph.id,
                             self.layout.layout.font_size,
                         )?;
                     } else {
                         cx.paint_glyph(
-                            glyph_origin,
+                            glyph_origin + baseline_offset,
                             run.font_id,
                             glyph.id,
                             self.layout.layout.font_size,
                             color,
                         )?;
                     }
+                } else {
+                    dbg!(content_mask.bounds, max_glyph_bounds);
                 }
             }
         }

crates/gpui2/src/window.rs 🔗

@@ -792,6 +792,7 @@ impl<'a> WindowContext<'a> {
     }
 
     /// Paint a monochrome (non-emoji) glyph into the scene for the current frame at the current z-index.
+    /// The y component of the origin is the baseline of the glyph.
     pub fn paint_glyph(
         &mut self,
         origin: Point<Pixels>,
@@ -845,6 +846,7 @@ impl<'a> WindowContext<'a> {
     }
 
     /// Paint an emoji glyph into the scene for the current frame at the current z-index.
+    /// The y component of the origin is the baseline of the glyph.
     pub fn paint_emoji(
         &mut self,
         origin: Point<Pixels>,

crates/picker2/src/picker2.rs 🔗

@@ -21,7 +21,8 @@
 use std::ops::Range;
 
 use gpui::{
-    div, list, AppContext, Component, Div, Element, ElementId, ParentElement, Render, ViewContext,
+    div, list, red, AppContext, Component, Div, Element, ElementId, ParentElement, Render, Styled,
+    ViewContext,
 };
 
 // pub struct Picker<D> {
@@ -97,15 +98,18 @@ impl<V: PickerDelegate> Picker<V> {
 
 impl<V: 'static + PickerDelegate> Picker<V> {
     pub fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
-        div().id(self.id.clone()).child(list(
-            "candidates",
-            view.match_count(self.id.clone()),
-            move |this: &mut V, visible_range, cx| {
-                visible_range
-                    .map(|ix| this.render_match(ix, false, false, false, self.id.clone(), cx))
-                    .collect()
-            },
-        ))
+        div().size_full().id(self.id.clone()).child(
+            list(
+                "candidates",
+                view.match_count(self.id.clone()),
+                move |this: &mut V, visible_range, cx| {
+                    visible_range
+                        .map(|ix| this.render_match(ix, false, false, false, self.id.clone(), cx))
+                        .collect()
+                },
+            )
+            .size_full(),
+        )
     }
 }
 

crates/storybook2/src/stories/picker.rs 🔗

@@ -1,33 +1,64 @@
-use gpui::{div, Div, ParentElement, Render, View, VisualContext, WindowContext};
+use gpui::{
+    black, div, red, Div, Fill, ParentElement, Render, SharedString, Styled, View, VisualContext,
+    WindowContext,
+};
 use picker::{Picker, PickerDelegate};
 
 pub struct PickerStory {
-    //     picker: View<Picker<PickerStoryDelegate>>,
+    candidates: Vec<SharedString>,
 }
 
 impl PickerDelegate for PickerStory {
-    type ListItem = Div<Self>;
+    type ListItem = SharedString;
 
-    fn match_count(&self, picker_id: gpui::ElementId) -> usize {
-        0
+    fn match_count(&self, _picker_id: gpui::ElementId) -> usize {
+        self.candidates.len()
     }
 
     fn render_match(
         &self,
         ix: usize,
-        active: bool,
-        hovered: bool,
-        selected: bool,
-        picker_id: gpui::ElementId,
+        _active: bool,
+        _hovered: bool,
+        _selected: bool,
+        _picker_id: gpui::ElementId,
         cx: &mut gpui::ViewContext<Self>,
     ) -> Self::ListItem {
-        todo!()
+        self.candidates[ix].clone()
     }
 }
 
 impl PickerStory {
     pub fn new(cx: &mut WindowContext) -> View<Self> {
-        cx.build_view(|cx| PickerStory {})
+        cx.build_view(|cx| PickerStory {
+            candidates: vec![
+                "Pizza (Italy)".into(),
+                "Sushi (Japan)".into(),
+                "Paella (Spain)".into(),
+                "Tacos (Mexico)".into(),
+                "Peking Duck (China)".into(),
+                "Fish and Chips (UK)".into(),
+                "Croissant (France)".into(),
+                "Bratwurst (Germany)".into(),
+                "Poutine (Canada)".into(),
+                "Chicken Tikka Masala (India)".into(),
+                "Feijoada (Brazil)".into(),
+                "Kimchi (Korea)".into(),
+                "Borscht (Ukraine)".into(),
+                "Falafel (Middle East)".into(),
+                "Baklava (Turkey)".into(),
+                "Shepherd's Pie (Ireland)".into(),
+                "Rendang (Indonesia)".into(),
+                "Kebab (Middle East)".into(),
+                "Ceviche (Peru)".into(),
+                "Pierogi (Poland)".into(),
+                "Churrasco (Brazil)".into(),
+                "Moussaka (Greece)".into(),
+                "Lasagna (Italy)".into(),
+                "Pad Thai (Thailand)".into(),
+                "Pho (Vietnam)".into(),
+            ],
+        })
     }
 }
 
@@ -35,6 +66,9 @@ impl Render for PickerStory {
     type Element = Div<Self>;
 
     fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
-        div().child(Picker::new("picker_story"))
+        div()
+            .text_color(red())
+            .size_full()
+            .child(Picker::new("picker_story"))
     }
 }