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