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 primary/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 (KDE: leading/left, Windows/GNOME/macOS: trailing/right).
10/// It is part of the theme model because "native feel" includes layout
11/// conventions that vary by platform, and it is overridable in theme presets.
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub enum DialogButtonOrder {
14    /// Primary button at the trailing (right) end -- Windows, GNOME, macOS, iOS style.
15    #[default]
16    #[serde(rename = "primary_right")]
17    PrimaryRight,
18    /// Primary button at the leading (left) end -- KDE style.
19    #[serde(rename = "primary_left")]
20    PrimaryLeft,
21}
22
23#[cfg(test)]
24#[allow(clippy::unwrap_used, clippy::expect_used)]
25mod tests {
26    use super::*;
27
28    // TOML cannot serialize a bare enum as a top-level value; use a wrapper struct.
29    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
30    struct Wrapper {
31        order: DialogButtonOrder,
32    }
33
34    #[test]
35    fn serde_round_trip_both_variants() {
36        for (variant, expected_str) in [
37            (DialogButtonOrder::PrimaryRight, "primary_right"),
38            (DialogButtonOrder::PrimaryLeft, "primary_left"),
39        ] {
40            let original = Wrapper { order: variant };
41            let serialized = toml::to_string(&original).unwrap();
42            assert!(serialized.contains(expected_str), "got: {serialized}");
43            let deserialized: Wrapper = toml::from_str(&serialized).unwrap();
44            assert_eq!(deserialized, original);
45        }
46    }
47
48    #[test]
49    fn deserializes_from_toml_string_values() {
50        for (toml_str, expected) in [
51            (
52                r#"order = "primary_right""#,
53                DialogButtonOrder::PrimaryRight,
54            ),
55            (r#"order = "primary_left""#, DialogButtonOrder::PrimaryLeft),
56        ] {
57            let w: Wrapper = toml::from_str(toml_str).unwrap();
58            assert_eq!(w.order, expected);
59        }
60    }
61
62    #[test]
63    fn debug_output_both_variants() {
64        assert_eq!(
65            format!("{:?}", DialogButtonOrder::PrimaryRight),
66            "PrimaryRight"
67        );
68        assert_eq!(
69            format!("{:?}", DialogButtonOrder::PrimaryLeft),
70            "PrimaryLeft"
71        );
72    }
73
74    #[test]
75    fn default_is_primary_right() {
76        assert_eq!(
77            DialogButtonOrder::default(),
78            DialogButtonOrder::PrimaryRight
79        );
80    }
81}