Skip to main content

native_theme/model/
tab_indicator_side.rs

1// Active-tab indicator placement convention
2
3use serde::{Deserialize, Serialize};
4
5/// Which edge of the active tab its indicator line lies along, for tabs above
6/// their pages.
7///
8/// A **platform convention**, like [`ArrowSide`](crate::model::ArrowSide):
9/// Breeze lays its highlight strip along a North tab's top edge, libadwaita's
10/// GtkNotebook and Material's primary tabs along the bottom one
11/// (`docs/platform-facts.md` ยง2.11, `active_indicator_side`). Tabs below their
12/// pages mirror it on every platform that draws one.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum TabIndicatorSide {
15    /// Along the tab's top edge, away from its page -- KDE.
16    #[serde(rename = "top")]
17    Top,
18    /// Along the tab's bottom edge, next to its page -- GNOME, Material.
19    #[serde(rename = "bottom")]
20    Bottom,
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        side: TabIndicatorSide,
32    }
33
34    #[test]
35    fn serde_round_trip_both_variants() {
36        for (variant, expected_str) in [
37            (TabIndicatorSide::Top, "top"),
38            (TabIndicatorSide::Bottom, "bottom"),
39        ] {
40            let original = Wrapper { side: 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 an_unknown_side_is_rejected() {
50        assert!(toml::from_str::<Wrapper>(r#"side = "left""#).is_err());
51    }
52}