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}