1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
//! Enable simple layout operations in [`embedded-graphics`] //! //! This crate extends [`embedded-graphics`] with tools that ease positioning of drawable objects. //! //! `embedded-layout` consists of two main parts: //! - [alignments] that can be used to position two objects relative to one another //! * `horizontal` //! * `NoAlignment`, `Left`, `Right`, `Center` //! * `LeftToRight`, `RightToLeft` //! * `vertical` //! * `NoAlignment`, `Top`, `Bottom`, `Center` //! * `TopToBottom`, `BottomToTop` //! - [layouts] that can be used to arrange multiple views //! * `ViewGroup` //! * `LinearLayout` //! //! # Views //! //! The term "view" refers to anything `embedded-layout` can work with. Basically, a view is an //! object that can be displayed. [`View`] is the most basic trait in `embedded-layout`. Views //! implement [`View`] to enable translation and alignment operations on them, and also to allow //! them to be used with layouts. //! //! [`View`] is implemented for [`embedded-graphics`] display objects. There's also an example about //! how to implement custom [`View`] objects. //! //! ## Examples //! //! The examples are based on [the `embedded-graphics` simulator]. The simulator is built on top of //! `SDL2`. See the [simulator README] for more information. //! //! ### Draw some text to the center of the display //! //! ``` //! # use embedded_graphics::mock_display::MockDisplay; //! # let mut display: MockDisplay<BinaryColor> = MockDisplay::new(); //! # //! use embedded_graphics::{ //! fonts::{Font6x8, Text}, //! pixelcolor::BinaryColor, //! style::TextStyleBuilder, //! }; //! use embedded_layout::prelude::*; //! //! // Create a Rectangle from the display's dimensions //! let display_area = display.display_area(); //! //! let text_style = TextStyleBuilder::new(Font6x8) //! .text_color(BinaryColor::On) //! .build(); //! //! Text::new("Hello, World!", Point::zero()) //! .into_styled(text_style) //! // align text to the display //! .align_to(&display_area, horizontal::Center, vertical::Center) //! .draw(&mut display) //! .unwrap(); //! ``` //! //! ### Use [`LinearLayout`] to arrange multiple objects //! //! ``` //! # use embedded_graphics::mock_display::MockDisplay; //! # let mut display: MockDisplay<BinaryColor> = MockDisplay::new(); //! # //! use embedded_graphics::{ //! fonts::{Font6x8, Text}, //! pixelcolor::BinaryColor, //! style::TextStyleBuilder, //! }; //! use embedded_layout::{layout::linear::LinearLayout, prelude::*}; //! //! let display_area = display.display_area(); //! //! let text_style = TextStyleBuilder::new(Font6x8) //! .text_color(BinaryColor::On) //! .build(); //! //! LinearLayout::vertical() //! .with_alignment(horizontal::Center) //! .add_view(Text::new("Vertical", Point::zero()).into_styled(text_style)) //! .add_view(Text::new("Linear", Point::zero()).into_styled(text_style)) //! .add_view(Text::new("Layout", Point::zero()).into_styled(text_style)) //! .arrange() //! .align_to(&display_area, horizontal::Center, vertical::Center) //! .draw(&mut display) //! .unwrap(); //! ``` //! //! # A note on imports //! //! `embedded-layout` reexports most of `embedded-graphics`' `prelude` module. In most cases //! this means you don't have to `use embedded_graphics::prelude::*`. In case you do, `Translate` //! and `Dimensions` may interfere with `embedded-layout`'s [`View`], so if you are using functions //! of those traits, you may need to use the [fully qualified syntax] (formerly UFCS): //! //! ```compile_fail //! use embedded_layout::prelude::*; //! use embedded_graphics::prelude::*; //< this imports `Dimensions` which has a `size` function //! use embedded_graphics::primitives::Rectangle; //! //! let rect = Rectangle::with_size(Point::zero(), Size::new(10, 10)); //! let size = rect.size(); //< this fails to compile //! ``` //! //! The above example fails to compile with this message: //! //! ```text //! ---- src\lib.rs - (line 13) stdout ---- //! error[E0034]: multiple applicable items in scope //! --> src\lib.rs:19:17 //! | //! 9 | let size = rect.size(); //< this fails to compile //! | ^^^^ multiple `size` found //! | [some other lines about where the candidates are] //! ``` //! //! Here's the above example using [fully qualified syntax]: //! //! ``` //! use embedded_graphics::{prelude::*, primitives::Rectangle}; //! use embedded_layout::prelude::*; //! //! let rect = Rectangle::with_size(Point::zero(), Size::new(10, 10)); //! let size = View::size(&rect); //< Note that we are explicitly picking which `size` to call //! let size = Dimensions::size(&rect); //! ``` //! //! [`embedded-graphics`]: https://github.com/jamwaffles/embedded-graphics/ //! [the `embedded-graphics` simulator]: https://github.com/jamwaffles/embedded-graphics/tree/master/simulator //! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name //! [`View`]: crate::View //! [layouts]: crate::layout //! [`LinearLayout`]: crate::layout::linear::LinearLayout //! [simulator README]: https://github.com/jamwaffles/embedded-graphics/tree/master/simulator#usage-without-sdl2 //! [alignments]: crate::align #![cfg_attr(not(test), no_std)] #![deny(missing_docs)] #![deny(clippy::missing_inline_in_public_items)] #![warn(clippy::all)] use embedded_graphics::{geometry::Point, prelude::*, primitives::Rectangle}; pub mod align; pub mod layout; mod utils; use utils::rect_helper::RectSize; /// The essentials. Also contains most of `embedded-graphics'` prelude. pub mod prelude { pub use crate::{ align::{horizontal, vertical, Align}, utils::{display_area::DisplayArea, rect_helper::RectExt}, View, }; pub use embedded_graphics::{ drawable::{Drawable, Pixel}, fonts::Font, geometry::{Point, Size}, image::{ImageDimensions, IntoPixelIter}, pixelcolor::{raw::RawData, GrayColor, IntoStorage, PixelColor, RgbColor}, primitives::Primitive, }; } /// A `View` is the base unit for most of the `embedded-layout` operations. /// /// `View`s must have a size and a position, so they need to implement the `Dimensions` and /// `Transform` traits. /// /// See the `custom_view` example for how you can define more complex views. pub trait View { /// Get the size of a View. #[inline] fn size(&self) -> Size { RectSize::size(self.bounds()) } /// Move the origin of an object by a given number of (x, y) pixels fn translate(&mut self, by: Point); /// Returns the bounding box of the `View` as a `Rectangle` fn bounds(&self) -> Rectangle; } impl<T> View for T where T: Transform + Dimensions, { #[inline] fn translate(&mut self, by: Point) { self.translate_mut(by); } #[inline] fn bounds(&self) -> Rectangle { Rectangle::new(self.top_left(), self.bottom_right()) } } #[cfg(test)] mod test { use crate::prelude::*; use embedded_graphics::primitives::Rectangle; #[test] fn test_size() { let rect = Rectangle::new(Point::zero(), Point::new(1, 2)); assert_eq!(rect.size(), Size::new(2, 3)); } }