Skip to main content

gooey/interface/controller/component/
layout.rs

1use std::num::NonZeroU32;
2use derive_more::{From, TryInto};
3use crate::math::{num, Normalized};
4use crate::interface::controller::{size, Alignment, Area, Offset, Orientation, Size};
5use super::impl_kind;
6
7#[derive(Clone, Debug, Default, Eq, PartialEq)]
8pub struct Layout {
9  /// Orientation controls how *child* elements are *tiled* (if any). The area
10  /// specifier determines whether child elements are arranged inside the border
11  /// or extending to the edge.
12  pub orientation : (Orientation, Area),
13  pub variant     : Variant
14}
15
16impl_kind!(Layout);
17
18#[derive(Clone, Debug, Eq, PartialEq, From, TryInto)]
19pub enum Variant {
20  /// Size and position controlled by parent, given the *weight* for this frame
21  /// in relation to the others.
22  ///
23  /// ⚠ *Note*: this does not refer to *tile coordinates*, but to "tiling"
24  /// of frames, as in a "tiling window manager"
25  Tiled (Tiled),
26  /// Size and position, either relative or absolute, relative to an anchor
27  /// point. The area specifier determines whether the anchor point is inside
28  /// the border or on the exterior edge of the parent.
29  Free  (Free, Area)
30}
31
32#[derive(Clone, Debug, Eq, PartialEq)]
33pub enum Tiled {
34  Weighted (NonZeroU32),
35  Absolute (NonZeroU32)
36}
37
38/// Note that offset coordinates are relative to the anchor point, with positive
39/// pointing *into* the parent for edges, up for vertically centered, and right
40/// for horizontally centered.
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
42pub struct Free {
43  pub anchor : Alignment,
44  pub offset : Offset,
45  pub size   : Size
46}
47
48impl From <Variant> for Layout {
49  /// From variant with default orientation
50  fn from (variant : Variant) -> Self {
51    Layout {
52      orientation: Default::default(),
53      variant
54    }
55  }
56}
57
58impl From <Free> for Variant {
59  /// From free layout with default area specifier
60  fn from (free : Free) -> Self {
61    Variant::Free (free, Area::default())
62  }
63}
64
65impl Default for Variant {
66  fn default() -> Self {
67    (Free::default(), Area::default()).into()
68  }
69}
70
71impl Free {
72  /// Free layout with upper-left anchor and absolute offset and absolute size
73  /// of 24 width by 12 height
74  #[inline]
75  pub fn default_tile() -> Self {
76    Free {
77      anchor: Alignment::tile(),
78      offset: Offset::default_absolute(),
79      size:   Size {
80        width:  24.into(),
81        height: 12.into()
82      }
83    }
84  }
85  /// Free layout with lower-left anchor and absolute offset and absolute size
86  /// of 640 width by 480 height
87  #[inline]
88  pub fn default_pixel() -> Self {
89    Free {
90      anchor: Alignment::pixel(),
91      offset: Offset::default_absolute(),
92      size:   Size {
93        width:  640.into(),
94        height: 480.into()
95      }
96    }
97  }
98
99  /// Free layout with upper-left anchor and absolute offset and given size
100  pub fn tile (size : Size) -> Self {
101    Free {
102      anchor: Alignment::tile(),
103      offset: Offset::default_absolute(),
104      size
105    }
106  }
107
108  /// Free layout with lower-left anchor and absolute offset and given size
109  pub fn pixel (size : Size) -> Self {
110    Free {
111      anchor: Alignment::pixel(),
112      offset: Offset::default_absolute(),
113      size
114    }
115  }
116
117  /// Centered frame with given size and no offset
118  pub fn middle_center (size : Size) -> Self {
119    Free {
120      anchor: Alignment::middle_center(),
121      offset: Offset::default_absolute(),
122      size
123    }
124  }
125
126  /// Free layout with middle+centered anchor, 100% relative width and height,
127  /// and default absolute offset
128  #[inline]
129  pub fn middle_center_max() -> Self {
130    use num::One;
131    Free {
132      anchor: Alignment::middle_center(),
133      size:   Size {
134        width:  Normalized::<f32>::one().into(),
135        height: Normalized::<f32>::one().into()
136      },
137      offset: Offset::default_absolute()
138    }
139  }
140
141  #[inline]
142  pub fn offset_move_right (&mut self) {
143    self.offset = self.offset.move_right (self.anchor, 1);
144  }
145  #[inline]
146  pub fn offset_move_left (&mut self) {
147    self.offset = self.offset.move_left (self.anchor, 1);
148  }
149  #[inline]
150  pub fn offset_move_up (&mut self) {
151    self.offset = self.offset.move_up (self.anchor, 1);
152  }
153  #[inline]
154  pub fn offset_move_down (&mut self) {
155    self.offset = self.offset.move_down (self.anchor, 1);
156  }
157  /// Grows absolute size by one unit or relative size by 1/60th.
158  #[inline]
159  pub fn size_grow_width (&mut self) {
160    match self.size.width {
161      size::Unsigned::Absolute (ref mut width) =>
162        *width = std::cmp::max (1, *width as i32 + 1) as u32,
163      size::Unsigned::Relative (ref mut width) =>
164        *width = Normalized::clamp (**width + 1.0/60.0)
165    }
166  }
167  /// Grows absolute size by one unit or relative size by 1/60th.
168  #[inline]
169  pub fn size_grow_height (&mut self) {
170    match self.size.height {
171      size::Unsigned::Absolute (ref mut height) =>
172        *height = std::cmp::max (1, *height as i32 + 1) as u32,
173      size::Unsigned::Relative (ref mut height) =>
174        *height = Normalized::clamp (**height + 1.0/60.0)
175    }
176  }
177  /// Shrinks absolute size by one unit or relative size by 1/60th.
178  ///
179  /// Enforces a minimum absolute size of 1 unit and minimum relative size of
180  /// 1/60th.
181  #[inline]
182  pub fn size_shrink_width (&mut self) {
183    match self.size.width {
184      size::Unsigned::Absolute (ref mut width) =>
185        *width = std::cmp::max (1, *width as i32 - 1) as u32,
186      size::Unsigned::Relative (ref mut width) =>
187        *width = Normalized::clamp ((**width - 1.0/60.0).max (1.0/60.0))
188    }
189  }
190  /// Shrinks absolute size by one unit or relative size by 1/60th.
191  ///
192  /// Enforces a minimum absolute size of 1 unit and minimum relative size of 1/60th.
193  #[inline]
194  pub fn size_shrink_height (&mut self) {
195    match self.size.height {
196      size::Unsigned::Absolute (ref mut height) =>
197        *height = std::cmp::max (1, *height as i32 - 1) as u32,
198      size::Unsigned::Relative (ref mut height) =>
199        *height = Normalized::clamp ((**height - 1.0/60.0).max (1.0/60.0))
200    }
201  }
202}
203
204impl Default for Free {
205  /// Default tile coordinates
206  fn default() -> Self {
207    Self::default_tile()
208  }
209}
210
211impl Tiled {
212  /// Clamps to the range `[1, u32::MAX]`
213  pub fn modify_size (&mut self, modify : i32) {
214    let size = match self {
215      Tiled::Weighted (n) | Tiled::Absolute (n) => n
216    };
217    let s = size.get() as i64 + modify as i64;
218    let new_size = s.max (1).min (u32::MAX as i64) as u32;
219    *size = NonZeroU32::new (new_size).unwrap();
220  }
221}
222
223impl Default for Tiled {
224  fn default() -> Self {
225    Tiled::Weighted (NonZeroU32::new (1).unwrap())
226  }
227}