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, Eq, PartialEq)]
56pub enum PinBadgeCorner {
57    TopLeft,
58    TopRight,
59}
60
61#[derive(Clone, Copy, Debug, PartialEq)]
62pub struct PinsConfig {
63    pub corner: PinBadgeCorner,
64    pub color: OverlayColorMode,
65    pub background_color: OverlayColorMode,
66    pub size: f32,
67}
68
69impl Default for PinsConfig {
70    fn default() -> Self {
71        Self {
72            corner: PinBadgeCorner::TopRight,
73            color: OverlayColorMode::Auto,
74            background_color: OverlayColorMode::Auto,
75            size: 1.0,
76        }
77    }
78}
79
80#[derive(Clone, Copy, Debug, PartialEq)]
81pub struct OverlayStyleConfig {
82    pub background_color: OverlayColorMode,
83    pub text_color: OverlayColorMode,
84    pub error_color: OverlayColorMode,
85    pub shape: OverlayShape,
86    pub borders: bool,
87    pub border_source: OverlayBorderSource,
88}
89
90impl Default for OverlayStyleConfig {
91    fn default() -> Self {
92        Self {
93            background_color: OverlayColorMode::Auto,
94            text_color: OverlayColorMode::Auto,
95            error_color: OverlayColorMode::Fixed {
96                r: 0xfb as f32 / 255.0,
97                g: 0x49 as f32 / 255.0,
98                b: 0x34 as f32 / 255.0,
99            },
100            shape: OverlayShape::Square,
101            borders: true,
102            border_source: OverlayBorderSource::Primary,
103        }
104    }
105}
106
107#[derive(Clone, Copy, Debug, PartialEq)]
108pub struct AnimationToggleConfig {
109    pub enabled: bool,
110}
111
112impl Default for AnimationToggleConfig {
113    fn default() -> Self {
114        Self { enabled: true }
115    }
116}
117
118#[derive(Clone, Copy, Debug, PartialEq)]
119pub struct TimedAnimationConfig {
120    pub enabled: bool,
121    pub duration_ms: u64,
122}
123
124impl TimedAnimationConfig {
125    pub const fn new(enabled: bool, duration_ms: u64) -> Self {
126        Self {
127            enabled,
128            duration_ms,
129        }
130    }
131}
132
133#[derive(Clone, Copy, Debug, Eq, PartialEq)]
134pub enum WindowCloseAnimationStyle {
135    Shrink,
136    Fade,
137}
138
139#[derive(Clone, Copy, Debug, PartialEq)]
140pub struct WindowCloseAnimationConfig {
141    pub enabled: bool,
142    pub duration_ms: u64,
143    pub style: WindowCloseAnimationStyle,
144}
145
146#[derive(Clone, Copy, Debug, PartialEq)]
147pub struct RaiseAnimationConfig {
148    pub enabled: bool,
149    pub duration_ms: u64,
150    pub scale: f32,
151    pub shadow_boost: f32,
152}
153
154impl RaiseAnimationConfig {
155    pub const fn new(enabled: bool, duration_ms: u64, scale: f32, shadow_boost: f32) -> Self {
156        Self {
157            enabled,
158            duration_ms,
159            scale,
160            shadow_boost,
161        }
162    }
163}
164
165impl WindowCloseAnimationConfig {
166    pub const fn new(enabled: bool, duration_ms: u64, style: WindowCloseAnimationStyle) -> Self {
167        Self {
168            enabled,
169            duration_ms,
170            style,
171        }
172    }
173}
174
175#[derive(Clone, Copy, Debug, PartialEq)]
176pub struct AnimationsConfig {
177    pub enabled: bool,
178    pub smooth_resize: TimedAnimationConfig,
179    pub maximize: TimedAnimationConfig,
180    pub window_close: WindowCloseAnimationConfig,
181    pub window_open: TimedAnimationConfig,
182    pub tile: TimedAnimationConfig,
183    pub stack: TimedAnimationConfig,
184    pub raise: RaiseAnimationConfig,
185}
186
187impl Default for AnimationsConfig {
188    fn default() -> Self {
189        Self {
190            enabled: true,
191            smooth_resize: TimedAnimationConfig::new(true, 90),
192            maximize: TimedAnimationConfig::new(true, 240),
193            window_close: WindowCloseAnimationConfig::new(
194                true,
195                250,
196                WindowCloseAnimationStyle::Shrink,
197            ),
198            window_open: TimedAnimationConfig::new(true, 620),
199            tile: TimedAnimationConfig::new(true, 240),
200            stack: TimedAnimationConfig::new(true, 220),
201            raise: RaiseAnimationConfig::new(true, 140, 1.025, 0.18),
202        }
203    }
204}
205
206#[derive(Clone, Debug, PartialEq)]
207pub struct ScreenshotConfig {
208    pub directory: String,
209    pub highlight_color: OverlayColorMode,
210    pub background_color: OverlayColorMode,
211}
212
213impl Default for ScreenshotConfig {
214    fn default() -> Self {
215        let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
216        Self {
217            directory: format!("{home}/Pictures/Screenshots"),
218            highlight_color: OverlayColorMode::Auto,
219            background_color: OverlayColorMode::Auto,
220        }
221    }
222}
223
224#[derive(Clone, Copy, Debug, PartialEq)]
225pub struct DecorationBorderColor {
226    pub r: f32,
227    pub g: f32,
228    pub b: f32,
229}
230
231#[derive(Clone, Copy, Debug, PartialEq)]
232pub struct PrimaryBorderConfig {
233    pub size_px: i32,
234    pub radius_px: i32,
235    pub color_focused: DecorationBorderColor,
236    pub color_unfocused: DecorationBorderColor,
237}
238
239#[derive(Clone, Copy, Debug, PartialEq)]
240pub struct SecondaryBorderConfig {
241    pub enabled: bool,
242    pub size_px: i32,
243    pub gap_px: i32,
244    pub color_focused: DecorationBorderColor,
245    pub color_unfocused: DecorationBorderColor,
246}
247
248#[derive(Clone, Copy, Debug, PartialEq)]
249pub struct ShadowColor {
250    pub r: f32,
251    pub g: f32,
252    pub b: f32,
253    pub a: f32,
254}
255
256#[derive(Clone, Copy, Debug, PartialEq)]
257pub struct ShadowLayerConfig {
258    pub enabled: bool,
259    pub blur_radius: f32,
260    pub spread: f32,
261    pub offset_x: f32,
262    pub offset_y: f32,
263    pub color: ShadowColor,
264}
265
266#[derive(Clone, Copy, Debug, PartialEq)]
267pub struct ShadowsConfig {
268    pub window: ShadowLayerConfig,
269    pub node: ShadowLayerConfig,
270    pub overlay: ShadowLayerConfig,
271}
272
273#[derive(Clone, Copy, Debug, PartialEq)]
274pub struct DecorationsConfig {
275    pub border: PrimaryBorderConfig,
276    pub secondary_border: SecondaryBorderConfig,
277    pub shadows: ShadowsConfig,
278    pub resize_using_border: bool,
279}
280
281impl Default for PrimaryBorderConfig {
282    fn default() -> Self {
283        Self {
284            size_px: 3,
285            radius_px: 0,
286            color_focused: DecorationBorderColor {
287                r: 0.22,
288                g: 0.82,
289                b: 0.92,
290            },
291            color_unfocused: DecorationBorderColor {
292                r: 0.28,
293                g: 0.30,
294                b: 0.35,
295            },
296        }
297    }
298}
299
300impl Default for SecondaryBorderConfig {
301    fn default() -> Self {
302        Self {
303            enabled: false,
304            size_px: 1,
305            gap_px: 2,
306            color_focused: DecorationBorderColor {
307                r: 0.98,
308                g: 0.74,
309                b: 0.15,
310            },
311            color_unfocused: DecorationBorderColor {
312                r: 0.12,
313                g: 0.12,
314                b: 0.12,
315            },
316        }
317    }
318}
319
320impl Default for ShadowsConfig {
321    fn default() -> Self {
322        Self {
323            window: ShadowLayerConfig {
324                enabled: true,
325                blur_radius: 8.0,
326                spread: 0.0,
327                offset_x: 0.0,
328                offset_y: 5.0,
329                color: ShadowColor {
330                    r: 0x05 as f32 / 255.0,
331                    g: 0x03 as f32 / 255.0,
332                    b: 0x05 as f32 / 255.0,
333                    a: 0x30 as f32 / 255.0,
334                },
335            },
336            node: ShadowLayerConfig {
337                enabled: true,
338                blur_radius: 14.0,
339                spread: 0.0,
340                offset_x: 0.0,
341                offset_y: 3.0,
342                color: ShadowColor {
343                    r: 0x05 as f32 / 255.0,
344                    g: 0x03 as f32 / 255.0,
345                    b: 0x05 as f32 / 255.0,
346                    a: 0x24 as f32 / 255.0,
347                },
348            },
349            overlay: ShadowLayerConfig {
350                enabled: true,
351                blur_radius: 24.0,
352                spread: 1.0,
353                offset_x: 0.0,
354                offset_y: 7.0,
355                color: ShadowColor {
356                    r: 0x05 as f32 / 255.0,
357                    g: 0x03 as f32 / 255.0,
358                    b: 0x05 as f32 / 255.0,
359                    a: 0x38 as f32 / 255.0,
360                },
361            },
362        }
363    }
364}
365
366impl Default for DecorationsConfig {
367    fn default() -> Self {
368        Self {
369            border: PrimaryBorderConfig::default(),
370            secondary_border: SecondaryBorderConfig::default(),
371            shadows: ShadowsConfig::default(),
372            resize_using_border: false,
373        }
374    }
375}
376
377#[derive(Clone, Copy, Debug, Eq, PartialEq)]
378pub enum PanToNewMode {
379    Never,
380    IfNeeded,
381    Always,
382}
383
384#[derive(Clone, Copy, Debug, Eq, PartialEq)]
385pub enum ExpandedPlacementStrategy {
386    Center,
387    FindEmpty,
388}
389
390#[derive(Clone, Copy, Debug, Eq, PartialEq)]
391pub enum FindEmptyMode {
392    BestEffort,
393}
394
395#[derive(Clone, Copy, Debug, Eq, PartialEq)]
396pub enum LandmarkPlacementStrategy {
397    NearestFree,
398}
399
400#[derive(Clone, Copy, Debug, Eq, PartialEq)]
401pub enum NormalBlockerPolicy {
402    Relocate,
403}
404
405#[derive(Clone, Copy, Debug, Eq, PartialEq)]
406pub enum PinnedBlockerPolicy {
407    Preserve,
408}
409
410#[derive(Clone, Debug, Eq, PartialEq)]
411pub struct ExpandedPlacementConfig {
412    pub strategy: ExpandedPlacementStrategy,
413    pub fallback: ExpandedPlacementStrategy,
414    pub find_empty_mode: FindEmptyMode,
415}
416
417impl Default for ExpandedPlacementConfig {
418    fn default() -> Self {
419        Self {
420            strategy: ExpandedPlacementStrategy::FindEmpty,
421            fallback: ExpandedPlacementStrategy::Center,
422            find_empty_mode: FindEmptyMode::BestEffort,
423        }
424    }
425}
426
427#[derive(Clone, Debug, Eq, PartialEq)]
428pub struct LandmarkPlacementConfig {
429    pub strategy: LandmarkPlacementStrategy,
430    pub normal_blocker: NormalBlockerPolicy,
431    pub pinned_blocker: PinnedBlockerPolicy,
432}
433
434impl Default for LandmarkPlacementConfig {
435    fn default() -> Self {
436        Self {
437            strategy: LandmarkPlacementStrategy::NearestFree,
438            normal_blocker: NormalBlockerPolicy::Relocate,
439            pinned_blocker: PinnedBlockerPolicy::Preserve,
440        }
441    }
442}
443
444#[derive(Clone, Debug, PartialEq)]
445pub struct PlacementRevealConfig {
446    pub enabled: bool,
447    pub max_pan_px: f32,
448    pub animation_ms: u64,
449}
450
451impl Default for PlacementRevealConfig {
452    fn default() -> Self {
453        Self {
454            enabled: true,
455            max_pan_px: 360.0,
456            animation_ms: 180,
457        }
458    }
459}
460
461#[derive(Clone, Debug, PartialEq)]
462pub struct PlacementConfig {
463    pub expanded: ExpandedPlacementConfig,
464    pub landmarks: LandmarkPlacementConfig,
465    pub reveal: PlacementRevealConfig,
466}
467
468impl Default for PlacementConfig {
469    fn default() -> Self {
470        Self {
471            expanded: ExpandedPlacementConfig::default(),
472            landmarks: LandmarkPlacementConfig::default(),
473            reveal: PlacementRevealConfig::default(),
474        }
475    }
476}
477
478#[derive(Clone, Copy, Debug, Eq, PartialEq)]
479pub enum CloseRestorePanMode {
480    Never,
481    IfOffscreen,
482    Always,
483}
484
485#[derive(Clone, Copy, Debug, Eq, PartialEq)]
486pub enum ClickCollapsedOutsideFocusMode {
487    Ignore,
488    Activate,
489}
490
491#[derive(Clone, Copy, Debug, Eq, PartialEq)]
492pub enum ClickCollapsedPanMode {
493    Never,
494    IfOffscreen,
495    Always,
496}
497
498#[derive(Clone, Copy, Debug, Eq, PartialEq)]
499pub enum InputFocusMode {
500    Click,
501    Hover,
502}
503
504#[derive(Clone, Debug, Eq, PartialEq)]
505pub struct KeyboardConfig {
506    pub layout: String,
507    pub variant: String,
508    pub options: String,
509}
510
511impl Default for KeyboardConfig {
512    fn default() -> Self {
513        Self {
514            layout: "us".to_string(),
515            variant: String::new(),
516            options: String::new(),
517        }
518    }
519}
520
521#[derive(Clone, Debug, Eq, PartialEq)]
522pub struct InputConfig {
523    pub repeat_rate: i32,
524    pub repeat_delay: i32,
525    pub focus_mode: InputFocusMode,
526    pub raise_on_click: bool,
527    pub keyboard: KeyboardConfig,
528}
529
530impl Default for InputConfig {
531    fn default() -> Self {
532        Self {
533            repeat_rate: 30,
534            repeat_delay: 500,
535            focus_mode: InputFocusMode::Click,
536            raise_on_click: true,
537            keyboard: KeyboardConfig::default(),
538        }
539    }
540}
541
542#[derive(Clone, Copy, Debug, PartialEq)]
543pub struct FocusRingConfig {
544    pub rx: f32,
545    pub ry: f32,
546    pub offset_x: f32,
547    pub offset_y: f32,
548}
549
550impl FocusRingConfig {
551    pub fn to_focus_ring(self) -> FocusRing {
552        FocusRing::new(self.rx, self.ry, self.offset_x, self.offset_y)
553    }
554}
555
556#[derive(Clone, Copy, Debug, PartialEq)]
557pub struct BearingsConfig {
558    pub show_distance: bool,
559    pub show_icons: bool,
560    pub show_pinned: bool,
561    pub fade_distance: f32,
562}
563
564#[derive(Clone, Debug, Eq, PartialEq)]
565pub struct CursorConfig {
566    pub theme: String,
567    pub size: u32,
568    pub hide_while_typing: bool,
569    pub hide_after_ms: u64,
570}
571
572impl Default for CursorConfig {
573    fn default() -> Self {
574        Self {
575            theme: "Adwaita".to_string(),
576            size: 24,
577            hide_while_typing: false,
578            hide_after_ms: 0,
579        }
580    }
581}
582
583#[derive(Clone, Debug, Eq, PartialEq)]
584pub struct FontConfig {
585    pub family: String,
586    pub size: u32,
587}
588
589impl Default for FontConfig {
590    fn default() -> Self {
591        Self {
592            family: "monospace".to_string(),
593            size: 11,
594        }
595    }
596}
597
598#[derive(Clone, Copy, Debug, Eq, PartialEq)]
599pub enum ClusterBloomDirection {
600    Clockwise,
601    CounterClockwise,
602}
603
604#[derive(Clone, Copy, Debug, Eq, PartialEq)]
605pub enum ClusterDefaultLayout {
606    Tiling,
607    Stacking,
608}
609
610impl ClusterDefaultLayout {
611    pub fn to_workspace_layout_kind(self) -> ClusterWorkspaceLayoutKind {
612        match self {
613            Self::Tiling => ClusterWorkspaceLayoutKind::Tiling,
614            Self::Stacking => ClusterWorkspaceLayoutKind::Stacking,
615        }
616    }
617}
618
619#[derive(Clone, Debug)]
620pub enum WindowRulePattern {
621    Exact(String),
622    Regex(Regex),
623}
624
625impl PartialEq for WindowRulePattern {
626    fn eq(&self, other: &Self) -> bool {
627        match (self, other) {
628            (Self::Exact(a), Self::Exact(b)) => a == b,
629            (Self::Regex(a), Self::Regex(b)) => a.as_str() == b.as_str(),
630            _ => false,
631        }
632    }
633}
634
635impl Eq for WindowRulePattern {}
636
637impl WindowRulePattern {
638    pub fn matches(&self, value: &str) -> bool {
639        match self {
640            Self::Exact(exact) => exact == value,
641            Self::Regex(regex) => regex.is_match(value),
642        }
643    }
644
645    pub fn as_str(&self) -> &str {
646        match self {
647            Self::Exact(exact) => exact.as_str(),
648            Self::Regex(regex) => regex.as_str(),
649        }
650    }
651}
652
653#[derive(Clone, Copy, Debug, Eq, PartialEq)]
654pub enum InitialWindowOverlapPolicy {
655    None,
656    ParentOnly,
657    All,
658}
659
660#[derive(Clone, Copy, Debug, Eq, PartialEq)]
661pub enum InitialWindowSpawnPlacement {
662    Default,
663    Center,
664    Adjacent,
665    ViewportCenter,
666    Cursor,
667    App,
668}
669
670#[derive(Clone, Copy, Debug, Eq, PartialEq)]
671pub enum InitialWindowClusterParticipation {
672    Layout,
673    Float,
674}
675
676#[derive(Clone, Debug, Eq, PartialEq)]
677pub struct WindowRule {
678    pub app_ids: Vec<WindowRulePattern>,
679    pub titles: Vec<WindowRulePattern>,
680    pub overlap_policy: InitialWindowOverlapPolicy,
681    pub spawn_placement: InitialWindowSpawnPlacement,
682    pub cluster_participation: InitialWindowClusterParticipation,
683}
684
685#[derive(Clone, Debug, PartialEq)]
686pub struct ViewportOutputConfig {
687    pub connector: String,
688    pub enabled: bool,
689    pub offset_x: i32,
690    pub offset_y: i32,
691    pub width: u32,
692    pub height: u32,
693    pub refresh_rate: Option<f64>,
694    pub transform_degrees: u16,
695    pub vrr: ViewportVrrMode,
696    pub focus_ring: Option<FocusRingConfig>,
697}
698
699#[derive(Clone, Copy, Debug, PartialEq, Eq)]
700pub enum ViewportVrrMode {
701    Off,
702    On,
703    OnDemand,
704}
705
706impl ViewportVrrMode {
707    pub fn as_str(self) -> &'static str {
708        match self {
709            Self::Off => "off",
710            Self::On => "on",
711            Self::OnDemand => "on-demand",
712        }
713    }
714
715    pub fn drm_enabled(self) -> bool {
716        matches!(self, Self::On)
717    }
718}