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    /// Returns the constraints that the parent passed to the layout, in pixels.
33    fn constraints(&self) -> Constraints;
34    /// Returns the minimum width constraint as a [`Dp`].
35    fn min_width(&self) -> Dp;
36    /// Returns the maximum width constraint as a [`Dp`]. Infinite when the width is unbounded.
37    fn max_width(&self) -> Dp;
38    /// Returns the minimum height constraint as a [`Dp`].
39    fn min_height(&self) -> Dp;
40    /// Returns the maximum height constraint as a [`Dp`]. Infinite when the height is unbounded.
41    fn max_height(&self) -> Dp;
42}
43
44/// Concrete implementation of [`BoxWithConstraintsScope`].
45#[derive(Clone, Copy, Debug, PartialEq)]
46pub struct BoxWithConstraintsScopeImpl {
47    constraints: Constraints,
48    density: f32,
49}
50
51impl BoxWithConstraintsScopeImpl {
52    /// Creates a scope for `constraints` at a density of 1.0, where one dp is one pixel.
53    pub fn new(constraints: Constraints) -> Self {
54        Self {
55            constraints,
56            density: 1.0,
57        }
58    }
59
60    /// Creates a scope for `constraints` where one dp is `density` pixels.
61    pub fn with_density(constraints: Constraints, density: f32) -> Self {
62        Self {
63            constraints,
64            density,
65        }
66    }
67
68    fn to_dp(self, raw: f32) -> Dp {
69        Dp::from_px(Px(raw), Density::from_scale(self.density))
70    }
71
72    /// Converts `dp` to pixels at this scope's density.
73    pub fn to_px(&self, dp: Dp) -> f32 {
74        dp.to_px(Density::from_scale(self.density)).0
75    }
76
77    /// Returns the number of pixels in one dp.
78    pub fn density(&self) -> f32 {
79        self.density
80    }
81}
82
83impl BoxScope for BoxWithConstraintsScopeImpl {
84    fn align(&self, alignment: Alignment) -> Modifier {
85        BoxScopeImpl.align(alignment)
86    }
87}
88
89/// Concrete implementation of BoxScope.
90#[derive(Clone, Copy, Debug, PartialEq)]
91pub struct BoxScopeImpl;
92
93impl BoxScope for BoxScopeImpl {
94    fn align(&self, alignment: Alignment) -> Modifier {
95        Modifier::empty().alignInBox(alignment)
96    }
97}
98
99/// Creates Column child modifiers through [`ColumnScope`].
100#[derive(Clone, Copy, Debug, PartialEq)]
101pub struct ColumnScopeImpl;
102
103impl ColumnScope for ColumnScopeImpl {
104    fn align(&self, alignment: HorizontalAlignment) -> Modifier {
105        Modifier::empty().alignInColumn(alignment)
106    }
107
108    fn weight(&self, weight: f32, fill: bool) -> Modifier {
109        Modifier::empty().columnWeight(weight, fill)
110    }
111}
112
113/// Creates Row child modifiers through [`RowScope`].
114#[derive(Clone, Copy, Debug, PartialEq)]
115pub struct RowScopeImpl;
116
117impl RowScope for RowScopeImpl {
118    fn align(&self, alignment: VerticalAlignment) -> Modifier {
119        Modifier::empty().alignInRow(alignment)
120    }
121
122    fn weight(&self, weight: f32, fill: bool) -> Modifier {
123        Modifier::empty().rowWeight(weight, fill)
124    }
125}
126
127impl BoxWithConstraintsScope for BoxWithConstraintsScopeImpl {
128    fn constraints(&self) -> Constraints {
129        self.constraints
130    }
131
132    fn min_width(&self) -> Dp {
133        self.to_dp(self.constraints.min_width)
134    }
135
136    fn max_width(&self) -> Dp {
137        self.to_dp(self.constraints.max_width)
138    }
139
140    fn min_height(&self) -> Dp {
141        self.to_dp(self.constraints.min_height)
142    }
143
144    fn max_height(&self) -> Dp {
145        self.to_dp(self.constraints.max_height)
146    }
147}