Align close tab icon cleanly with unsaved indicator

Nathan Sobo created

Change summary

gpui/src/app.rs           | 16 ++++++---
zed/assets/icons/x.svg    |  1 
zed/src/workspace/pane.rs | 68 ++++++++++++++++------------------------
3 files changed, 37 insertions(+), 48 deletions(-)

Detailed changes

gpui/src/app.rs 🔗

@@ -216,7 +216,7 @@ impl App {
     }
 
     pub fn font_cache(&self) -> Arc<FontCache> {
-        self.0.borrow().font_cache.clone()
+        self.0.borrow().ctx.font_cache.clone()
     }
 
     fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
@@ -326,7 +326,7 @@ impl TestAppContext {
     }
 
     pub fn font_cache(&self) -> Arc<FontCache> {
-        self.0.borrow().font_cache.clone()
+        self.0.borrow().ctx.font_cache.clone()
     }
 
     pub fn platform(&self) -> Rc<dyn platform::Platform> {
@@ -370,7 +370,6 @@ type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
 pub struct MutableAppContext {
     weak_self: Option<rc::Weak<RefCell<Self>>>,
     platform: Rc<dyn platform::Platform>,
-    font_cache: Arc<FontCache>,
     assets: Arc<AssetCache>,
     ctx: AppContext,
     actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
@@ -404,7 +403,6 @@ impl MutableAppContext {
         Self {
             weak_self: None,
             platform,
-            font_cache: Arc::new(FontCache::new(fonts)),
             assets: Arc::new(AssetCache::new(asset_source)),
             ctx: AppContext {
                 models: Default::default(),
@@ -413,6 +411,7 @@ impl MutableAppContext {
                 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
                 background: Arc::new(executor::Background::new()),
                 thread_pool: scoped_pool::Pool::new(num_cpus::get(), "app"),
+                font_cache: Arc::new(FontCache::new(fonts)),
             },
             actions: HashMap::new(),
             global_actions: HashMap::new(),
@@ -444,7 +443,7 @@ impl MutableAppContext {
     }
 
     pub fn font_cache(&self) -> &Arc<FontCache> {
-        &self.font_cache
+        &self.ctx.font_cache
     }
 
     pub fn foreground_executor(&self) -> &Rc<executor::Foreground> {
@@ -764,7 +763,7 @@ impl MutableAppContext {
         let text_layout_cache = TextLayoutCache::new(self.platform.fonts());
         let presenter = Rc::new(RefCell::new(Presenter::new(
             window_id,
-            self.font_cache.clone(),
+            self.ctx.font_cache.clone(),
             text_layout_cache,
             self.assets.clone(),
             self,
@@ -1327,6 +1326,7 @@ pub struct AppContext {
     background: Arc<executor::Background>,
     ref_counts: Arc<Mutex<RefCounts>>,
     thread_pool: scoped_pool::Pool,
+    font_cache: Arc<FontCache>,
 }
 
 impl AppContext {
@@ -1366,6 +1366,10 @@ impl AppContext {
         &self.background
     }
 
+    pub fn font_cache(&self) -> &FontCache {
+        &self.font_cache
+    }
+
     pub fn thread_pool(&self) -> &scoped_pool::Pool {
         &self.thread_pool
     }

zed/assets/icons/x.svg 🔗

@@ -1,3 +1,3 @@
-<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">

zed/src/workspace/pane.rs 🔗

@@ -1,7 +1,7 @@
 use super::{ItemViewHandle, SplitDirection};
 use crate::{settings::Settings, watch};
 use gpui::{
-    color::{ColorF, ColorU},
+    color::ColorU,
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
     keymap::Binding,
@@ -179,6 +179,10 @@ impl Pane {
     fn render_tabs(&self, ctx: &AppContext) -> ElementBox {
         let settings = smol::block_on(self.settings.read());
         let border_color = ColorU::from_u32(0xdbdbdcff);
+        let line_height = ctx.font_cache().line_height(
+            ctx.font_cache().default_font(settings.ui_font_family),
+            settings.ui_font_size,
+        );
 
         let mut row = Flex::row();
         let last_item_ix = self.items.len() - 1;
@@ -196,7 +200,6 @@ impl Pane {
                         border.right = ix == last_item_ix;
                         border.bottom = ix != self.active_item;
 
-                        let padding = 6.;
                         let mut container = Container::new(
                             Stack::new()
                                 .with_child(
@@ -211,28 +214,23 @@ impl Pane {
                                     .boxed(),
                                 )
                                 .with_child(
-                                    LineBox::new(
-                                        settings.ui_font_family,
-                                        settings.ui_font_size,
-                                        Align::new(Self::render_tab_icon(
-                                            mouse_state.hovered,
-                                            item.is_dirty(ctx),
-                                        ))
-                                        .right()
-                                        .boxed(),
-                                    )
+                                    Align::new(Self::render_tab_icon(
+                                        line_height - 2.,
+                                        mouse_state.hovered,
+                                        item.is_dirty(ctx),
+                                    ))
+                                    .right()
                                     .boxed(),
                                 )
                                 .boxed(),
                         )
-                        .with_vertical_padding(padding)
                         .with_horizontal_padding(10.)
                         .with_border(border);
 
                         if ix == self.active_item {
                             container = container
                                 .with_background_color(ColorU::white())
-                                .with_padding_bottom(padding + border.width);
+                                .with_padding_bottom(border.width);
                         } else {
                             container =
                                 container.with_background_color(ColorU::from_u32(0xeaeaebff));
@@ -260,17 +258,9 @@ impl Pane {
         // so that the tab's border doesn't abut the window's border.
         row.add_child(
             ConstrainedBox::new(
-                Container::new(
-                    LineBox::new(
-                        settings.ui_font_family,
-                        settings.ui_font_size,
-                        Empty::new().boxed(),
-                    )
+                Container::new(Empty::new().boxed())
+                    .with_border(Border::bottom(1.0, border_color))
                     .boxed(),
-                )
-                .with_uniform_padding(6.0)
-                .with_border(Border::bottom(1.0, border_color))
-                .boxed(),
             )
             .with_min_width(20.)
             .named("fixed-filler"),
@@ -279,34 +269,26 @@ impl Pane {
         row.add_child(
             Expanded::new(
                 0.0,
-                Container::new(
-                    LineBox::new(
-                        settings.ui_font_family,
-                        settings.ui_font_size,
-                        Empty::new().boxed(),
-                    )
+                Container::new(Empty::new().boxed())
+                    .with_border(Border::bottom(1.0, border_color))
                     .boxed(),
-                )
-                .with_uniform_padding(6.0)
-                .with_border(Border::bottom(1.0, border_color))
-                .boxed(),
             )
             .named("filler"),
         );
 
-        row.named("tabs")
+        ConstrainedBox::new(row.boxed())
+            .with_height(line_height + 16.)
+            .named("tabs")
     }
 
-    fn render_tab_icon(tab_hovered: bool, is_modified: bool) -> ElementBox {
+    fn render_tab_icon(close_icon_size: f32, tab_hovered: bool, is_modified: bool) -> ElementBox {
         let modified_color = ColorU::from_u32(0x556de8ff);
-        if tab_hovered {
+        let icon = if tab_hovered {
             let mut icon = Svg::new("icons/x.svg");
             if is_modified {
                 icon = icon.with_color(modified_color);
             }
-            ConstrainedBox::new(icon.boxed())
-                .with_width(10.)
-                .named("close-tab-icon")
+            icon.named("close-tab-icon")
         } else {
             let diameter = 8.;
             ConstrainedBox::new(
@@ -326,7 +308,11 @@ impl Pane {
             .with_width(diameter)
             .with_height(diameter)
             .named("unsaved-tab-icon")
-        }
+        };
+
+        ConstrainedBox::new(Align::new(icon).boxed())
+            .with_width(close_icon_size)
+            .named("tab-icon")
     }
 }