Detailed changes
@@ -21,28 +21,18 @@
"color": "#576ddb",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#e2dfe7",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#576ddb",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#5852607a",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#e2dfe7",
+ "size": 14
+ }
},
- "background": "#5852607a"
+ "hover": {
+ "background": "#58526052"
+ }
},
"border": {
"color": "#19171c",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#efecf4",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#576ddb",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#26232a",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#576ddb",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#8b87922e",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#26232a",
+ "size": 14
+ }
},
- "background": "#8b87922e"
+ "hover": {
+ "background": "#8b87921f"
+ }
},
"border": {
"color": "#efecf4",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#19171c",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#4f8ff7",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#f1f1f1",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#4f8ff7",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#2b2b2b",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#f1f1f1",
+ "size": 14
+ }
},
- "background": "#2b2b2b"
+ "hover": {
+ "background": "#232323"
+ }
},
"border": {
"color": "#070707",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#ffffff",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#484bed",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#2b2b2b",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#484bed",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#e3e3e3",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#2b2b2b",
+ "size": 14
+ }
},
- "background": "#e3e3e3"
+ "hover": {
+ "background": "#eaeaea"
+ }
},
"border": {
"color": "#d5d5d5",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#000000",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#268bd2",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#eee8d5",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#268bd2",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#586e757a",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#eee8d5",
+ "size": 14
+ }
},
- "background": "#586e757a"
+ "hover": {
+ "background": "#586e7552"
+ }
},
"border": {
"color": "#002b36",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#fdf6e3",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#268bd2",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#073642",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#268bd2",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#93a1a12e",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#073642",
+ "size": 14
+ }
},
- "background": "#93a1a12e"
+ "hover": {
+ "background": "#93a1a11f"
+ }
},
"border": {
"color": "#fdf6e3",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#002b36",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#3d8fd1",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#dfe2f1",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#3d8fd1",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#5e66877a",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#dfe2f1",
+ "size": 14
+ }
},
- "background": "#5e66877a"
+ "hover": {
+ "background": "#5e668752"
+ }
},
"border": {
"color": "#202746",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#f5f7ff",
+ "size": 12
+ }
}
}
},
@@ -21,28 +21,18 @@
"color": "#3d8fd1",
"weight": "bold",
"size": 14
- }
- },
- "active_item": {
- "padding": {
- "bottom": 4,
- "left": 12,
- "right": 12,
- "top": 4
},
- "corner_radius": 8,
- "text": {
- "family": "Zed Sans",
- "color": "#293256",
- "size": 14
- },
- "highlight_text": {
- "family": "Zed Sans",
- "color": "#3d8fd1",
- "weight": "bold",
- "size": 14
+ "active": {
+ "background": "#979db42e",
+ "text": {
+ "family": "Zed Sans",
+ "color": "#293256",
+ "size": 14
+ }
},
- "background": "#979db42e"
+ "hover": {
+ "background": "#979db41f"
+ }
},
"border": {
"color": "#f5f7ff",
@@ -906,6 +896,13 @@
},
"margin": {
"left": 2
+ },
+ "active": {
+ "text": {
+ "family": "Zed Mono",
+ "color": "#202746",
+ "size": 12
+ }
}
}
},
@@ -1,7 +1,7 @@
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
actions,
- elements::{ChildView, Flex, Label, ParentElement},
+ elements::{ChildView, Flex, Label, MouseState, ParentElement},
keymap::Keystroke,
Action, Element, Entity, MutableAppContext, View, ViewContext, ViewHandle,
};
@@ -200,17 +200,19 @@ impl PickerDelegate for CommandPalette {
}
}
- fn render_match(&self, ix: usize, selected: bool, cx: &gpui::AppContext) -> gpui::ElementBox {
+ fn render_match(
+ &self,
+ ix: usize,
+ mouse_state: &MouseState,
+ selected: bool,
+ cx: &gpui::AppContext,
+ ) -> gpui::ElementBox {
let mat = &self.matches[ix];
let command = &self.actions[mat.candidate_id];
let settings = cx.global::<Settings>();
let theme = &settings.theme;
- let style = if selected {
- &theme.picker.active_item
- } else {
- &theme.picker.item
- };
- let key_style = &theme.command_palette.key;
+ let style = theme.picker.item.style_for(mouse_state, selected);
+ let key_style = &theme.command_palette.key.style_for(mouse_state, selected);
let keystroke_spacing = theme.command_palette.keystroke_spacing;
Flex::row()
@@ -95,12 +95,8 @@ impl View for DiagnosticIndicator {
.theme
.workspace
.status_bar
- .diagnostic_summary;
- let style = if state.hovered {
- style.hover()
- } else {
- &style.default
- };
+ .diagnostic_summary
+ .style_for(state, false);
let mut summary_row = Flex::row();
if self.summary.error_count > 0 {
@@ -190,11 +186,7 @@ impl View for DiagnosticIndicator {
MouseEventHandler::new::<Message, _, _>(1, cx, |state, _| {
Label::new(
diagnostic.message.split('\n').next().unwrap().to_string(),
- if state.hovered {
- message_style.hover().text.clone()
- } else {
- message_style.default.text.clone()
- },
+ message_style.style_for(state, false).text.clone(),
)
.aligned()
.contained()
@@ -223,14 +223,16 @@ impl PickerDelegate for FileFinder {
cx.emit(Event::Dismissed);
}
- fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox {
+ fn render_match(
+ &self,
+ ix: usize,
+ mouse_state: &MouseState,
+ selected: bool,
+ cx: &AppContext,
+ ) -> ElementBox {
let path_match = &self.matches[ix];
let settings = cx.global::<Settings>();
- let style = if selected {
- &settings.theme.picker.active_item
- } else {
- &settings.theme.picker.item
- };
+ let style = settings.theme.picker.item.style_for(mouse_state, selected);
let (file_name, file_name_positions, full_path, full_path_positions) =
self.labels_for_match(path_match);
Flex::column()
@@ -228,14 +228,16 @@ impl PickerDelegate for OutlineView {
cx.emit(Event::Dismissed);
}
- fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox {
+ fn render_match(
+ &self,
+ ix: usize,
+ mouse_state: &MouseState,
+ selected: bool,
+ cx: &AppContext,
+ ) -> ElementBox {
let settings = cx.global::<Settings>();
let string_match = &self.matches[ix];
- let style = if selected {
- &settings.theme.picker.active_item
- } else {
- &settings.theme.picker.item
- };
+ let style = settings.theme.picker.item.style_for(mouse_state, selected);
let outline_item = &self.outline.items[string_match.candidate_id];
Text::new(outline_item.text.clone(), style.label.text.clone())
@@ -1,12 +1,14 @@
use editor::Editor;
use gpui::{
elements::{
- ChildView, EventHandler, Flex, Label, ParentElement, ScrollTarget, UniformList,
- UniformListState,
+ ChildView, Flex, Label, MouseEventHandler, MouseState, ParentElement, ScrollTarget,
+ UniformList, UniformListState,
},
geometry::vector::{vec2f, Vector2F},
- keymap, AppContext, Axis, Element, ElementBox, Entity, MutableAppContext, RenderContext, Task,
- View, ViewContext, ViewHandle, WeakViewHandle,
+ keymap,
+ platform::CursorStyle,
+ AppContext, Axis, Element, ElementBox, Entity, MutableAppContext, RenderContext, Task, View,
+ ViewContext, ViewHandle, WeakViewHandle,
};
use settings::Settings;
use std::cmp;
@@ -29,7 +31,13 @@ pub trait PickerDelegate: View {
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Self>) -> Task<()>;
fn confirm(&mut self, cx: &mut ViewContext<Self>);
fn dismiss(&mut self, cx: &mut ViewContext<Self>);
- fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox;
+ fn render_match(
+ &self,
+ ix: usize,
+ state: &MouseState,
+ selected: bool,
+ cx: &AppContext,
+ ) -> ElementBox;
fn center_selection_after_match_updates(&self) -> bool {
false
}
@@ -73,18 +81,18 @@ impl<D: PickerDelegate> View for Picker<D> {
self.list_state.clone(),
match_count,
move |mut range, items, cx| {
- let cx = cx.as_ref();
let delegate = delegate.upgrade(cx).unwrap();
- let delegate = delegate.read(cx);
- let selected_ix = delegate.selected_index();
- range.end = cmp::min(range.end, delegate.match_count());
+ let selected_ix = delegate.read(cx).selected_index();
+ range.end = cmp::min(range.end, delegate.read(cx).match_count());
items.extend(range.map(move |ix| {
- EventHandler::new(delegate.render_match(ix, ix == selected_ix, cx))
- .on_mouse_down(move |cx| {
- cx.dispatch_action(SelectIndex(ix));
- true
- })
- .boxed()
+ MouseEventHandler::new::<D, _, _>(ix, cx, |state, cx| {
+ delegate
+ .read(cx)
+ .render_match(ix, state, ix == selected_ix, cx)
+ })
+ .on_mouse_down(move |cx| cx.dispatch_action(SelectIndex(ix)))
+ .with_cursor_style(CursorStyle::PointingHand)
+ .boxed()
}));
},
)
@@ -220,14 +220,17 @@ impl PickerDelegate for ProjectSymbolsView {
Task::ready(())
}
- fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox {
+ fn render_match(
+ &self,
+ ix: usize,
+ mouse_state: &MouseState,
+ selected: bool,
+ cx: &AppContext,
+ ) -> ElementBox {
let string_match = &self.matches[ix];
let settings = cx.global::<Settings>();
- let style = if selected {
- &settings.theme.picker.active_item
- } else {
- &settings.theme.picker.item
- };
+ let style = &settings.theme.picker.item;
+ let current_style = style.style_for(mouse_state, selected);
let symbol = &self.symbols[string_match.candidate_id];
let syntax_runs = styled_runs_for_code_label(&symbol.label, &settings.theme.editor.syntax);
@@ -246,11 +249,11 @@ impl PickerDelegate for ProjectSymbolsView {
Flex::column()
.with_child(
- Text::new(symbol.label.text.clone(), style.label.text.clone())
+ Text::new(symbol.label.text.clone(), current_style.label.text.clone())
.with_soft_wrap(false)
.with_highlights(combine_syntax_and_fuzzy_match_highlights(
&symbol.label.text,
- style.label.text.clone().into(),
+ current_style.label.text.clone().into(),
syntax_runs,
&string_match.positions,
))
@@ -259,10 +262,10 @@ impl PickerDelegate for ProjectSymbolsView {
.with_child(
// Avoid styling the path differently when it is selected, since
// the symbol's syntax highlighting doesn't change when selected.
- Label::new(path.to_string(), settings.theme.picker.item.label.clone()).boxed(),
+ Label::new(path.to_string(), style.default.label.clone()).boxed(),
)
.contained()
- .with_style(style.container)
+ .with_style(current_style.container)
.boxed()
}
}
@@ -2,7 +2,7 @@ mod theme_registry;
use gpui::{
color::Color,
- elements::{ContainerStyle, ImageStyle, LabelStyle},
+ elements::{ContainerStyle, ImageStyle, LabelStyle, MouseState},
fonts::{HighlightStyle, TextStyle},
Border,
};
@@ -229,7 +229,7 @@ pub struct ProjectPanelEntry {
#[derive(Debug, Deserialize, Default)]
pub struct CommandPalette {
- pub key: ContainedLabel,
+ pub key: Interactive<ContainedLabel>,
pub keystroke_spacing: f32,
}
@@ -293,8 +293,7 @@ pub struct Picker {
pub container: ContainerStyle,
pub empty: ContainedLabel,
pub input_editor: FieldEditor,
- pub item: ContainedLabel,
- pub active_item: ContainedLabel,
+ pub item: Interactive<ContainedLabel>,
}
#[derive(Clone, Debug, Deserialize, Default)]
@@ -419,16 +418,23 @@ pub struct Interactive<T> {
}
impl<T> Interactive<T> {
- pub fn active(&self) -> &T {
- self.active.as_ref().unwrap_or(&self.default)
- }
-
- pub fn hover(&self) -> &T {
- self.hover.as_ref().unwrap_or(&self.default)
- }
-
- pub fn active_hover(&self) -> &T {
- self.active_hover.as_ref().unwrap_or(self.active())
+ pub fn style_for(&self, state: &MouseState, active: bool) -> &T {
+ if active {
+ if state.hovered {
+ self.active_hover
+ .as_ref()
+ .or(self.active.as_ref())
+ .unwrap_or(&self.default)
+ } else {
+ self.active.as_ref().unwrap_or(&self.default)
+ }
+ } else {
+ if state.hovered {
+ self.hover.as_ref().unwrap_or(&self.default)
+ } else {
+ &self.default
+ }
+ }
}
}
@@ -203,15 +203,17 @@ impl PickerDelegate for ThemeSelector {
})
}
- fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox {
+ fn render_match(
+ &self,
+ ix: usize,
+ mouse_state: &MouseState,
+ selected: bool,
+ cx: &AppContext,
+ ) -> ElementBox {
let settings = cx.global::<Settings>();
let theme = &settings.theme;
let theme_match = &self.matches[ix];
- let style = if selected {
- &theme.picker.active_item
- } else {
- &theme.picker.item
- };
+ let style = theme.picker.item.style_for(mouse_state, selected);
Label::new(theme_match.string.clone(), style.label.clone())
.with_highlights(theme_match.positions.clone())
@@ -193,13 +193,7 @@ impl View for SidebarButtons {
Flex::row()
.with_children(items.iter().enumerate().map(|(ix, item)| {
MouseEventHandler::new::<Self, _, _>(ix, cx, move |state, _| {
- let style = if Some(ix) == active_ix {
- item_style.active()
- } else if state.hovered {
- item_style.hover()
- } else {
- &item_style.default
- };
+ let style = item_style.style_for(state, Some(ix) == active_ix);
Svg::new(item.icon_path)
.with_color(style.icon_color)
.constrained()
@@ -1574,11 +1574,11 @@ impl Workspace {
} else {
Some(
MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
- let style = if state.hovered {
- &theme.workspace.titlebar.sign_in_prompt.hover()
- } else {
- &theme.workspace.titlebar.sign_in_prompt.default
- };
+ let style = theme
+ .workspace
+ .titlebar
+ .sign_in_prompt
+ .style_for(state, false);
Label::new("Sign in".to_string(), style.text.clone())
.contained()
.with_style(style.container)
@@ -1649,18 +1649,11 @@ impl Workspace {
{
Some(
MouseEventHandler::new::<ToggleShare, _, _>(0, cx, |state, cx| {
- let style = &theme.workspace.titlebar.share_icon;
- let style = if self.project().read(cx).is_shared() {
- if state.hovered {
- style.active_hover()
- } else {
- &style.active()
- }
- } else if state.hovered {
- &style.active()
- } else {
- &style.default
- };
+ let style = &theme
+ .workspace
+ .titlebar
+ .share_icon
+ .style_for(state, self.project().read(cx).is_shared());
Svg::new("icons/share.svg")
.with_color(style.color)
.constrained()
@@ -18,6 +18,9 @@ export default function commandPalette(theme: Theme) {
margin: {
left: 2
},
+ active: {
+ text: text(theme, "mono", "active", { size: "xs" }),
+ }
}
}
}
@@ -2,30 +2,28 @@ import Theme from "../themes/theme";
import { backgroundColor, border, player, shadow, text } from "./components";
export default function picker(theme: Theme) {
- const item = {
- padding: {
- bottom: 4,
- left: 12,
- right: 12,
- top: 4,
- },
- cornerRadius: 8,
- text: text(theme, "sans", "secondary"),
- highlightText: text(theme, "sans", "feature", { weight: "bold" }),
- };
-
- const activeItem = {
- ...item,
- background: backgroundColor(theme, 300, "active"),
- text: text(theme, "sans", "primary"),
- };
-
return {
background: backgroundColor(theme, 300),
cornerRadius: 8,
padding: 8,
- item,
- activeItem,
+ item: {
+ padding: {
+ bottom: 4,
+ left: 12,
+ right: 12,
+ top: 4,
+ },
+ cornerRadius: 8,
+ text: text(theme, "sans", "secondary"),
+ highlightText: text(theme, "sans", "feature", { weight: "bold" }),
+ active: {
+ background: backgroundColor(theme, 300, "active"),
+ text: text(theme, "sans", "primary"),
+ },
+ hover: {
+ background: backgroundColor(theme, 300, "hovered"),
+ }
+ },
border: border(theme, "primary"),
empty: {
text: text(theme, "sans", "placeholder"),