Skip to main content

cranpose_ui/widgets/
scopes.rs

1//! Scope traits and implementations for Box, Column, and Row
2
3use cranpose_ui_graphics::{Density, Dp, Px};
4use cranpose_ui_layout::{Alignment, Constraints, HorizontalAlignment, VerticalAlignment};
5
6use crate::modifier::Modifier;
7
8/// Child alignment modifiers for a Box.
9pub trait BoxScope {
10    /// Align content within the Box on both axes.
11    fn align(&self, alignment: Alignment) -> Modifier;
12}
13
14/// Horizontal alignment and weight modifiers for Column children.
15pub trait ColumnScope {
16    /// Align content horizontally within the Column.
17    fn align(&self, alignment: HorizontalAlignment) -> Modifier;
18    /// Apply weight to distribute remaining space proportionally.
19    fn weight(&self, weight: f32, fill: bool) -> Modifier;
20}
21
22/// Vertical alignment and weight modifiers for Row children.
23pub trait RowScope {
24    /// Align content vertically within the Row.
25    fn align(&self, alignment: VerticalAlignment) -> Modifier;
26    /// Apply weight to distribute remaining space proportionally.
27    fn weight(&self, weight: f32, fill: bool) -> Modifier;
28}
29
30/// Scope exposed to `BoxWithConstraints` content.
31pub trait BoxWithConstraintsScope: BoxScope {
32    fn constraints(&self) -> Constraints;
33    fn min_width(&self) -> Dp;
34    fn max_width(&self) -> Dp;
35    fn min_height(&self) -> Dp;
36    fn max_height(&self) -> Dp;
37}
38
39/// Concrete implementation of [`BoxWithConstraintsScope`].
40#[derive(Clone, Copy, Debug, PartialEq)]
41pub struct BoxWithConstraintsScopeImpl {
42    constraints: Constraints,
43    density: f32,
44}
45
46impl BoxWithConstraintsScopeImpl {
47    pub fn new(constraints: Constraints) -> Self {
48        Self {
49            constraints,
50            density: 1.0,
51        }
52    }
53
54    pub fn with_density(constraints: Constraints, density: f32) -> Self {
55        Self {
56            constraints,
57            density,
58        }
59    }
60
61    fn to_dp(self, raw: f32) -> Dp {
62        Dp::from_px(Px(raw), Density::from_scale(self.density))
63    }
64
65    pub fn to_px(&self, dp: Dp) -> f32 {
66        dp.to_px(Density::from_scale(self.density)).0
67    }
68
69    pub fn density(&self) -> f32 {
70        self.density
71    }
72}
73
74impl BoxScope for BoxWithConstraintsScopeImpl {
75    fn align(&self, alignment: Alignment) -> Modifier {
76        BoxScopeImpl.align(alignment)
77    }
78}
79
80/// Concrete implementation of BoxScope.
81#[derive(Clone, Copy, Debug, PartialEq)]
82pub struct BoxScopeImpl;
83
84impl BoxScope for BoxScopeImpl {
85    fn align(&self, alignment: Alignment) -> Modifier {
86        Modifier::empty().alignInBox(alignment)
87    }
88}
89
90/// Creates Column child modifiers through [`ColumnScope`].
91#[derive(Clone, Copy, Debug, PartialEq)]
92pub struct ColumnScopeImpl;
93
94impl ColumnScope for ColumnScopeImpl {
95    fn align(&self, alignment: HorizontalAlignment) -> Modifier {
96        Modifier::empty().alignInColumn(alignment)
97    }
98
99    fn weight(&self, weight: f32, fill: bool) -> Modifier {
100        Modifier::empty().columnWeight(weight, fill)
101    }
102}
103
104/// Creates Row child modifiers through [`RowScope`].
105#[derive(Clone, Copy, Debug, PartialEq)]
106pub struct RowScopeImpl;
107
108impl RowScope for RowScopeImpl {
109    fn align(&self, alignment: VerticalAlignment) -> Modifier {
110        Modifier::empty().alignInRow(alignment)
111    }
112
113    fn weight(&self, weight: f32, fill: bool) -> Modifier {
114        Modifier::empty().rowWeight(weight, fill)
115    }
116}
117
118impl BoxWithConstraintsScope for BoxWithConstraintsScopeImpl {
119    fn constraints(&self) -> Constraints {
120        self.constraints
121    }
122
123    fn min_width(&self) -> Dp {
124        self.to_dp(self.constraints.min_width)
125    }
126
127    fn max_width(&self) -> Dp {
128        self.to_dp(self.constraints.max_width)
129    }
130
131    fn min_height(&self) -> Dp {
132        self.to_dp(self.constraints.min_height)
133    }
134
135    fn max_height(&self) -> Dp {
136        self.to_dp(self.constraints.max_height)
137    }
138}