Skip to main content

halley_config/layout/
types.rs

1use halley_core::cluster_layout::ClusterWorkspaceLayoutKind;
2use halley_core::viewport::FocusRing;
3use regex::Regex;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum NodeBorderColorMode {
7    UseWindowActive,
8    UseWindowInactive,
9    UseWindowSecondaryActive,
10    UseWindowSecondaryInactive,
11}
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum NodeDisplayPolicy {
15    Off,
16    Hover,
17    Always,
18}
19
20#[derive(Clone, Copy, Debug, PartialEq)]
21pub enum NodeBackgroundColorMode {
22    Auto,
23    Theme,
24    Light,
25    Dark,
26    Fixed { r: f32, g: f32, b: f32 },
27}
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30pub enum ShapeStyle {
31    Square,
32    Squircle,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq)]
36pub enum OverlayColorMode {
37    Auto,
38    Light,
39    Dark,
40    Fixed { r: f32, g: f32, b: f32 },
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub enum OverlayShape {
45    Square,
46    Rounded,
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub enum OverlayBorderSource {
51    Primary,
52    Secondary,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq)]
56pub struct OverlayStyleConfig {
57    pub background_color: OverlayColorMode,
58    pub text_color: OverlayColorMode,
59    pub shape: OverlayShape,
60    pub borders: bool,
61    pub border_source: OverlayBorderSource,
62}
63
64impl Default for OverlayStyleConfig {
65    fn default() -> Self {
66        Self {
67            background_color: OverlayColorMode::Auto,
68            text_color: OverlayColorMode::Auto,
69            shape: OverlayShape::Square,
70            borders: true,
71            border_source: OverlayBorderSource::Primary,
72        }
73    }
74}
75
76#[derive(Clone, Copy, Debug, PartialEq)]
77pub struct AnimationToggleConfig {
78    pub enabled: bool,
79}
80
81impl Default for AnimationToggleConfig {
82    fn default() -> Self {
83        Self { enabled: true }
84    }
85}
86
87#[derive(Clone, Copy, Debug, PartialEq)]
88pub struct TimedAnimationConfig {
89    pub enabled: bool,
90    pub duration_ms: u64,
91}
92
93impl TimedAnimationConfig {
94    pub const fn new(enabled: bool, duration_ms: u64) -> Self {
95        Self {
96            enabled,
97            duration_ms,
98        }
99    }
100}
101
102#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub enum WindowCloseAnimationStyle {
104    Shrink,
105}
106
107#[derive(Clone, Copy, Debug, PartialEq)]
108pub struct WindowCloseAnimationConfig {
109    pub enabled: bool,
110    pub duration_ms: u64,
111    pub style: WindowCloseAnimationStyle,
112}
113
114impl WindowCloseAnimationConfig {
115    pub const fn new(enabled: bool, duration_ms: u64, style: WindowCloseAnimationStyle) -> Self {
116        Self {
117            enabled,
118            duration_ms,
119            style,
120        }
121    }
122}
123
124#[derive(Clone, Copy, Debug, PartialEq)]
125pub struct AnimationsConfig {
126    pub enabled: bool,
127    pub smooth_resize: TimedAnimationConfig,
128    pub maximize: TimedAnimationConfig,
129    pub window_close: WindowCloseAnimationConfig,
130    pub window_open: TimedAnimationConfig,
131    pub tile: TimedAnimationConfig,
132    pub stack: TimedAnimationConfig,
133}
134
135impl Default for AnimationsConfig {
136    fn default() -> Self {
137        Self {
138            enabled: true,
139            smooth_resize: TimedAnimationConfig::new(true, 90),
140            maximize: TimedAnimationConfig::new(true, 240),
141            window_close: WindowCloseAnimationConfig::new(
142                true,
143                250,
144                WindowCloseAnimationStyle::Shrink,
145            ),
146            window_open: TimedAnimationConfig::new(true, 620),
147            tile: TimedAnimationConfig::new(true, 240),
148            stack: TimedAnimationConfig::new(true, 220),
149        }
150    }
151}
152
153#[derive(Clone, Debug, PartialEq)]
154pub struct ScreenshotConfig {
155    pub directory: String,
156    pub highlight_color: OverlayColorMode,
157    pub background_color: OverlayColorMode,
158}
159
160impl Default for ScreenshotConfig {
161    fn default() -> Self {
162        let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
163        Self {
164            directory: format!("{home}/Pictures/Screenshots"),
165            highlight_color: OverlayColorMode::Auto,
166            background_color: OverlayColorMode::Auto,
167        }
168    }
169}
170
171#[derive(Clone, Copy, Debug, PartialEq)]
172pub struct DecorationBorderColor {
173    pub r: f32,
174    pub g: f32,
175    pub b: f32,
176}
177
178#[derive(Clone, Copy, Debug, PartialEq)]
179pub struct PrimaryBorderConfig {
180    pub size_px: i32,
181    pub radius_px: i32,
182    pub color_focused: DecorationBorderColor,
183    pub color_unfocused: DecorationBorderColor,
184}
185
186#[derive(Clone, Copy, Debug, PartialEq)]
187pub struct SecondaryBorderConfig {
188    pub enabled: bool,
189    pub size_px: i32,
190    pub gap_px: i32,
191    pub color_focused: DecorationBorderColor,
192    pub color_unfocused: DecorationBorderColor,
193}
194
195#[derive(Clone, Copy, Debug, PartialEq)]
196pub struct ShadowColor {
197    pub r: f32,
198    pub g: f32,
199    pub b: f32,
200    pub a: f32,
201}
202
203#[derive(Clone, Copy, Debug, PartialEq)]
204pub struct ShadowLayerConfig {
205    pub enabled: bool,
206    pub blur_radius: f32,
207    pub spread: f32,
208    pub offset_x: f32,
209    pub offset_y: f32,
210    pub color: ShadowColor,
211}
212
213#[derive(Clone, Copy, Debug, PartialEq)]
214pub struct ShadowsConfig {
215    pub window: ShadowLayerConfig,
216    pub node: ShadowLayerConfig,
217    pub overlay: ShadowLayerConfig,
218}
219
220#[derive(Clone, Copy, Debug, PartialEq)]
221pub struct DecorationsConfig {
222    pub border: PrimaryBorderConfig,
223    pub secondary_border: SecondaryBorderConfig,
224    pub shadows: ShadowsConfig,
225    pub resize_using_border: bool,
226}
227
228impl Default for PrimaryBorderConfig {
229    fn default() -> Self {
230        Self {
231            size_px: 3,
232            radius_px: 0,
233            color_focused: DecorationBorderColor {
234                r: 0.22,
235                g: 0.82,
236                b: 0.92,
237            },
238            color_unfocused: DecorationBorderColor {
239                r: 0.28,
240                g: 0.30,
241                b: 0.35,
242            },
243        }
244    }
245}
246
247impl Default for SecondaryBorderConfig {
248    fn default() -> Self {
249        Self {
250            enabled: false,
251            size_px: 1,
252            gap_px: 2,
253            color_focused: DecorationBorderColor {
254                r: 0.98,
255                g: 0.74,
256                b: 0.15,
257            },
258            color_unfocused: DecorationBorderColor {
259                r: 0.12,
260                g: 0.12,
261                b: 0.12,
262            },
263        }
264    }
265}
266
267impl Default for ShadowsConfig {
268    fn default() -> Self {
269        Self {
270            window: ShadowLayerConfig {
271                enabled: true,
272                blur_radius: 8.0,
273                spread: 0.0,
274                offset_x: 0.0,
275                offset_y: 5.0,
276                color: ShadowColor {
277                    r: 0x05 as f32 / 255.0,
278                    g: 0x03 as f32 / 255.0,
279                    b: 0x05 as f32 / 255.0,
280                    a: 0x30 as f32 / 255.0,
281                },
282            },
283            node: ShadowLayerConfig {
284                enabled: true,
285                blur_radius: 14.0,
286                spread: 0.0,
287                offset_x: 0.0,
288                offset_y: 3.0,
289                color: ShadowColor {
290                    r: 0x05 as f32 / 255.0,
291                    g: 0x03 as f32 / 255.0,
292                    b: 0x05 as f32 / 255.0,
293                    a: 0x24 as f32 / 255.0,
294                },
295            },
296            overlay: ShadowLayerConfig {
297                enabled: true,
298                blur_radius: 24.0,
299                spread: 1.0,
300                offset_x: 0.0,
301                offset_y: 7.0,
302                color: ShadowColor {
303                    r: 0x05 as f32 / 255.0,
304                    g: 0x03 as f32 / 255.0,
305                    b: 0x05 as f32 / 255.0,
306                    a: 0x38 as f32 / 255.0,
307                },
308            },
309        }
310    }
311}
312
313impl Default for DecorationsConfig {
314    fn default() -> Self {
315        Self {
316            border: PrimaryBorderConfig::default(),
317            secondary_border: SecondaryBorderConfig::default(),
318            shadows: ShadowsConfig::default(),
319            resize_using_border: false,
320        }
321    }
322}
323
324#[derive(Clone, Copy, Debug, Eq, PartialEq)]
325pub enum PanToNewMode {
326    Never,
327    IfNeeded,
328    Always,
329}
330
331#[derive(Clone, Copy, Debug, Eq, PartialEq)]
332pub enum CloseRestorePanMode {
333    Never,
334    IfOffscreen,
335    Always,
336}
337
338#[derive(Clone, Copy, Debug, Eq, PartialEq)]
339pub enum ClickCollapsedOutsideFocusMode {
340    Ignore,
341    Activate,
342}
343
344#[derive(Clone, Copy, Debug, Eq, PartialEq)]
345pub enum ClickCollapsedPanMode {
346    Never,
347    IfOffscreen,
348    Always,
349}
350
351#[derive(Clone, Copy, Debug, Eq, PartialEq)]
352pub enum InputFocusMode {
353    Click,
354    Hover,
355}
356
357#[derive(Clone, Debug, Eq, PartialEq)]
358pub struct KeyboardConfig {
359    pub layout: String,
360    pub variant: String,
361    pub options: String,
362}
363
364impl Default for KeyboardConfig {
365    fn default() -> Self {
366        Self {
367            layout: "us".to_string(),
368            variant: String::new(),
369            options: String::new(),
370        }
371    }
372}
373
374#[derive(Clone, Debug, Eq, PartialEq)]
375pub struct InputConfig {
376    pub repeat_rate: i32,
377    pub repeat_delay: i32,
378    pub focus_mode: InputFocusMode,
379    pub keyboard: KeyboardConfig,
380}
381
382impl Default for InputConfig {
383    fn default() -> Self {
384        Self {
385            repeat_rate: 30,
386            repeat_delay: 500,
387            focus_mode: InputFocusMode::Click,
388            keyboard: KeyboardConfig::default(),
389        }
390    }
391}
392
393#[derive(Clone, Copy, Debug, PartialEq)]
394pub struct FocusRingConfig {
395    pub rx: f32,
396    pub ry: f32,
397    pub offset_x: f32,
398    pub offset_y: f32,
399}
400
401impl FocusRingConfig {
402    pub fn to_focus_ring(self) -> FocusRing {
403        FocusRing::new(self.rx, self.ry, self.offset_x, self.offset_y)
404    }
405}
406
407#[derive(Clone, Copy, Debug, PartialEq)]
408pub struct BearingsConfig {
409    pub show_distance: bool,
410    pub show_icons: bool,
411    pub fade_distance: f32,
412}
413
414#[derive(Clone, Debug, Eq, PartialEq)]
415pub struct CursorConfig {
416    pub theme: String,
417    pub size: u32,
418    pub hide_while_typing: bool,
419    pub hide_after_ms: u64,
420}
421
422impl Default for CursorConfig {
423    fn default() -> Self {
424        Self {
425            theme: "Adwaita".to_string(),
426            size: 24,
427            hide_while_typing: false,
428            hide_after_ms: 0,
429        }
430    }
431}
432
433#[derive(Clone, Debug, Eq, PartialEq)]
434pub struct FontConfig {
435    pub family: String,
436    pub size: u32,
437}
438
439impl Default for FontConfig {
440    fn default() -> Self {
441        Self {
442            family: "monospace".to_string(),
443            size: 11,
444        }
445    }
446}
447
448#[derive(Clone, Copy, Debug, Eq, PartialEq)]
449pub enum ClusterBloomDirection {
450    Clockwise,
451    CounterClockwise,
452}
453
454#[derive(Clone, Copy, Debug, Eq, PartialEq)]
455pub enum ClusterDefaultLayout {
456    Tiling,
457    Stacking,
458}
459
460impl ClusterDefaultLayout {
461    pub fn to_workspace_layout_kind(self) -> ClusterWorkspaceLayoutKind {
462        match self {
463            Self::Tiling => ClusterWorkspaceLayoutKind::Tiling,
464            Self::Stacking => ClusterWorkspaceLayoutKind::Stacking,
465        }
466    }
467}
468
469#[derive(Clone, Debug)]
470pub enum WindowRulePattern {
471    Exact(String),
472    Regex(Regex),
473}
474
475impl PartialEq for WindowRulePattern {
476    fn eq(&self, other: &Self) -> bool {
477        match (self, other) {
478            (Self::Exact(a), Self::Exact(b)) => a == b,
479            (Self::Regex(a), Self::Regex(b)) => a.as_str() == b.as_str(),
480            _ => false,
481        }
482    }
483}
484
485impl Eq for WindowRulePattern {}
486
487impl WindowRulePattern {
488    pub fn matches(&self, value: &str) -> bool {
489        match self {
490            Self::Exact(exact) => exact == value,
491            Self::Regex(regex) => regex.is_match(value),
492        }
493    }
494
495    pub fn as_str(&self) -> &str {
496        match self {
497            Self::Exact(exact) => exact.as_str(),
498            Self::Regex(regex) => regex.as_str(),
499        }
500    }
501}
502
503#[derive(Clone, Copy, Debug, Eq, PartialEq)]
504pub enum InitialWindowOverlapPolicy {
505    None,
506    ParentOnly,
507    All,
508}
509
510#[derive(Clone, Copy, Debug, Eq, PartialEq)]
511pub enum InitialWindowSpawnPlacement {
512    Center,
513    Adjacent,
514    ViewportCenter,
515    Cursor,
516    App,
517}
518
519#[derive(Clone, Copy, Debug, Eq, PartialEq)]
520pub enum InitialWindowClusterParticipation {
521    Layout,
522    Float,
523}
524
525#[derive(Clone, Debug, Eq, PartialEq)]
526pub struct WindowRule {
527    pub app_ids: Vec<WindowRulePattern>,
528    pub titles: Vec<WindowRulePattern>,
529    pub overlap_policy: InitialWindowOverlapPolicy,
530    pub spawn_placement: InitialWindowSpawnPlacement,
531    pub cluster_participation: InitialWindowClusterParticipation,
532}
533
534#[derive(Clone, Debug, PartialEq)]
535pub struct ViewportOutputConfig {
536    pub connector: String,
537    pub enabled: bool,
538    pub offset_x: i32,
539    pub offset_y: i32,
540    pub width: u32,
541    pub height: u32,
542    pub refresh_rate: Option<f64>,
543    pub transform_degrees: u16,
544    pub vrr: ViewportVrrMode,
545    pub focus_ring: Option<FocusRingConfig>,
546}
547
548#[derive(Clone, Copy, Debug, PartialEq, Eq)]
549pub enum ViewportVrrMode {
550    Off,
551    On,
552    OnDemand,
553}
554
555impl ViewportVrrMode {
556    pub fn as_str(self) -> &'static str {
557        match self {
558            Self::Off => "off",
559            Self::On => "on",
560            Self::OnDemand => "on-demand",
561        }
562    }
563
564    pub fn drm_enabled(self) -> bool {
565        !matches!(self, Self::Off)
566    }
567}