feat(workspace): add option for moving the tab close button to the left (#2739)

Fixes https://github.com/zed-industries/community/issues/1760

Release Notes:

- Add option for chosing where the close button should be displayed on
editor tabs
This commit is contained in:
Mikayla Maki 2023-07-17 13:10:42 -07:00 committed by GitHub
commit 1a8bfdfa21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 72 deletions

View file

@ -128,9 +128,12 @@
// 4. Save when idle for a certain amount of time:
// "autosave": { "after_delay": {"milliseconds": 500} },
"autosave": "off",
// Color tab titles based on the git status of the buffer.
// Settings related to the editor's tabs
"tabs": {
"git_status": false
// Show git status colors in the editor tabs.
"git_status": false,
// Position of the close button on the editor tabs.
"close_position": "right"
},
// Whether or not to remove any trailing whitespace from lines of a buffer
// before saving it.

View file

@ -723,12 +723,12 @@ pub struct Scrollbar {
pub thumb: ContainerStyle,
pub width: f32,
pub min_height_factor: f32,
pub git: FileGitDiffColors,
pub git: BufferGitDiffColors,
pub selections: Color,
}
#[derive(Clone, Deserialize, Default, JsonSchema)]
pub struct FileGitDiffColors {
pub struct BufferGitDiffColors {
pub inserted: Color,
pub modified: Color,
pub deleted: Color,

View file

@ -33,11 +33,30 @@ use theme::Theme;
#[derive(Deserialize)]
pub struct ItemSettings {
pub git_status: bool,
pub close_position: ClosePosition,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ClosePosition {
Left,
#[default]
Right,
}
impl ClosePosition {
pub fn right(&self) -> bool {
match self {
ClosePosition::Left => false,
ClosePosition::Right => true,
}
}
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ItemSettingsContent {
git_status: Option<bool>,
close_position: Option<ClosePosition>,
}
impl Setting for ItemSettings {

View file

@ -1370,81 +1370,94 @@ impl Pane {
container.border.left = false;
}
Flex::row()
.with_child({
let diameter = 7.0;
let icon_color = if item.has_conflict(cx) {
Some(tab_style.icon_conflict)
} else if item.is_dirty(cx) {
Some(tab_style.icon_dirty)
} else {
None
};
let buffer_jewel_element = {
let diameter = 7.0;
let icon_color = if item.has_conflict(cx) {
Some(tab_style.icon_conflict)
} else if item.is_dirty(cx) {
Some(tab_style.icon_dirty)
} else {
None
};
Canvas::new(move |scene, bounds, _, _, _| {
if let Some(color) = icon_color {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
scene.push_quad(Quad {
bounds: square,
background: Some(color),
border: Default::default(),
corner_radius: diameter / 2.,
});
}
})
.constrained()
.with_width(diameter)
.with_height(diameter)
.aligned()
Canvas::new(move |scene, bounds, _, _, _| {
if let Some(color) = icon_color {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
scene.push_quad(Quad {
bounds: square,
background: Some(color),
border: Default::default(),
corner_radius: diameter / 2.,
});
}
})
.with_child(title.aligned().contained().with_style(ContainerStyle {
margin: Margin {
left: tab_style.spacing,
right: tab_style.spacing,
..Default::default()
},
.constrained()
.with_width(diameter)
.with_height(diameter)
.aligned()
};
let title_element = title.aligned().contained().with_style(ContainerStyle {
margin: Margin {
left: tab_style.spacing,
right: tab_style.spacing,
..Default::default()
}))
.with_child(
if hovered {
let item_id = item.id();
enum TabCloseButton {}
let icon = Svg::new("icons/x_mark_8.svg");
MouseEventHandler::<TabCloseButton, _>::new(item_id, cx, |mouse_state, _| {
if mouse_state.hovered() {
icon.with_color(tab_style.icon_close_active)
} else {
icon.with_color(tab_style.icon_close)
}
})
.with_padding(Padding::uniform(4.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, {
let pane = pane.clone();
move |_, _, cx| {
let pane = pane.clone();
cx.window_context().defer(move |cx| {
if let Some(pane) = pane.upgrade(cx) {
pane.update(cx, |pane, cx| {
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
});
}
},
..Default::default()
});
let close_element = if hovered {
let item_id = item.id();
enum TabCloseButton {}
let icon = Svg::new("icons/x_mark_8.svg");
MouseEventHandler::<TabCloseButton, _>::new(item_id, cx, |mouse_state, _| {
if mouse_state.hovered() {
icon.with_color(tab_style.icon_close_active)
} else {
icon.with_color(tab_style.icon_close)
}
})
.with_padding(Padding::uniform(4.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, {
let pane = pane.clone();
move |_, _, cx| {
let pane = pane.clone();
cx.window_context().defer(move |cx| {
if let Some(pane) = pane.upgrade(cx) {
pane.update(cx, |pane, cx| {
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
});
}
})
.into_any_named("close-tab-icon")
.constrained()
} else {
Empty::new().constrained()
});
}
.with_width(tab_style.close_icon_width)
.aligned(),
)
.contained()
.with_style(container)
})
.into_any_named("close-tab-icon")
.constrained()
.with_height(tab_style.height)
.into_any()
} else {
Empty::new().constrained()
}
.with_width(tab_style.close_icon_width)
.aligned();
let close_right = settings::get::<ItemSettings>(cx).close_position.right();
if close_right {
Flex::row()
.with_child(buffer_jewel_element)
.with_child(title_element)
.with_child(close_element)
} else {
Flex::row()
.with_child(close_element)
.with_child(title_element)
.with_child(buffer_jewel_element)
}
.contained()
.with_style(container)
.constrained()
.with_height(tab_style.height)
.into_any()
}
pub fn render_tab_bar_button<