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
//! Enable simple layout operations in [`embedded-graphics`]
//!
//! This crate extends [`embedded-graphics`] with tools that ease positioning of drawable objects.
//!
//! `embedded-layout` consists of three 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
//! * `LinearLayout`
//! - [view groups] which are collections of view objects
//! * `Chain` to create ad-hoc collections (can hold views of different types)
//! * `Views` to create view groups from arrays and slices (can only hold views of a single type)
//! * `derive(ViewGroup)` to turn any plain old Rust struct into a view group
//!
//! # 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 the [`View`] trait 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 you can 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::{
//! mono_font::{ascii::FONT_6X9, MonoTextStyle},
//! pixelcolor::BinaryColor,
//! prelude::*,
//! text::Text,
//! };
//! use embedded_layout::prelude::*;
//!
//! // Create a Rectangle from the display's dimensions
//! let display_area = display.bounding_box();
//!
//! let text_style = MonoTextStyle::new(&FONT_6X9, BinaryColor::On);
//!
//! Text::new("Hello!", Point::zero(), text_style)
//! // align text to the center of 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::{
//! mono_font::{ascii::FONT_6X9, MonoTextStyle},
//! pixelcolor::BinaryColor,
//! prelude::*,
//! text::Text,
//! };
//! use embedded_layout::{layout::linear::LinearLayout, prelude::*};
//!
//! let display_area = display.bounding_box();
//!
//! let text_style = MonoTextStyle::new(&FONT_6X9, BinaryColor::On);
//!
//! LinearLayout::vertical(
//! Chain::new(Text::new("Vertical", Point::zero(), text_style))
//! .append(Text::new("Linear", Point::zero(), text_style))
//! .append(Text::new("Layout", Point::zero(), text_style))
//! )
//! .with_alignment(horizontal::Center)
//! .arrange()
//! .align_to(&display_area, horizontal::Center, vertical::Center)
//! .draw(&mut display)
//! .unwrap();
//! ```
//!
//! [`embedded-graphics`]: https://crates.io/crates/embedded-graphics/0.6.2
//! [the `embedded-graphics` simulator]: https://crates.io/crates/embedded-graphics-simulator/0.2.1
//! [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/v0.6/simulator#usage-without-sdl2
//! [alignments]: crate::align
//! [view groups]: crate::view_group
#![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 use embedded_layout_macros::ViewGroup;
pub mod align;
pub mod layout;
pub mod object_chain;
pub mod utils;
pub mod view_group;
/// The essentials. Also contains most of `embedded-graphics'` prelude.
pub mod prelude {
pub use crate::{
align::{horizontal, vertical, Align},
chain,
object_chain::{Chain, Link},
utils::rect_helper::RectExt,
view_group::Views,
View,
};
}
/// A `View` is the base unit for most of the `embedded-layout` operations.
///
/// `View`s must have a size and a position.
///
/// 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 {
self.bounds().size
}
/// Object-safe version of `translate_mut()`.
///
/// The default implementations of `translate` and `translate_mut` both call this functions.
fn translate_impl(&mut self, by: Point);
/// Move the origin of an object by a given number of (x, y) pixels, mutating the object in place.
///
/// If you a looking for a method to implement, you might want `translate_impl()` instead.
#[inline]
fn translate_mut(&mut self, by: Point) -> &mut Self
where
Self: Sized,
{
self.translate_impl(by);
self
}
/// Move the origin of an object by a given number of (x, y) pixels, returning a new object.
///
/// If you a looking for a method to implement, you might want `translate_impl()` instead.
#[inline]
fn translate(mut self, by: Point) -> Self
where
Self: Sized,
{
self.translate_impl(by);
self
}
/// 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_impl(&mut self, by: Point) {
Transform::translate_mut(self, by);
}
#[inline]
fn bounds(&self) -> Rectangle {
self.bounding_box()
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[allow(dead_code)]
fn view_is_object_safe(_: &dyn View) {}
}