1 //! Direction-related structures. 2 //! 3 //! This module defines two main concepts: [`Orientation`] and [`Direction`]. 4 //! 5 //! [`Orientation`]: enum.Orientation.html 6 //! [`Direction`]: enum.Direction.html 7 //! 8 //! ### Orientation 9 //! 10 //! `Orientation` is a simple enum that can take two values: 11 //! `Horizontal` or `Vertical`. 12 //! 13 //! ### Direction 14 //! 15 //! `Direction` is a bit more complex, and can be of two kinds: 16 //! 17 //! * Absolute direction: left, up, right, or down 18 //! * Relative direction: front or back. Its actual direction depends on the 19 //! orientation. 20 //! 21 //! Usually, "front" refers to the "forward" direction, or the "next" 22 //! element. For example, for a vertical `LinearLayout`, "front" would refer 23 //! to the "down" direction. 24 //! 25 //! This is mostly relevant when referring to change of focus. Hitting the 26 //! `Tab` key would usually cycle focus in the "front" direction, while 27 //! using the arrow keys would use absolute directions instead. 28 29 use crate::Vec2; 30 use crate::XY; 31 32 /// Describes a vertical or horizontal orientation for a view. 33 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 34 pub enum Orientation { 35 /// Horizontal orientation 36 Horizontal, 37 /// Vertical orientation 38 Vertical, 39 } 40 41 impl Orientation { 42 /// Returns a `XY(Horizontal, Vertical)`. pair() -> XY<Orientation>43 pub fn pair() -> XY<Orientation> { 44 XY::new(Orientation::Horizontal, Orientation::Vertical) 45 } 46 47 /// Returns the component of `v` corresponding to this orientation. 48 /// 49 /// (`Horizontal` will return the x value, 50 /// and `Vertical` will return the y value.) get<T: Clone>(self, v: &XY<T>) -> T51 pub fn get<T: Clone>(self, v: &XY<T>) -> T { 52 v.get(self).clone() 53 } 54 55 /// Returns the other orientation. swap(self) -> Self56 pub fn swap(self) -> Self { 57 match self { 58 Orientation::Horizontal => Orientation::Vertical, 59 Orientation::Vertical => Orientation::Horizontal, 60 } 61 } 62 63 /// Returns a mutable reference to the component of the given vector 64 /// corresponding to this orientation. 65 /// 66 /// # Examples 67 /// ```rust 68 /// # use cursive_core::XY; 69 /// # use cursive_core::direction::Orientation; 70 /// let o = Orientation::Horizontal; 71 /// let mut xy = XY::new(1, 2); 72 /// *o.get_ref(&mut xy) = 42; 73 /// 74 /// assert_eq!(xy, XY::new(42, 2)); 75 /// ``` get_ref<T>(self, v: &mut XY<T>) -> &mut T76 pub fn get_ref<T>(self, v: &mut XY<T>) -> &mut T { 77 match self { 78 Orientation::Horizontal => &mut v.x, 79 Orientation::Vertical => &mut v.y, 80 } 81 } 82 83 /// Takes an iterator on sizes, and stack them in the current orientation, 84 /// returning the size of the required bounding box. 85 /// 86 /// * For an horizontal view, returns `(Sum(x), Max(y))`. 87 /// * For a vertical view, returns `(Max(x), Sum(y))`. stack<T: Iterator<Item = Vec2>>(self, iter: T) -> Vec288 pub fn stack<T: Iterator<Item = Vec2>>(self, iter: T) -> Vec2 { 89 match self { 90 Orientation::Horizontal => { 91 iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(&b)) 92 } 93 Orientation::Vertical => { 94 iter.fold(Vec2::zero(), |a, b| a.stack_vertical(&b)) 95 } 96 } 97 } 98 99 /// Creates a new `Vec2` with `main_axis` in `self`'s axis, and 100 /// `second_axis` for the other axis. 101 /// 102 /// # Examples 103 /// 104 /// ```rust 105 /// # use cursive_core::direction::Orientation; 106 /// # use cursive_core::Vec2; 107 /// let o = Orientation::Horizontal; 108 /// let vec = o.make_vec(1, 2); 109 /// 110 /// assert_eq!(vec, Vec2::new(1, 2)); 111 /// 112 /// let o = Orientation::Vertical; 113 /// let vec = o.make_vec(1, 2); 114 /// 115 /// assert_eq!(vec, Vec2::new(2, 1)); 116 /// ``` make_vec(self, main_axis: usize, second_axis: usize) -> Vec2117 pub fn make_vec(self, main_axis: usize, second_axis: usize) -> Vec2 { 118 let mut result = Vec2::zero(); 119 *self.get_ref(&mut result) = main_axis; 120 *self.swap().get_ref(&mut result) = second_axis; 121 result 122 } 123 } 124 125 /// Represents a direction, either absolute or orientation-dependent. 126 /// 127 /// * Absolute directions are Up, Down, Left, and Right. 128 /// * Relative directions are Front and Back. 129 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 130 pub enum Direction { 131 /// An absolute direction. 132 Abs(Absolute), 133 /// A direction relative to the current orientation. 134 Rel(Relative), 135 } 136 137 impl Direction { 138 /// Returns the relative direction for the given orientation. 139 /// 140 /// Some combination have no corresponding relative position. For example, 141 /// `Direction::Abs(Up)` means nothing for `Orientation::Horizontal`. relative(self, orientation: Orientation) -> Option<Relative>142 pub fn relative(self, orientation: Orientation) -> Option<Relative> { 143 match self { 144 Direction::Abs(abs) => abs.relative(orientation), 145 Direction::Rel(rel) => Some(rel), 146 } 147 } 148 149 /// Returns the absolute direction in the given `orientation`. absolute(self, orientation: Orientation) -> Absolute150 pub fn absolute(self, orientation: Orientation) -> Absolute { 151 match self { 152 Direction::Abs(abs) => abs, 153 Direction::Rel(rel) => rel.absolute(orientation), 154 } 155 } 156 157 /// Returns the direction opposite `self`. opposite(self) -> Self158 pub fn opposite(self) -> Self { 159 match self { 160 Direction::Abs(abs) => Direction::Abs(abs.opposite()), 161 Direction::Rel(rel) => Direction::Rel(rel.swap()), 162 } 163 } 164 165 /// Shortcut to create `Direction::Rel(Relative::Back)` back() -> Self166 pub fn back() -> Self { 167 Direction::Rel(Relative::Back) 168 } 169 170 /// Shortcut to create `Direction::Rel(Relative::Front)` front() -> Self171 pub fn front() -> Self { 172 Direction::Rel(Relative::Front) 173 } 174 175 /// Shortcut to create `Direction::Abs(Absolute::Left)` left() -> Self176 pub fn left() -> Self { 177 Direction::Abs(Absolute::Left) 178 } 179 180 /// Shortcut to create `Direction::Abs(Absolute::Right)` right() -> Self181 pub fn right() -> Self { 182 Direction::Abs(Absolute::Right) 183 } 184 185 /// Shortcut to create `Direction::Abs(Absolute::Up)` up() -> Self186 pub fn up() -> Self { 187 Direction::Abs(Absolute::Up) 188 } 189 190 /// Shortcut to create `Direction::Abs(Absolute::Down)` down() -> Self191 pub fn down() -> Self { 192 Direction::Abs(Absolute::Down) 193 } 194 195 /// Shortcut to create `Direction::Abs(Absolute::None)` none() -> Self196 pub fn none() -> Self { 197 Direction::Abs(Absolute::None) 198 } 199 } 200 201 /// Direction relative to an orientation. 202 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 203 pub enum Relative { 204 // TODO: handle right-to-left? (Arabic, ...) 205 /// Front relative direction. 206 /// 207 /// * Horizontally, this means `Left` 208 /// * Vertically, this means `Up` 209 Front, 210 211 /// Back relative direction. 212 /// 213 /// * Horizontally, this means `Right` 214 /// * Vertically, this means `Down`. 215 Back, 216 } 217 218 impl Relative { 219 /// Returns the absolute direction in the given `orientation`. absolute(self, orientation: Orientation) -> Absolute220 pub fn absolute(self, orientation: Orientation) -> Absolute { 221 match (orientation, self) { 222 (Orientation::Horizontal, Relative::Front) => Absolute::Left, 223 (Orientation::Horizontal, Relative::Back) => Absolute::Right, 224 (Orientation::Vertical, Relative::Front) => Absolute::Up, 225 (Orientation::Vertical, Relative::Back) => Absolute::Down, 226 } 227 } 228 229 /// Picks one of the two values in a tuple. 230 /// 231 /// First one is `self` is `Front`, second one if `self` is `Back`. pick<T>(self, (front, back): (T, T)) -> T232 pub fn pick<T>(self, (front, back): (T, T)) -> T { 233 match self { 234 Relative::Front => front, 235 Relative::Back => back, 236 } 237 } 238 239 /// Returns the other relative direction. swap(self) -> Self240 pub fn swap(self) -> Self { 241 match self { 242 Relative::Front => Relative::Back, 243 Relative::Back => Relative::Front, 244 } 245 } 246 247 /// Returns the relative position of `a` to `b`. 248 /// 249 /// If `a < b`, it would be `Front`. 250 /// If `a > b`, it would be `Back`. 251 /// If `a == b`, returns `None`. a_to_b(a: usize, b: usize) -> Option<Self>252 pub fn a_to_b(a: usize, b: usize) -> Option<Self> { 253 use std::cmp::Ordering; 254 255 match a.cmp(&b) { 256 Ordering::Less => Some(Relative::Front), 257 Ordering::Greater => Some(Relative::Back), 258 Ordering::Equal => None, 259 } 260 } 261 } 262 263 /// Absolute direction (up, down, left, right). 264 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 265 pub enum Absolute { 266 /// Left 267 Left, 268 /// Up 269 Up, 270 /// Right 271 Right, 272 /// Down 273 Down, 274 275 /// No real direction. 276 /// 277 /// Used when the "direction" is accross layers for instance. 278 None, 279 } 280 281 impl Absolute { 282 /// Returns the relative direction for the given orientation. 283 /// 284 /// Returns `None` when the direction does not apply to the given 285 /// orientation (ex: `Left` and `Vertical`). relative(self, orientation: Orientation) -> Option<Relative>286 pub fn relative(self, orientation: Orientation) -> Option<Relative> { 287 match (orientation, self) { 288 (Orientation::Horizontal, Absolute::Left) 289 | (Orientation::Vertical, Absolute::Up) => Some(Relative::Front), 290 (Orientation::Horizontal, Absolute::Right) 291 | (Orientation::Vertical, Absolute::Down) => Some(Relative::Back), 292 _ => None, 293 } 294 } 295 296 /// Returns the direction opposite `self`. opposite(self) -> Self297 pub fn opposite(self) -> Self { 298 match self { 299 Absolute::Left => Absolute::Right, 300 Absolute::Right => Absolute::Left, 301 Absolute::Up => Absolute::Down, 302 Absolute::Down => Absolute::Up, 303 Absolute::None => Absolute::None, 304 } 305 } 306 307 /// Splits this absolute direction into an orientation and relative direction. 308 /// 309 /// For example, `Right` will give `(Horizontal, Back)`. split(self) -> (Orientation, Relative)310 pub fn split(self) -> (Orientation, Relative) { 311 match self { 312 Absolute::Left => (Orientation::Horizontal, Relative::Front), 313 Absolute::Right => (Orientation::Horizontal, Relative::Back), 314 Absolute::Up => (Orientation::Vertical, Relative::Front), 315 Absolute::Down => (Orientation::Vertical, Relative::Back), 316 // TODO: Remove `Absolute::None` 317 Absolute::None => panic!("None direction not supported here"), 318 } 319 } 320 } 321