Skip to main content

fret_ui_kit/
edges4.rs

1use fret_core::Px;
2
3use crate::style::MarginEdgeRefinement;
4use crate::{MetricRef, SignedMetricRef, Space};
5
6/// A 4-edge value (top/right/bottom/left) used for fluent authoring ergonomics.
7///
8/// This intentionally lives in the ecosystem layer (`fret-ui-kit`) and is **token-aware** via
9/// `Space`/`MetricRef` conversions (unlike `fret_core::Edges`, which is Px-only).
10#[derive(Debug, Clone, PartialEq)]
11pub struct Edges4<T> {
12    pub top: T,
13    pub right: T,
14    pub bottom: T,
15    pub left: T,
16}
17
18impl<T> Edges4<T> {
19    pub fn trbl(top: T, right: T, bottom: T, left: T) -> Self {
20        Self {
21            top,
22            right,
23            bottom,
24            left,
25        }
26    }
27
28    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Edges4<U> {
29        Edges4 {
30            top: f(self.top),
31            right: f(self.right),
32            bottom: f(self.bottom),
33            left: f(self.left),
34        }
35    }
36}
37
38impl<T: Clone> Edges4<T> {
39    pub fn all(value: T) -> Self {
40        Self {
41            top: value.clone(),
42            right: value.clone(),
43            bottom: value.clone(),
44            left: value,
45        }
46    }
47
48    pub fn symmetric(horizontal: T, vertical: T) -> Self {
49        Self {
50            top: vertical.clone(),
51            right: horizontal.clone(),
52            bottom: vertical,
53            left: horizontal,
54        }
55    }
56}
57
58impl From<Edges4<Space>> for Edges4<MetricRef> {
59    fn from(value: Edges4<Space>) -> Self {
60        value.map(MetricRef::space)
61    }
62}
63
64impl From<Edges4<Px>> for Edges4<MetricRef> {
65    fn from(value: Edges4<Px>) -> Self {
66        value.map(MetricRef::Px)
67    }
68}
69
70impl From<Edges4<Space>> for Edges4<SignedMetricRef> {
71    fn from(value: Edges4<Space>) -> Self {
72        Edges4::<MetricRef>::from(value).pos()
73    }
74}
75
76impl From<Edges4<Px>> for Edges4<SignedMetricRef> {
77    fn from(value: Edges4<Px>) -> Self {
78        Edges4::<MetricRef>::from(value).pos()
79    }
80}
81
82impl Edges4<Space> {
83    pub fn pos(self) -> Edges4<SignedMetricRef> {
84        Edges4::<MetricRef>::from(self).pos()
85    }
86
87    #[allow(clippy::should_implement_trait)]
88    pub fn neg(self) -> Edges4<SignedMetricRef> {
89        Edges4::<MetricRef>::from(self).neg()
90    }
91}
92
93impl Edges4<Px> {
94    pub fn pos(self) -> Edges4<SignedMetricRef> {
95        Edges4::<MetricRef>::from(self).pos()
96    }
97
98    #[allow(clippy::should_implement_trait)]
99    pub fn neg(self) -> Edges4<SignedMetricRef> {
100        Edges4::<MetricRef>::from(self).neg()
101    }
102}
103
104impl Edges4<MetricRef> {
105    pub fn pos(self) -> Edges4<SignedMetricRef> {
106        self.map(SignedMetricRef::pos)
107    }
108
109    #[allow(clippy::should_implement_trait)]
110    pub fn neg(self) -> Edges4<SignedMetricRef> {
111        self.map(SignedMetricRef::neg)
112    }
113}
114
115/// Margin edges support `auto` in addition to px/token lengths.
116#[derive(Debug, Clone)]
117pub enum MarginEdge {
118    Px(SignedMetricRef),
119    Auto,
120}
121
122impl MarginEdge {
123    pub fn auto() -> Self {
124        Self::Auto
125    }
126
127    pub fn px(metric: impl Into<SignedMetricRef>) -> Self {
128        Self::Px(metric.into())
129    }
130}
131
132impl From<SignedMetricRef> for MarginEdge {
133    fn from(value: SignedMetricRef) -> Self {
134        Self::Px(value)
135    }
136}
137
138impl From<MetricRef> for MarginEdge {
139    fn from(value: MetricRef) -> Self {
140        Self::Px(SignedMetricRef::pos(value))
141    }
142}
143
144impl From<Px> for MarginEdge {
145    fn from(value: Px) -> Self {
146        Self::from(MetricRef::Px(value))
147    }
148}
149
150impl From<Space> for MarginEdge {
151    fn from(value: Space) -> Self {
152        Self::from(MetricRef::space(value))
153    }
154}
155
156impl From<Edges4<Space>> for Edges4<MarginEdge> {
157    fn from(value: Edges4<Space>) -> Self {
158        value.map(MarginEdge::from)
159    }
160}
161
162impl From<Edges4<Px>> for Edges4<MarginEdge> {
163    fn from(value: Edges4<Px>) -> Self {
164        value.map(MarginEdge::from)
165    }
166}
167
168impl From<Edges4<MetricRef>> for Edges4<MarginEdge> {
169    fn from(value: Edges4<MetricRef>) -> Self {
170        value.map(MarginEdge::from)
171    }
172}
173
174impl From<Edges4<SignedMetricRef>> for Edges4<MarginEdge> {
175    fn from(value: Edges4<SignedMetricRef>) -> Self {
176        value.map(MarginEdge::from)
177    }
178}
179
180impl From<MarginEdge> for MarginEdgeRefinement {
181    fn from(value: MarginEdge) -> Self {
182        match value {
183            MarginEdge::Px(m) => MarginEdgeRefinement::Px(m),
184            MarginEdge::Auto => MarginEdgeRefinement::Auto,
185        }
186    }
187}