drmkit_csd/state.rs
1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! What a decorated window currently is.
5
6/// Which window button the pointer is over.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
8#[non_exhaustive]
9pub enum HoverButton {
10 /// None of them.
11 #[default]
12 None,
13 /// Close.
14 Close,
15 /// Minimize.
16 Minimize,
17 /// Maximize.
18 Maximize,
19}
20
21/// What changed since the decoration was last drawn.
22///
23/// A bitmask rather than a bool: redrawing a title bar because the pointer
24/// moved over a button costs a rounded-rect fill; redrawing it because the
25/// geometry changed costs a blur. A caller that cannot tell them apart pays
26/// the second price for the first event.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct Dirty(u32);
29
30impl Dirty {
31 /// Nothing changed.
32 pub const NONE: Self = Self(0);
33 /// The title text.
34 pub const TITLE: Self = Self(1 << 0);
35 /// Focus.
36 pub const FOCUS: Self = Self(1 << 1);
37 /// Which button is hovered.
38 pub const HOVER: Self = Self(1 << 2);
39 /// The window's size or position.
40 pub const GEOMETRY: Self = Self(1 << 3);
41 /// An animation advanced.
42 pub const ANIMATION: Self = Self(1 << 4);
43 /// Everything. What a freshly created state carries, since nothing has
44 /// been drawn yet and every part of it is new.
45 pub const ALL: Self = Self(u32::MAX);
46
47 /// Whether any of `other`'s bits are set here.
48 #[must_use]
49 pub const fn intersects(self, other: Self) -> bool {
50 self.0 & other.0 != 0
51 }
52
53 /// Both sets of bits.
54 #[must_use]
55 pub const fn union(self, other: Self) -> Self {
56 Self(self.0 | other.0)
57 }
58
59 /// Whether nothing is set.
60 #[must_use]
61 pub const fn is_empty(self) -> bool {
62 self.0 == 0
63 }
64}
65
66/// The progress value a state carries before an animator has written one.
67///
68/// Out of the `0..=1` range on purpose: a caller can tell "not yet animated"
69/// from "animated to zero", which are different things — the first means draw
70/// it settled, the second means draw it mid-transition at the start.
71pub const PROGRESS_UNSET: f32 = -1.0;
72
73/// A decorated window, as the renderer sees it.
74#[derive(Debug, Clone, PartialEq)]
75#[allow(
76 clippy::exhaustive_structs,
77 reason = "built by callers with `..Default::default()`, which a new field does not break"
78)]
79pub struct WindowState {
80 /// The title text.
81 pub title: String,
82 /// Whether the window has focus.
83 pub focused: bool,
84 /// Which button is hovered.
85 pub hover: HoverButton,
86 /// What has changed since the last draw.
87 pub dirty: Dirty,
88 /// How far through the focus transition, or [`PROGRESS_UNSET`].
89 pub focus_progress: f32,
90 /// How far through the hover transition, or [`PROGRESS_UNSET`].
91 pub hover_progress: f32,
92}
93
94impl Default for WindowState {
95 fn default() -> Self {
96 Self {
97 title: String::new(),
98 focused: false,
99 hover: HoverButton::None,
100 dirty: Dirty::ALL,
101 focus_progress: PROGRESS_UNSET,
102 hover_progress: PROGRESS_UNSET,
103 }
104 }
105}