gooey/interface/controller/component/
layout.rs

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