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}