1pub use gpui3::{
2 div, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString,
3 StatefullyInteractivee, Styled, ViewContext, WindowContext,
4};
5
6use crate::settings::user_settings;
7pub use crate::{theme, ButtonVariant, ElementExt, Theme};
8
9use gpui3::{hsla, rems, rgb, Hsla, Rems};
10use strum::EnumIter;
11
12#[derive(Default)]
13pub struct SystemColor {
14 pub transparent: Hsla,
15 pub mac_os_traffic_light_red: Hsla,
16 pub mac_os_traffic_light_yellow: Hsla,
17 pub mac_os_traffic_light_green: Hsla,
18 pub state_hover_background: Hsla,
19 pub state_active_background: Hsla,
20}
21
22impl SystemColor {
23 pub fn new() -> SystemColor {
24 SystemColor {
25 transparent: hsla(0.0, 0.0, 0.0, 0.0),
26 mac_os_traffic_light_red: rgb::<Hsla>(0xEC695E),
27 mac_os_traffic_light_yellow: rgb::<Hsla>(0xF4BF4F),
28 mac_os_traffic_light_green: rgb::<Hsla>(0x62C554),
29 state_hover_background: hsla(0.0, 0.0, 0.0, 0.08),
30 state_active_background: hsla(0.0, 0.0, 0.0, 0.16),
31 }
32 }
33 pub fn color(&self) -> Hsla {
34 self.transparent
35 }
36}
37
38#[derive(Clone, Copy)]
39pub struct ThemeColor {
40 pub border: Hsla,
41 pub border_variant: Hsla,
42 pub border_focused: Hsla,
43 pub border_transparent: Hsla,
44 /// The background color of an elevated surface, like a modal, tooltip or toast.
45 pub elevated_surface: Hsla,
46 pub surface: Hsla,
47 /// Window background color
48 pub background: Hsla,
49 /// Default background for elements like filled buttons,
50 /// text fields, checkboxes, radio buttons, etc.
51 /// - TODO: Map to step 3.
52 pub filled_element: Hsla,
53 /// The background color of a hovered element, like a button being hovered
54 /// with a mouse, or hovered on a touch screen.
55 /// - TODO: Map to step 4.
56 pub filled_element_hover: Hsla,
57 /// The background color of an active element, like a button being pressed,
58 /// or tapped on a touch screen.
59 /// - TODO: Map to step 5.
60 pub filled_element_active: Hsla,
61 /// The background color of a selected element, like a selected tab,
62 /// a button toggled on, or a checkbox that is checked.
63 pub filled_element_selected: Hsla,
64 pub filled_element_disabled: Hsla,
65 pub ghost_element: Hsla,
66 /// - TODO: Map to step 3.
67 pub ghost_element_hover: Hsla,
68 /// - TODO: Map to step 4.
69 pub ghost_element_active: Hsla,
70 pub ghost_element_selected: Hsla,
71 pub ghost_element_disabled: Hsla,
72}
73
74impl ThemeColor {
75 pub fn new(cx: &WindowContext) -> Self {
76 let theme = theme(cx);
77 let system_color = SystemColor::new();
78
79 Self {
80 border: theme.lowest.base.default.border,
81 border_variant: theme.lowest.variant.default.border,
82 border_focused: theme.lowest.accent.default.border,
83 border_transparent: system_color.transparent,
84 elevated_surface: theme.middle.base.default.background,
85 surface: theme.middle.base.default.background,
86 background: theme.lowest.base.default.background,
87 filled_element: theme.lowest.base.default.background,
88 filled_element_hover: theme.lowest.base.hovered.background,
89 filled_element_active: theme.lowest.base.active.background,
90 filled_element_selected: theme.lowest.accent.default.background,
91 filled_element_disabled: system_color.transparent,
92 ghost_element: system_color.transparent,
93 ghost_element_hover: theme.lowest.base.default.background,
94 ghost_element_active: theme.lowest.base.hovered.background,
95 ghost_element_selected: theme.lowest.accent.default.background,
96 ghost_element_disabled: system_color.transparent,
97 }
98 }
99}
100
101#[derive(Default, PartialEq, EnumIter, Clone, Copy)]
102pub enum HighlightColor {
103 #[default]
104 Default,
105 Comment,
106 String,
107 Function,
108 Keyword,
109}
110
111impl HighlightColor {
112 pub fn hsla(&self, theme: &Theme) -> Hsla {
113 let system_color = SystemColor::new();
114
115 match self {
116 Self::Default => theme
117 .syntax
118 .get("primary")
119 .cloned()
120 .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
121 Self::Comment => theme
122 .syntax
123 .get("comment")
124 .cloned()
125 .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
126 Self::String => theme
127 .syntax
128 .get("string")
129 .cloned()
130 .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
131 Self::Function => theme
132 .syntax
133 .get("function")
134 .cloned()
135 .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
136 Self::Keyword => theme
137 .syntax
138 .get("keyword")
139 .cloned()
140 .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
141 }
142 }
143}
144
145pub fn ui_size(cx: &mut WindowContext, size: f32) -> Rems {
146 const UI_SCALE_RATIO: f32 = 0.875;
147
148 let settings = user_settings(cx);
149
150 rems(*settings.ui_scale * UI_SCALE_RATIO * size)
151}
152
153#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
154pub enum FileSystemStatus {
155 #[default]
156 None,
157 Conflict,
158 Deleted,
159}
160
161impl FileSystemStatus {
162 pub fn to_string(&self) -> String {
163 match self {
164 Self::None => "None".to_string(),
165 Self::Conflict => "Conflict".to_string(),
166 Self::Deleted => "Deleted".to_string(),
167 }
168 }
169}
170
171#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
172pub enum GitStatus {
173 #[default]
174 None,
175 Created,
176 Modified,
177 Deleted,
178 Conflict,
179 Renamed,
180}
181
182impl GitStatus {
183 pub fn to_string(&self) -> String {
184 match self {
185 Self::None => "None".to_string(),
186 Self::Created => "Created".to_string(),
187 Self::Modified => "Modified".to_string(),
188 Self::Deleted => "Deleted".to_string(),
189 Self::Conflict => "Conflict".to_string(),
190 Self::Renamed => "Renamed".to_string(),
191 }
192 }
193
194 pub fn hsla(&self, cx: &WindowContext) -> Hsla {
195 let theme = theme(cx);
196 let system_color = SystemColor::new();
197
198 match self {
199 Self::None => system_color.transparent,
200 Self::Created => theme.lowest.positive.default.foreground,
201 Self::Modified => theme.lowest.warning.default.foreground,
202 Self::Deleted => theme.lowest.negative.default.foreground,
203 Self::Conflict => theme.lowest.warning.default.foreground,
204 Self::Renamed => theme.lowest.accent.default.foreground,
205 }
206 }
207}
208
209#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
210pub enum DiagnosticStatus {
211 #[default]
212 None,
213 Error,
214 Warning,
215 Info,
216}
217
218#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
219pub enum IconSide {
220 #[default]
221 Left,
222 Right,
223}
224
225#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
226pub enum OrderMethod {
227 #[default]
228 Ascending,
229 Descending,
230 MostRecent,
231}
232
233#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
234pub enum Shape {
235 #[default]
236 Circle,
237 RoundedRectangle,
238}
239
240#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
241pub enum DisclosureControlVisibility {
242 #[default]
243 OnHover,
244 Always,
245}
246
247#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
248pub enum DisclosureControlStyle {
249 /// Shows the disclosure control only when hovered where possible.
250 ///
251 /// More compact, but not available everywhere.
252 ChevronOnHover,
253 /// Shows an icon where possible, otherwise shows a chevron.
254 ///
255 /// For example, in a file tree a folder or file icon is shown
256 /// instead of a chevron
257 Icon,
258 /// Always shows a chevron.
259 Chevron,
260 /// Completely hides the disclosure control where possible.
261 None,
262}
263
264#[derive(Default, PartialEq, Copy, Clone, EnumIter, strum::Display)]
265pub enum InteractionState {
266 #[default]
267 Enabled,
268 Hovered,
269 Active,
270 Focused,
271 Disabled,
272}
273
274impl InteractionState {
275 pub fn if_enabled(&self, enabled: bool) -> Self {
276 if enabled {
277 *self
278 } else {
279 InteractionState::Disabled
280 }
281 }
282}
283
284#[derive(Default, PartialEq)]
285pub enum SelectedState {
286 #[default]
287 Unselected,
288 PartiallySelected,
289 Selected,
290}
291
292#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
293pub enum Toggleable {
294 Toggleable(ToggleState),
295 #[default]
296 NotToggleable,
297}
298
299impl Toggleable {
300 pub fn is_toggled(&self) -> bool {
301 match self {
302 Self::Toggleable(ToggleState::Toggled) => true,
303 _ => false,
304 }
305 }
306}
307
308impl From<ToggleState> for Toggleable {
309 fn from(state: ToggleState) -> Self {
310 Self::Toggleable(state)
311 }
312}
313
314#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
315pub enum ToggleState {
316 /// The "on" state of a toggleable element.
317 ///
318 /// Example:
319 /// - A collasable list that is currently expanded
320 /// - A toggle button that is currently on.
321 Toggled,
322 /// The "off" state of a toggleable element.
323 ///
324 /// Example:
325 /// - A collasable list that is currently collapsed
326 /// - A toggle button that is currently off.
327 #[default]
328 NotToggled,
329}
330
331impl From<Toggleable> for ToggleState {
332 fn from(toggleable: Toggleable) -> Self {
333 match toggleable {
334 Toggleable::Toggleable(state) => state,
335 Toggleable::NotToggleable => ToggleState::NotToggled,
336 }
337 }
338}
339
340impl From<bool> for ToggleState {
341 fn from(toggled: bool) -> Self {
342 if toggled {
343 ToggleState::Toggled
344 } else {
345 ToggleState::NotToggled
346 }
347 }
348}