From eca9f495a1211684146f845e81ea1375690d28e5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 27 Apr 2021 11:58:59 -0600 Subject: [PATCH] Render a close tab button on tab hover Co-Authored-By: Max Brunsfeld --- gpui/src/elements/mouse_event_handler.rs | 4 +- gpui/src/elements/svg.rs | 8 +- gpui/src/platform/mac/sprite_cache.rs | 6 +- gpui/src/scene.rs | 4 +- zed/assets/.gitkeep | 0 zed/assets/icons/x.svg | 3 + zed/src/file_finder.rs | 2 +- zed/src/workspace/pane.rs | 140 +++++++++++++---------- 8 files changed, 96 insertions(+), 71 deletions(-) delete mode 100644 zed/assets/.gitkeep create mode 100644 zed/assets/icons/x.svg diff --git a/gpui/src/elements/mouse_event_handler.rs b/gpui/src/elements/mouse_event_handler.rs index 7554b53a6bff0e884709d203244e8ff230f310be..6d15a9709ef639ade7f8e5013a8df5f087034cec 100644 --- a/gpui/src/elements/mouse_event_handler.rs +++ b/gpui/src/elements/mouse_event_handler.rs @@ -12,8 +12,8 @@ pub struct MouseEventHandler { #[derive(Clone, Copy, Debug, Default)] pub struct MouseState { - hovered: bool, - clicked: bool, + pub hovered: bool, + pub clicked: bool, } impl MouseEventHandler { diff --git a/gpui/src/elements/svg.rs b/gpui/src/elements/svg.rs index 12b08b154c9a572e1ee2743cbf6317a50a38d352..b52112f65c664234e81db93bdce647f8291d5769 100644 --- a/gpui/src/elements/svg.rs +++ b/gpui/src/elements/svg.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use serde_json::json; use crate::{ @@ -11,14 +13,14 @@ use crate::{ }; pub struct Svg { - path: String, + path: Cow<'static, str>, color: ColorU, } impl Svg { - pub fn new(path: String) -> Self { + pub fn new(path: impl Into>) -> Self { Self { - path, + path: path.into(), color: ColorU::black(), } } diff --git a/gpui/src/platform/mac/sprite_cache.rs b/gpui/src/platform/mac/sprite_cache.rs index f73ebc6292a3928ee9d26e76cb5d6ac7f170dc40..bfb1c1f6013e2c6f64aca1c253974a7c320a1a07 100644 --- a/gpui/src/platform/mac/sprite_cache.rs +++ b/gpui/src/platform/mac/sprite_cache.rs @@ -9,7 +9,7 @@ use crate::{ use etagere::BucketedAtlasAllocator; use metal::{MTLPixelFormat, TextureDescriptor}; use ordered_float::OrderedFloat; -use std::{collections::HashMap, sync::Arc}; +use std::{borrow::Cow, collections::HashMap, sync::Arc}; #[derive(Hash, Eq, PartialEq)] struct GlyphDescriptor { @@ -29,7 +29,7 @@ pub struct GlyphSprite { #[derive(Hash, Eq, PartialEq)] struct IconDescriptor { - path: String, + path: Cow<'static, str>, width: i32, height: i32, } @@ -138,7 +138,7 @@ impl SpriteCache { pub fn render_icon( &mut self, size: Vector2F, - path: String, + path: Cow<'static, str>, svg: usvg::Tree, scale_factor: f32, ) -> IconSprite { diff --git a/gpui/src/scene.rs b/gpui/src/scene.rs index 44f9fcd1a06c3aec1a922dd2c74782a26a7b7bc6..10460ed2e0a526af5c4de1a7b6edac3bf823531f 100644 --- a/gpui/src/scene.rs +++ b/gpui/src/scene.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use serde_json::json; use crate::{ @@ -51,7 +53,7 @@ pub struct Glyph { pub struct Icon { pub bounds: RectF, pub svg: usvg::Tree, - pub path: String, + pub path: Cow<'static, str>, pub color: ColorU, } diff --git a/zed/assets/.gitkeep b/zed/assets/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/zed/assets/icons/x.svg b/zed/assets/icons/x.svg new file mode 100644 index 0000000000000000000000000000000000000000..c47eb9848c87acc04297e2abe6ccb5ab6eb3e7a7 --- /dev/null +++ b/zed/assets/icons/x.svg @@ -0,0 +1,3 @@ + + + diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index d6ec299593b4cbce237369304a8a028731042794..dcefdc7f8d780f931739333a2b194b4c120af59a 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -187,7 +187,7 @@ impl FileFinder { LineBox::new( settings.ui_font_family, settings.ui_font_size, - Svg::new("icons/file-16.svg".into()).boxed(), + Svg::new("icons/file-16.svg").boxed(), ) .boxed(), ) diff --git a/zed/src/workspace/pane.rs b/zed/src/workspace/pane.rs index 4767f30fda520b732ff030deefaaf81abbe22927..353a4f13e397d46c3507642e8a5d9d4272f426c4 100644 --- a/zed/src/workspace/pane.rs +++ b/zed/src/workspace/pane.rs @@ -183,54 +183,61 @@ impl Pane { let mut row = Flex::row(); let last_item_ix = self.items.len() - 1; for (ix, item) in self.items.iter().enumerate() { - let title = item.title(ctx); - - let mut border = Border::new(1.0, border_color); - border.left = ix > 0; - border.right = ix == last_item_ix; - border.bottom = ix != self.active_item; - - let padding = 6.; - let mut container = Container::new( - Stack::new() - .with_child( - Align::new( - Label::new(title, settings.ui_font_family, settings.ui_font_size) - .boxed(), - ) - .boxed(), - ) - .with_child( - LineBox::new( - settings.ui_font_family, - settings.ui_font_size, - Align::new(Self::render_modified_icon(item.is_dirty(ctx))) - .right() - .boxed(), - ) - .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); - } else { - container = container.with_background_color(ColorU::from_u32(0xeaeaebff)); - } - enum Tab {} row.add_child( Expanded::new( 1.0, MouseEventHandler::new::(item.id(), ctx, |mouse_state| { - log::info!("mouse event handler {:?}", mouse_state); + let title = item.title(ctx); + + let mut border = Border::new(1.0, border_color); + border.left = ix > 0; + border.right = ix == last_item_ix; + border.bottom = ix != self.active_item; + + let padding = 6.; + let mut container = Container::new( + Stack::new() + .with_child( + Align::new( + Label::new( + title, + settings.ui_font_family, + settings.ui_font_size, + ) + .boxed(), + ) + .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(), + ) + .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); + } else { + container = + container.with_background_color(ColorU::from_u32(0xeaeaebff)); + } + ConstrainedBox::new( EventHandler::new(container.boxed()) .on_mouse_down(move |ctx| { @@ -290,25 +297,36 @@ impl Pane { row.named("tabs") } - fn render_modified_icon(is_modified: bool) -> ElementBox { - let diameter = 8.; - ConstrainedBox::new( - Canvas::new(move |bounds, ctx| { - if is_modified { - let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); - ctx.scene.push_quad(Quad { - bounds: square, - background: Some(ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8()), - border: Default::default(), - corner_radius: diameter / 2., - }); - } - }) - .boxed(), - ) - .with_width(diameter) - .with_height(diameter) - .named("tab-right-icon") + fn render_tab_icon(tab_hovered: bool, is_modified: bool) -> ElementBox { + let modified_color = ColorU::from_u32(0x556de8ff); + 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") + } else { + let diameter = 8.; + ConstrainedBox::new( + Canvas::new(move |bounds, ctx| { + if is_modified { + let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); + ctx.scene.push_quad(Quad { + bounds: square, + background: Some(modified_color), + border: Default::default(), + corner_radius: diameter / 2., + }); + } + }) + .boxed(), + ) + .with_width(diameter) + .with_height(diameter) + .named("unsaved-tab-icon") + } } }