diff --git a/gpui/src/elements/uniform_list.rs b/gpui/src/elements/uniform_list.rs index aefe30e67b20220d96b7924ac96d91939a910852..f499801e6384380eed8875068c498a3ffa930ab3 100644 --- a/gpui/src/elements/uniform_list.rs +++ b/gpui/src/elements/uniform_list.rs @@ -43,6 +43,8 @@ where state: UniformListState, item_count: usize, append_items: F, + padding_top: f32, + padding_bottom: f32, } impl UniformList @@ -54,9 +56,21 @@ where state, item_count, append_items, + padding_top: 0., + padding_bottom: 0., } } + pub fn with_padding_top(mut self, padding: f32) -> Self { + self.padding_top = padding; + self + } + + pub fn with_padding_bottom(mut self, padding: f32) -> Self { + self.padding_bottom = padding; + self + } + fn scroll( &self, _: Vector2F, @@ -84,7 +98,7 @@ where } if let Some(item_ix) = state.scroll_to.take() { - let item_top = item_ix as f32 * item_height; + let item_top = self.padding_top + item_ix as f32 * item_height; let item_bottom = item_top + item_height; if item_top < state.scroll_top { @@ -137,11 +151,16 @@ where size.set_y(size.y().min(scroll_height).max(constraint.min.y())); } - scroll_max = (item_height * self.item_count as f32 - size.y()).max(0.); + let scroll_height = + item_height * self.item_count as f32 + self.padding_top + self.padding_bottom; + scroll_max = (scroll_height - size.y()).max(0.); self.autoscroll(scroll_max, size.y(), item_height); items.clear(); - let start = cmp::min((self.scroll_top() / item_height) as usize, self.item_count); + let start = cmp::min( + ((self.scroll_top() - self.padding_top) / item_height) as usize, + self.item_count, + ); let end = cmp::min( self.item_count, start + (size.y() / item_height).ceil() as usize + 1, @@ -173,8 +192,11 @@ where ) -> Self::PaintState { cx.scene.push_layer(Some(bounds)); - let mut item_origin = - bounds.origin() - vec2f(0.0, self.state.scroll_top() % layout.item_height); + let mut item_origin = bounds.origin() + - vec2f( + 0., + (self.state.scroll_top() - self.padding_top) % layout.item_height, + ); for item in &mut layout.items { item.paint(item_origin, visible_bounds, cx); diff --git a/zed/assets/themes/_base.toml b/zed/assets/themes/_base.toml index 236e308543f27cd7b0e4a5102b1840cd9cf2349e..ddbd0fc86ea7793c6a3d2551cba33177e76b9cbd 100644 --- a/zed/assets/themes/_base.toml +++ b/zed/assets/themes/_base.toml @@ -18,6 +18,7 @@ padding = { right = 4 } width = 16 [workspace.tab] +height = 34 text = "$text.2" padding = { left = 12, right = 12 } icon_width = 8 @@ -26,10 +27,11 @@ icon_close = "$text.2.color" icon_close_active = "$text.0.color" icon_dirty = "$status.info" icon_conflict = "$status.warn" -border = { left = true, bottom = true, width = 1, color = "$border.0" } +border = { left = true, bottom = true, width = 1, color = "$border.0", overlay = true } [workspace.active_tab] extends = "$workspace.tab" +border.bottom = false background = "$surface.1" text = "$text.0" @@ -41,13 +43,14 @@ border = { right = true, width = 1, color = "$border.0" } padding = { left = 1 } background = "$border.0" -[workspace.sidebar.icon] -color = "$text.2.color" -height = 18 +[workspace.sidebar.item] +icon_color = "$text.2.color" +icon_size = 18 +height = "$workspace.tab.height" -[workspace.sidebar.active_icon] -extends = "$workspace.sidebar.icon" -color = "$text.0.color" +[workspace.sidebar.active_item] +extends = "$workspace.sidebar.item" +icon_color = "$text.0.color" [workspace.left_sidebar] extends = "$workspace.sidebar" @@ -58,7 +61,7 @@ extends = "$workspace.sidebar" border = { width = 1, color = "$border.0", left = true } [panel] -padding = 12 +padding = { top = 12, left = 12, bottom = 12, right = 12 } [chat_panel] extends = "$panel" @@ -161,12 +164,11 @@ corner_radius = 6 [project_panel] extends = "$panel" -padding = 0 -entry_base_padding = "$panel.padding" +padding.top = 6 # ($workspace.tab.height - $project_panel.entry.height) / 2 [project_panel.entry] text = "$text.1" -padding = { top = 3, bottom = 3 } +height = 22 icon_color = "$text.3.color" icon_size = 8 icon_spacing = 8 diff --git a/zed/src/project_panel.rs b/zed/src/project_panel.rs index 82ae9f1892291c85883617315cff7de11f09a9b1..06f706734602d8fede968451a6d8ea6af5c8c06b 100644 --- a/zed/src/project_panel.rs +++ b/zed/src/project_panel.rs @@ -507,11 +507,15 @@ impl ProjectPanel { Label::new(details.filename, style.text.clone()) .contained() .with_margin_left(style.icon_spacing) + .aligned() + .left() .boxed(), ) + .constrained() + .with_height(theme.entry.height) .contained() .with_style(style.container) - .with_padding_left(theme.entry_base_padding + details.depth as f32 * 20.) + .with_padding_left(theme.container.padding.left + details.depth as f32 * 20.) .boxed() }, ) @@ -534,6 +538,8 @@ impl View for ProjectPanel { fn render(&mut self, _: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { let settings = self.settings.clone(); + let mut container_style = settings.borrow().theme.project_panel.container; + let padding = std::mem::take(&mut container_style.padding); let handle = self.handle.clone(); UniformList::new( self.list.clone(), @@ -551,8 +557,10 @@ impl View for ProjectPanel { }) }, ) + .with_padding_top(padding.top) + .with_padding_bottom(padding.bottom) .contained() - .with_style(self.settings.borrow().theme.project_panel.container) + .with_style(container_style) .boxed() } diff --git a/zed/src/theme.rs b/zed/src/theme.rs index 1153b76dce054b403d2628c91028a92a298f2835..0788cacb47ef07f4e3260e0646a25ab655e338d5 100644 --- a/zed/src/theme.rs +++ b/zed/src/theme.rs @@ -67,6 +67,7 @@ pub struct OfflineIcon { #[derive(Clone, Deserialize)] pub struct Tab { + pub height: f32, #[serde(flatten)] pub container: ContainerStyle, #[serde(flatten)] @@ -84,14 +85,15 @@ pub struct Sidebar { #[serde(flatten)] pub container: ContainerStyle, pub width: f32, - pub icon: SidebarIcon, - pub active_icon: SidebarIcon, + pub item: SidebarItem, + pub active_item: SidebarItem, pub resize_handle: ContainerStyle, } #[derive(Deserialize)] -pub struct SidebarIcon { - pub color: Color, +pub struct SidebarItem { + pub icon_color: Color, + pub icon_size: f32, pub height: f32, } @@ -107,18 +109,18 @@ pub struct ChatPanel { pub hovered_sign_in_prompt: TextStyle, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct ProjectPanel { #[serde(flatten)] pub container: ContainerStyle, - pub entry_base_padding: f32, pub entry: ProjectPanelEntry, pub hovered_entry: ProjectPanelEntry, pub selected_entry: ProjectPanelEntry, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct ProjectPanelEntry { + pub height: f32, #[serde(flatten)] pub container: ContainerStyle, pub text: TextStyle, diff --git a/zed/src/workspace/pane.rs b/zed/src/workspace/pane.rs index 31ec57354ad131f8542f211c5ee88cfb2520ad8f..6af62e8d1d80bf84e0392ac7510ee4f4733933ea 100644 --- a/zed/src/workspace/pane.rs +++ b/zed/src/workspace/pane.rs @@ -2,12 +2,11 @@ use super::{ItemViewHandle, SplitDirection}; use crate::settings::Settings; use gpui::{ action, - color::Color, elements::*, geometry::{rect::RectF, vector::vec2f}, keymap::Binding, platform::CursorStyle, - Border, Entity, MutableAppContext, Quad, RenderContext, View, ViewContext, ViewHandle, + Entity, MutableAppContext, Quad, RenderContext, View, ViewContext, ViewHandle, }; use postage::watch; use std::{cmp, path::Path, sync::Arc}; @@ -180,10 +179,6 @@ impl Pane { fn render_tabs(&self, cx: &mut RenderContext) -> ElementBox { let settings = self.settings.borrow(); let theme = &settings.theme; - let line_height = cx.font_cache().line_height( - theme.workspace.tab.label.text.font_id, - theme.workspace.tab.label.text.font_size, - ); enum Tabs {} let tabs = MouseEventHandler::new::(0, cx, |mouse_state, cx| { @@ -202,12 +197,11 @@ impl Pane { title.push('…'); } - let mut style = theme.workspace.tab.clone(); - if is_active { - style = theme.workspace.active_tab.clone(); - style.container.border.bottom = false; - style.container.padding.bottom += style.container.border.width; - } + let mut style = if is_active { + theme.workspace.active_tab.clone() + } else { + theme.workspace.tab.clone() + }; if ix == 0 { style.container.border.left = false; } @@ -319,26 +313,11 @@ impl Pane { }) } - // Ensure there's always a minimum amount of space after the last tab, - // so that the tab's border doesn't abut the window's border. - let mut border = Border::bottom(1.0, Color::default()); - border.color = theme.workspace.tab.container.border.color; - - row.add_child( - ConstrainedBox::new( - Container::new(Empty::new().boxed()) - .with_border(border) - .boxed(), - ) - .with_min_width(20.) - .named("fixed-filler"), - ); - row.add_child( Expanded::new( 0.0, Container::new(Empty::new().boxed()) - .with_border(border) + .with_border(theme.workspace.tab.container.border) .boxed(), ) .named("filler"), @@ -348,7 +327,7 @@ impl Pane { }); ConstrainedBox::new(tabs.boxed()) - .with_height(line_height + 16.) + .with_height(theme.workspace.tab.height) .named("tabs") } } diff --git a/zed/src/workspace/sidebar.rs b/zed/src/workspace/sidebar.rs index 3ceba15df0051701873c472a993ced0fe0b0ed64..5e8d8c2f9c1f9ee7e5586bf32db5699fc124757b 100644 --- a/zed/src/workspace/sidebar.rs +++ b/zed/src/workspace/sidebar.rs @@ -68,11 +68,6 @@ impl Sidebar { pub fn render(&self, settings: &Settings, cx: &mut RenderContext) -> ElementBox { let side = self.side; - let theme = &settings.theme; - let line_height = cx.font_cache().line_height( - theme.workspace.tab.label.text.font_id, - theme.workspace.tab.label.text.font_size, - ); let theme = self.theme(settings); ConstrainedBox::new( @@ -80,9 +75,9 @@ impl Sidebar { Flex::column() .with_children(self.items.iter().enumerate().map(|(item_index, item)| { let theme = if Some(item_index) == self.active_item_ix { - &theme.active_icon + &theme.active_item } else { - &theme.icon + &theme.item }; enum SidebarButton {} MouseEventHandler::new::( @@ -93,15 +88,15 @@ impl Sidebar { Align::new( ConstrainedBox::new( Svg::new(item.icon_path) - .with_color(theme.color) + .with_color(theme.icon_color) .boxed(), ) - .with_height(theme.height) + .with_height(theme.icon_size) .boxed(), ) .boxed(), ) - .with_height(line_height + 16.0) + .with_height(theme.height) .boxed() }, )