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 window_close: WindowCloseAnimationConfig,
129 pub window_open: TimedAnimationConfig,
130 pub tile: TimedAnimationConfig,
131 pub stack: TimedAnimationConfig,
132}
133
134impl Default for AnimationsConfig {
135 fn default() -> Self {
136 Self {
137 enabled: true,
138 smooth_resize: TimedAnimationConfig::new(true, 90),
139 window_close: WindowCloseAnimationConfig::new(
140 true,
141 250,
142 WindowCloseAnimationStyle::Shrink,
143 ),
144 window_open: TimedAnimationConfig::new(true, 620),
145 tile: TimedAnimationConfig::new(true, 240),
146 stack: TimedAnimationConfig::new(true, 220),
147 }
148 }
149}
150
151#[derive(Clone, Debug, PartialEq)]
152pub struct ScreenshotConfig {
153 pub directory: String,
154 pub highlight_color: OverlayColorMode,
155 pub background_color: OverlayColorMode,
156}
157
158impl Default for ScreenshotConfig {
159 fn default() -> Self {
160 let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
161 Self {
162 directory: format!("{home}/Pictures/Screenshots"),
163 highlight_color: OverlayColorMode::Auto,
164 background_color: OverlayColorMode::Auto,
165 }
166 }
167}
168
169#[derive(Clone, Copy, Debug, PartialEq)]
170pub struct DecorationBorderColor {
171 pub r: f32,
172 pub g: f32,
173 pub b: f32,
174}
175
176#[derive(Clone, Copy, Debug, PartialEq)]
177pub struct PrimaryBorderConfig {
178 pub size_px: i32,
179 pub radius_px: i32,
180 pub color_focused: DecorationBorderColor,
181 pub color_unfocused: DecorationBorderColor,
182}
183
184#[derive(Clone, Copy, Debug, PartialEq)]
185pub struct SecondaryBorderConfig {
186 pub enabled: bool,
187 pub size_px: i32,
188 pub gap_px: i32,
189 pub color_focused: DecorationBorderColor,
190 pub color_unfocused: DecorationBorderColor,
191}
192
193#[derive(Clone, Copy, Debug, PartialEq)]
194pub struct DecorationsConfig {
195 pub border: PrimaryBorderConfig,
196 pub secondary_border: SecondaryBorderConfig,
197 pub resize_using_border: bool,
198}
199
200impl Default for PrimaryBorderConfig {
201 fn default() -> Self {
202 Self {
203 size_px: 3,
204 radius_px: 0,
205 color_focused: DecorationBorderColor {
206 r: 0.22,
207 g: 0.82,
208 b: 0.92,
209 },
210 color_unfocused: DecorationBorderColor {
211 r: 0.28,
212 g: 0.30,
213 b: 0.35,
214 },
215 }
216 }
217}
218
219impl Default for SecondaryBorderConfig {
220 fn default() -> Self {
221 Self {
222 enabled: false,
223 size_px: 1,
224 gap_px: 2,
225 color_focused: DecorationBorderColor {
226 r: 0.98,
227 g: 0.74,
228 b: 0.15,
229 },
230 color_unfocused: DecorationBorderColor {
231 r: 0.12,
232 g: 0.12,
233 b: 0.12,
234 },
235 }
236 }
237}
238
239impl Default for DecorationsConfig {
240 fn default() -> Self {
241 Self {
242 border: PrimaryBorderConfig::default(),
243 secondary_border: SecondaryBorderConfig::default(),
244 resize_using_border: false,
245 }
246 }
247}
248
249#[derive(Clone, Copy, Debug, Eq, PartialEq)]
250pub enum PanToNewMode {
251 Never,
252 IfNeeded,
253 Always,
254}
255
256#[derive(Clone, Copy, Debug, Eq, PartialEq)]
257pub enum CloseRestorePanMode {
258 Never,
259 IfOffscreen,
260 Always,
261}
262
263#[derive(Clone, Copy, Debug, Eq, PartialEq)]
264pub enum ClickCollapsedOutsideFocusMode {
265 Ignore,
266 Activate,
267}
268
269#[derive(Clone, Copy, Debug, Eq, PartialEq)]
270pub enum ClickCollapsedPanMode {
271 Never,
272 IfOffscreen,
273 Always,
274}
275
276#[derive(Clone, Copy, Debug, Eq, PartialEq)]
277pub enum InputFocusMode {
278 Click,
279 Hover,
280}
281
282#[derive(Clone, Copy, Debug, Eq, PartialEq)]
283pub struct InputConfig {
284 pub repeat_rate: i32,
285 pub repeat_delay: i32,
286 pub focus_mode: InputFocusMode,
287}
288
289impl Default for InputConfig {
290 fn default() -> Self {
291 Self {
292 repeat_rate: 30,
293 repeat_delay: 500,
294 focus_mode: InputFocusMode::Click,
295 }
296 }
297}
298
299#[derive(Clone, Copy, Debug, PartialEq)]
300pub struct FocusRingConfig {
301 pub rx: f32,
302 pub ry: f32,
303 pub offset_x: f32,
304 pub offset_y: f32,
305}
306
307impl FocusRingConfig {
308 pub fn to_focus_ring(self) -> FocusRing {
309 FocusRing::new(self.rx, self.ry, self.offset_x, self.offset_y)
310 }
311}
312
313#[derive(Clone, Copy, Debug, PartialEq)]
314pub struct BearingsConfig {
315 pub show_distance: bool,
316 pub show_icons: bool,
317 pub fade_distance: f32,
318}
319
320#[derive(Clone, Debug, Eq, PartialEq)]
321pub struct CursorConfig {
322 pub theme: String,
323 pub size: u32,
324 pub hide_while_typing: bool,
325 pub hide_after_ms: u64,
326}
327
328impl Default for CursorConfig {
329 fn default() -> Self {
330 Self {
331 theme: "Adwaita".to_string(),
332 size: 24,
333 hide_while_typing: false,
334 hide_after_ms: 0,
335 }
336 }
337}
338
339#[derive(Clone, Debug, Eq, PartialEq)]
340pub struct FontConfig {
341 pub family: String,
342 pub size: u32,
343}
344
345impl Default for FontConfig {
346 fn default() -> Self {
347 Self {
348 family: "monospace".to_string(),
349 size: 11,
350 }
351 }
352}
353
354#[derive(Clone, Copy, Debug, Eq, PartialEq)]
355pub enum ClusterBloomDirection {
356 Clockwise,
357 CounterClockwise,
358}
359
360#[derive(Clone, Copy, Debug, Eq, PartialEq)]
361pub enum ClusterDefaultLayout {
362 Tiling,
363 Stacking,
364}
365
366impl ClusterDefaultLayout {
367 pub fn to_workspace_layout_kind(self) -> ClusterWorkspaceLayoutKind {
368 match self {
369 Self::Tiling => ClusterWorkspaceLayoutKind::Tiling,
370 Self::Stacking => ClusterWorkspaceLayoutKind::Stacking,
371 }
372 }
373}
374
375#[derive(Clone, Debug)]
376pub enum WindowRulePattern {
377 Exact(String),
378 Regex(Regex),
379}
380
381impl PartialEq for WindowRulePattern {
382 fn eq(&self, other: &Self) -> bool {
383 match (self, other) {
384 (Self::Exact(a), Self::Exact(b)) => a == b,
385 (Self::Regex(a), Self::Regex(b)) => a.as_str() == b.as_str(),
386 _ => false,
387 }
388 }
389}
390
391impl Eq for WindowRulePattern {}
392
393impl WindowRulePattern {
394 pub fn matches(&self, value: &str) -> bool {
395 match self {
396 Self::Exact(exact) => exact == value,
397 Self::Regex(regex) => regex.is_match(value),
398 }
399 }
400
401 pub fn as_str(&self) -> &str {
402 match self {
403 Self::Exact(exact) => exact.as_str(),
404 Self::Regex(regex) => regex.as_str(),
405 }
406 }
407}
408
409#[derive(Clone, Copy, Debug, Eq, PartialEq)]
410pub enum InitialWindowOverlapPolicy {
411 None,
412 ParentOnly,
413 All,
414}
415
416#[derive(Clone, Copy, Debug, Eq, PartialEq)]
417pub enum InitialWindowSpawnPlacement {
418 Center,
419 Adjacent,
420 ViewportCenter,
421 Cursor,
422 App,
423}
424
425#[derive(Clone, Copy, Debug, Eq, PartialEq)]
426pub enum InitialWindowClusterParticipation {
427 Layout,
428 Float,
429}
430
431#[derive(Clone, Debug, Eq, PartialEq)]
432pub struct WindowRule {
433 pub app_ids: Vec<WindowRulePattern>,
434 pub titles: Vec<WindowRulePattern>,
435 pub overlap_policy: InitialWindowOverlapPolicy,
436 pub spawn_placement: InitialWindowSpawnPlacement,
437 pub cluster_participation: InitialWindowClusterParticipation,
438}
439
440#[derive(Clone, Debug, PartialEq)]
441pub struct ViewportOutputConfig {
442 pub connector: String,
443 pub enabled: bool,
444 pub offset_x: i32,
445 pub offset_y: i32,
446 pub width: u32,
447 pub height: u32,
448 pub refresh_rate: Option<f64>,
449 pub transform_degrees: u16,
450 pub vrr: ViewportVrrMode,
451 pub focus_ring: Option<FocusRingConfig>,
452}
453
454#[derive(Clone, Copy, Debug, PartialEq, Eq)]
455pub enum ViewportVrrMode {
456 Off,
457 On,
458 OnDemand,
459}
460
461impl ViewportVrrMode {
462 pub fn as_str(self) -> &'static str {
463 match self {
464 Self::Off => "off",
465 Self::On => "on",
466 Self::OnDemand => "on-demand",
467 }
468 }
469
470 pub fn drm_enabled(self) -> bool {
471 !matches!(self, Self::Off)
472 }
473}