Skip to main content

native_theme/model/
dialog_order.rs

1// Dialog button ordering convention
2
3use serde::{Deserialize, Serialize};
4
5/// Specifies the order of affirmative/cancel buttons in dialogs.
6///
7/// This is a **platform convention**, not visual styling. Different desktop
8/// environments place the confirmation button at different ends of the
9/// button row (macOS/KDE: leading, Windows/GNOME: trailing). It is part
10/// of the theme model because "native feel" includes layout conventions
11/// that vary by platform, and it is overridable in theme presets.
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum DialogButtonOrder {
15    /// Affirmative button at the trailing (right) end — Windows, GNOME style.
16    #[default]
17    TrailingAffirmative,
18    /// Affirmative button at the leading (left) end — macOS, KDE style.
19    LeadingAffirmative,
20}
21
22#[cfg(test)]
23#[allow(clippy::unwrap_used, clippy::expect_used)]
24mod tests {
25    use super::*;
26
27    // TOML cannot serialize a bare enum as a top-level value; use a wrapper struct.
28    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
29    struct Wrapper {
30        order: DialogButtonOrder,
31    }
32
33    #[test]
34    fn trailing_affirmative_serializes_correctly() {
35        let w = Wrapper {
36            order: DialogButtonOrder::TrailingAffirmative,
37        };
38        let toml_str = toml::to_string(&w).unwrap();
39        assert!(toml_str.contains("trailing_affirmative"), "got: {toml_str}");
40    }
41
42    #[test]
43    fn leading_affirmative_serializes_correctly() {
44        let w = Wrapper {
45            order: DialogButtonOrder::LeadingAffirmative,
46        };
47        let toml_str = toml::to_string(&w).unwrap();
48        assert!(toml_str.contains("leading_affirmative"), "got: {toml_str}");
49    }
50
51    #[test]
52    fn trailing_affirmative_round_trip() {
53        let original = Wrapper {
54            order: DialogButtonOrder::TrailingAffirmative,
55        };
56        let serialized = toml::to_string(&original).unwrap();
57        let deserialized: Wrapper = toml::from_str(&serialized).unwrap();
58        assert_eq!(deserialized, original);
59    }
60
61    #[test]
62    fn leading_affirmative_round_trip() {
63        let original = Wrapper {
64            order: DialogButtonOrder::LeadingAffirmative,
65        };
66        let serialized = toml::to_string(&original).unwrap();
67        let deserialized: Wrapper = toml::from_str(&serialized).unwrap();
68        assert_eq!(deserialized, original);
69    }
70
71    #[test]
72    fn trailing_affirmative_deserializes_from_toml_value() {
73        let toml_str = r#"order = "trailing_affirmative""#;
74        let w: Wrapper = toml::from_str(toml_str).unwrap();
75        assert_eq!(w.order, DialogButtonOrder::TrailingAffirmative);
76    }
77
78    #[test]
79    fn leading_affirmative_deserializes_from_toml_value() {
80        let toml_str = r#"order = "leading_affirmative""#;
81        let w: Wrapper = toml::from_str(toml_str).unwrap();
82        assert_eq!(w.order, DialogButtonOrder::LeadingAffirmative);
83    }
84}