diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/CHANGELOG.md | 19 | ||||
-rw-r--r-- | core/Cargo.toml | 6 | ||||
-rw-r--r-- | core/README.md | 6 | ||||
-rw-r--r-- | core/src/background.rs | 6 | ||||
-rw-r--r-- | core/src/color.rs | 139 | ||||
-rw-r--r-- | core/src/font.rs | 6 | ||||
-rw-r--r-- | core/src/keyboard.rs | 8 | ||||
-rw-r--r-- | core/src/keyboard/event.rs | 34 | ||||
-rw-r--r-- | core/src/keyboard/key_code.rs | 203 | ||||
-rw-r--r-- | core/src/keyboard/modifiers.rs | 45 | ||||
-rw-r--r-- | core/src/length.rs | 2 | ||||
-rw-r--r-- | core/src/lib.rs | 6 | ||||
-rw-r--r-- | core/src/mouse.rs | 8 | ||||
-rw-r--r-- | core/src/mouse/button.rs | 15 | ||||
-rw-r--r-- | core/src/mouse/event.rs | 56 | ||||
-rw-r--r-- | core/src/mouse/interaction.rs | 20 | ||||
-rw-r--r-- | core/src/point.rs | 30 | ||||
-rw-r--r-- | core/src/rectangle.rs | 92 | ||||
-rw-r--r-- | core/src/size.rs | 51 | ||||
-rw-r--r-- | core/src/vector.rs | 32 |
20 files changed, 700 insertions, 84 deletions
diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md deleted file mode 100644 index c0796e66..00000000 --- a/core/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] -### Added -- `Color::from_rgb8` to easily build a `Color` from its hexadecimal representation. [#90] - -[#90]: https://github.com/hecrj/iced/pull/90 - - -## [0.1.0] - 2019-11-25 -### Added -- First release! :tada: - -[Unreleased]: https://github.com/hecrj/iced/compare/core-0.1.0...HEAD -[0.1.0]: https://github.com/hecrj/iced/releases/tag/core-0.1.0 diff --git a/core/Cargo.toml b/core/Cargo.toml index 22bc7ceb..a859c868 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iced_core" -version = "0.1.0" +version = "0.3.0" authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] edition = "2018" description = "The essential concepts of Iced" @@ -8,3 +8,7 @@ license = "MIT" repository = "https://github.com/hecrj/iced" [dependencies] + +[dependencies.palette] +version = "0.5.0" +optional = true diff --git a/core/README.md b/core/README.md index 31630ea8..3ec053ac 100644 --- a/core/README.md +++ b/core/README.md @@ -8,7 +8,9 @@ This crate is meant to be a starting point for an Iced runtime. - +<p align="center"> + <img alt="The foundations" src="../docs/graphs/foundations.png" width="50%"> +</p> [documentation]: https://docs.rs/iced_core @@ -16,7 +18,7 @@ This crate is meant to be a starting point for an Iced runtime. Add `iced_core` as a dependency in your `Cargo.toml`: ```toml -iced_core = "0.1.0" +iced_core = "0.3" ``` __Iced moves fast and the `master` branch can contain breaking changes!__ If diff --git a/core/src/background.rs b/core/src/background.rs index e1a37ddc..cfb95867 100644 --- a/core/src/background.rs +++ b/core/src/background.rs @@ -13,3 +13,9 @@ impl From<Color> for Background { Background::Color(color) } } + +impl From<Color> for Option<Background> { + fn from(color: Color) -> Self { + Some(Background::from(color)) + } +} diff --git a/core/src/color.rs b/core/src/color.rs index db509b88..c66ee97c 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -1,10 +1,16 @@ +#[cfg(feature = "palette")] +use palette::rgb::{Srgb, Srgba}; + /// A color in the sRGB color space. -#[derive(Debug, Clone, Copy, PartialEq)] -#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Color { + /// Red component, 0.0 - 1.0 pub r: f32, + /// Green component, 0.0 - 1.0 pub g: f32, + /// Blue component, 0.0 - 1.0 pub b: f32, + /// Transparency, 0.0 - 1.0 pub a: f32, } @@ -33,23 +39,47 @@ impl Color { a: 0.0, }; - /// Creates a [`Color`] from its RGB components. + /// Creates a new [`Color`]. /// - /// [`Color`]: struct.Color.html + /// In debug mode, it will panic if the values are not in the correct + /// range: 0.0 - 1.0 + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color { + debug_assert!( + (0.0..=1.0).contains(&r), + "Red component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&g), + "Green component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&b), + "Blue component must be on [0, 1]" + ); + debug_assert!( + (0.0..=1.0).contains(&a), + "Alpha component must be on [0, 1]" + ); + + Color { r, g, b, a } + } + + /// Creates a [`Color`] from its RGB components. pub const fn from_rgb(r: f32, g: f32, b: f32) -> Color { - Color { r, g, b, a: 1.0 } + Color::from_rgba(r, g, b, 1.0f32) + } + + /// Creates a [`Color`] from its RGBA components. + pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Color { + Color { r, g, b, a } } /// Creates a [`Color`] from its RGB8 components. - /// - /// [`Color`]: struct.Color.html pub fn from_rgb8(r: u8, g: u8, b: u8) -> Color { Color::from_rgba8(r, g, b, 1.0) } /// Creates a [`Color`] from its RGB8 components and an alpha value. - /// - /// [`Color`]: struct.Color.html pub fn from_rgba8(r: u8, g: u8, b: u8, a: f32) -> Color { Color { r: f32::from(r) / 255.0, @@ -60,8 +90,6 @@ impl Color { } /// Converts the [`Color`] into its linear values. - /// - /// [`Color`]: struct.Color.html pub fn into_linear(self) -> [f32; 4] { // As described in: // https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation @@ -80,16 +108,101 @@ impl Color { self.a, ] } + + /// Inverts the [`Color`] in-place. + pub fn invert(&mut self) { + self.r = 1.0f32 - self.r; + self.b = 1.0f32 - self.g; + self.g = 1.0f32 - self.b; + } + + /// Returns the inverted [`Color`]. + pub fn inverse(self) -> Color { + Color::new(1.0f32 - self.r, 1.0f32 - self.g, 1.0f32 - self.b, self.a) + } } impl From<[f32; 3]> for Color { fn from([r, g, b]: [f32; 3]) -> Self { - Color { r, g, b, a: 1.0 } + Color::new(r, g, b, 1.0) } } impl From<[f32; 4]> for Color { fn from([r, g, b, a]: [f32; 4]) -> Self { - Color { r, g, b, a } + Color::new(r, g, b, a) + } +} + +#[cfg(feature = "palette")] +/// Converts from palette's `Srgba` type to a [`Color`]. +impl From<Srgba> for Color { + fn from(srgba: Srgba) -> Self { + Color::new(srgba.red, srgba.green, srgba.blue, srgba.alpha) + } +} + +#[cfg(feature = "palette")] +/// Converts from [`Color`] to palette's `Srgba` type. +impl From<Color> for Srgba { + fn from(c: Color) -> Self { + Srgba::new(c.r, c.g, c.b, c.a) + } +} + +#[cfg(feature = "palette")] +/// Converts from palette's `Srgb` type to a [`Color`]. +impl From<Srgb> for Color { + fn from(srgb: Srgb) -> Self { + Color::new(srgb.red, srgb.green, srgb.blue, 1.0) + } +} + +#[cfg(feature = "palette")] +/// Converts from [`Color`] to palette's `Srgb` type. +impl From<Color> for Srgb { + fn from(c: Color) -> Self { + Srgb::new(c.r, c.g, c.b) + } +} + +#[cfg(feature = "palette")] +#[cfg(test)] +mod tests { + use super::*; + use palette::Blend; + + #[test] + fn srgba_traits() { + let c = Color::from_rgb(0.5, 0.4, 0.3); + // Round-trip conversion to the palette:Srgba type + let s: Srgba = c.into(); + let r: Color = s.into(); + assert_eq!(c, r); + } + + #[test] + fn color_manipulation() { + let c1 = Color::from_rgb(0.5, 0.4, 0.3); + let c2 = Color::from_rgb(0.2, 0.5, 0.3); + + // Convert to linear color for manipulation + let l1 = Srgba::from(c1).into_linear(); + let l2 = Srgba::from(c2).into_linear(); + + // Take the lighter of each of the RGB components + let lighter = l1.lighten(l2); + + // Convert back to our Color + let r: Color = Srgba::from_linear(lighter).into(); + assert_eq!( + r, + Color { + r: 0.5, + g: 0.5, + b: 0.3, + a: 1.0 + } + ); } } diff --git a/core/src/font.rs b/core/src/font.rs index be49c825..3f9ad2b5 100644 --- a/core/src/font.rs +++ b/core/src/font.rs @@ -16,3 +16,9 @@ pub enum Font { bytes: &'static [u8], }, } + +impl Default for Font { + fn default() -> Font { + Font::Default + } +} diff --git a/core/src/keyboard.rs b/core/src/keyboard.rs new file mode 100644 index 00000000..61e017ad --- /dev/null +++ b/core/src/keyboard.rs @@ -0,0 +1,8 @@ +//! Reuse basic keyboard types. +mod event; +mod key_code; +mod modifiers; + +pub use event::Event; +pub use key_code::KeyCode; +pub use modifiers::Modifiers; diff --git a/core/src/keyboard/event.rs b/core/src/keyboard/event.rs new file mode 100644 index 00000000..0564c171 --- /dev/null +++ b/core/src/keyboard/event.rs @@ -0,0 +1,34 @@ +use super::{KeyCode, Modifiers}; + +/// A keyboard event. +/// +/// _**Note:** This type is largely incomplete! If you need to track +/// additional events, feel free to [open an issue] and share your use case!_ +/// +/// [open an issue]: https://github.com/hecrj/iced/issues +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Event { + /// A keyboard key was pressed. + KeyPressed { + /// The key identifier + key_code: KeyCode, + + /// The state of the modifier keys + modifiers: Modifiers, + }, + + /// A keyboard key was released. + KeyReleased { + /// The key identifier + key_code: KeyCode, + + /// The state of the modifier keys + modifiers: Modifiers, + }, + + /// A unicode character was received. + CharacterReceived(char), + + /// The keyboard modifiers have changed. + ModifiersChanged(Modifiers), +} diff --git a/core/src/keyboard/key_code.rs b/core/src/keyboard/key_code.rs new file mode 100644 index 00000000..74ead170 --- /dev/null +++ b/core/src/keyboard/key_code.rs @@ -0,0 +1,203 @@ +/// The symbolic name of a keyboard key. +/// +/// This is mostly the `KeyCode` type found in [`winit`]. +/// +/// [`winit`]: https://docs.rs/winit/0.20.0-alpha3/winit/ +#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)] +#[repr(u32)] +#[allow(missing_docs)] +pub enum KeyCode { + /// The '1' key over the letters. + Key1, + /// The '2' key over the letters. + Key2, + /// The '3' key over the letters. + Key3, + /// The '4' key over the letters. + Key4, + /// The '5' key over the letters. + Key5, + /// The '6' key over the letters. + Key6, + /// The '7' key over the letters. + Key7, + /// The '8' key over the letters. + Key8, + /// The '9' key over the letters. + Key9, + /// The '0' key over the 'O' and 'P' keys. + Key0, + + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + + /// The Escape key, next to F1. + Escape, + + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + + /// Print Screen/SysRq. + Snapshot, + /// Scroll Lock. + Scroll, + /// Pause/Break key, next to Scroll lock. + Pause, + + /// `Insert`, next to Backspace. + Insert, + Home, + Delete, + End, + PageDown, + PageUp, + + Left, + Up, + Right, + Down, + + /// The Backspace key, right over Enter. + Backspace, + /// The Enter key. + Enter, + /// The space bar. + Space, + + /// The "Compose" key on Linux. + Compose, + + Caret, + + Numlock, + Numpad0, + Numpad1, + Numpad2, + Numpad3, + Numpad4, + Numpad5, + Numpad6, + Numpad7, + Numpad8, + Numpad9, + NumpadAdd, + NumpadDivide, + NumpadDecimal, + NumpadComma, + NumpadEnter, + NumpadEquals, + NumpadMultiply, + NumpadSubtract, + + AbntC1, + AbntC2, + Apostrophe, + Apps, + Asterisk, + At, + Ax, + Backslash, + Calculator, + Capital, + Colon, + Comma, + Convert, + Equals, + Grave, + Kana, + Kanji, + LAlt, + LBracket, + LControl, + LShift, + LWin, + Mail, + MediaSelect, + MediaStop, + Minus, + Mute, + MyComputer, + NavigateForward, // also called "Next" + NavigateBackward, // also called "Prior" + NextTrack, + NoConvert, + OEM102, + Period, + PlayPause, + Plus, + Power, + PrevTrack, + RAlt, + RBracket, + RControl, + RShift, + RWin, + Semicolon, + Slash, + Sleep, + Stop, + Sysrq, + Tab, + Underline, + Unlabeled, + VolumeDown, + VolumeUp, + Wake, + WebBack, + WebFavorites, + WebForward, + WebHome, + WebRefresh, + WebSearch, + WebStop, + Yen, + Copy, + Paste, + Cut, +} diff --git a/core/src/keyboard/modifiers.rs b/core/src/keyboard/modifiers.rs new file mode 100644 index 00000000..d2a0500e --- /dev/null +++ b/core/src/keyboard/modifiers.rs @@ -0,0 +1,45 @@ +/// The current state of the keyboard modifiers. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct Modifiers { + /// Whether a shift key is pressed + pub shift: bool, + + /// Whether a control key is pressed + pub control: bool, + + /// Whether an alt key is pressed + pub alt: bool, + + /// Whether a logo key is pressed (e.g. windows key, command key...) + pub logo: bool, +} + +impl Modifiers { + /// Returns true if a "command key" is pressed in the [`Modifiers`]. + /// + /// The "command key" is the main modifier key used to issue commands in the + /// current platform. Specifically: + /// + /// - It is the `logo` or command key (⌘) on macOS + /// - It is the `control` key on other platforms + pub fn is_command_pressed(self) -> bool { + #[cfg(target_os = "macos")] + let is_pressed = self.logo; + + #[cfg(not(target_os = "macos"))] + let is_pressed = self.control; + + is_pressed + } + + /// Returns true if the current [`Modifiers`] have at least the same + /// keys pressed as the provided ones, and false otherwise. + pub fn matches(&self, modifiers: Self) -> bool { + let shift = !modifiers.shift || self.shift; + let control = !modifiers.control || self.control; + let alt = !modifiers.alt || self.alt; + let logo = !modifiers.logo || self.logo; + + shift && control && alt && logo + } +} diff --git a/core/src/length.rs b/core/src/length.rs index 06d8cf0a..186411a5 100644 --- a/core/src/length.rs +++ b/core/src/length.rs @@ -26,8 +26,6 @@ impl Length { /// The _fill factor_ is a relative unit describing how much of the /// remaining space should be filled when compared to other elements. It /// is only meant to be used by layout engines. - /// - /// [`Length`]: enum.Length.html pub fn fill_factor(&self) -> u16 { match self { Length::Fill => 1, diff --git a/core/src/lib.rs b/core/src/lib.rs index ea5e8b43..f2d21a5f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,11 +1,11 @@ //! The core library of [Iced]. //! -//!  -//! //! This library holds basic types that can be reused and re-exported in //! different runtime implementations. For instance, both [`iced_native`] and //! [`iced_web`] are built on top of `iced_core`. //! +//!  +//! //! [Iced]: https://github.com/hecrj/iced //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native //! [`iced_web`]: https://github.com/hecrj/iced/tree/master/web @@ -14,6 +14,8 @@ #![deny(unused_results)] #![forbid(unsafe_code)] #![forbid(rust_2018_idioms)] +pub mod keyboard; +pub mod mouse; mod align; mod background; diff --git a/core/src/mouse.rs b/core/src/mouse.rs new file mode 100644 index 00000000..25ce6ac3 --- /dev/null +++ b/core/src/mouse.rs @@ -0,0 +1,8 @@ +//! Reuse basic mouse types. +mod button; +mod event; +mod interaction; + +pub use button::Button; +pub use event::{Event, ScrollDelta}; +pub use interaction::Interaction; diff --git a/core/src/mouse/button.rs b/core/src/mouse/button.rs new file mode 100644 index 00000000..aeb8a55d --- /dev/null +++ b/core/src/mouse/button.rs @@ -0,0 +1,15 @@ +/// The button of a mouse. +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub enum Button { + /// The left mouse button. + Left, + + /// The right mouse button. + Right, + + /// The middle (wheel) button. + Middle, + + /// Some other button. + Other(u8), +} diff --git a/core/src/mouse/event.rs b/core/src/mouse/event.rs new file mode 100644 index 00000000..321b8399 --- /dev/null +++ b/core/src/mouse/event.rs @@ -0,0 +1,56 @@ +use crate::Point; + +use super::Button; + +/// A mouse event. +/// +/// _**Note:** This type is largely incomplete! If you need to track +/// additional events, feel free to [open an issue] and share your use case!_ +/// +/// [open an issue]: https://github.com/hecrj/iced/issues +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Event { + /// The mouse cursor entered the window. + CursorEntered, + + /// The mouse cursor left the window. + CursorLeft, + + /// The mouse cursor was moved + CursorMoved { + /// The new position of the mouse cursor + position: Point, + }, + + /// A mouse button was pressed. + ButtonPressed(Button), + + /// A mouse button was released. + ButtonReleased(Button), + + /// The mouse wheel was scrolled. + WheelScrolled { + /// The scroll movement. + delta: ScrollDelta, + }, +} + +/// A scroll movement. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ScrollDelta { + /// A line-based scroll movement + Lines { + /// The number of horizontal lines scrolled + x: f32, + + /// The number of vertical lines scrolled + y: f32, + }, + /// A pixel-based scroll movement + Pixels { + /// The number of horizontal pixels scrolled + x: f32, + /// The number of vertical pixels scrolled + y: f32, + }, +} diff --git a/core/src/mouse/interaction.rs b/core/src/mouse/interaction.rs new file mode 100644 index 00000000..664147a7 --- /dev/null +++ b/core/src/mouse/interaction.rs @@ -0,0 +1,20 @@ +/// The interaction of a mouse cursor. +#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)] +#[allow(missing_docs)] +pub enum Interaction { + Idle, + Pointer, + Grab, + Text, + Crosshair, + Working, + Grabbing, + ResizingHorizontally, + ResizingVertically, +} + +impl Default for Interaction { + fn default() -> Interaction { + Interaction::Idle + } +} diff --git a/core/src/point.rs b/core/src/point.rs index b55f5099..9bf7726b 100644 --- a/core/src/point.rs +++ b/core/src/point.rs @@ -1,7 +1,7 @@ use crate::Vector; /// A 2D point. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Point { /// The X coordinate. pub x: f32, @@ -11,17 +11,21 @@ pub struct Point { } impl Point { - /// The origin (i.e. a [`Point`] with both X=0 and Y=0). - /// - /// [`Point`]: struct.Point.html + /// The origin (i.e. a [`Point`] at (0, 0)). pub const ORIGIN: Point = Point::new(0.0, 0.0); /// Creates a new [`Point`] with the given coordinates. - /// - /// [`Point`]: struct.Point.html pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } + + /// Computes the distance to another [`Point`]. + pub fn distance(&self, to: Point) -> f32 { + let a = self.x - to.x; + let b = self.y - to.y; + + a.hypot(b) + } } impl From<[f32; 2]> for Point { @@ -36,6 +40,12 @@ impl From<[u16; 2]> for Point { } } +impl From<Point> for [f32; 2] { + fn from(point: Point) -> [f32; 2] { + [point.x, point.y] + } +} + impl std::ops::Add<Vector> for Point { type Output = Self; @@ -57,3 +67,11 @@ impl std::ops::Sub<Vector> for Point { } } } + +impl std::ops::Sub<Point> for Point { + type Output = Vector; + + fn sub(self, point: Point) -> Vector { + Vector::new(self.x - point.x, self.y - point.y) + } +} diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index 7ed3d2df..0a7f5fe2 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -1,4 +1,4 @@ -use crate::Point; +use crate::{Point, Size, Vector}; /// A rectangle. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] @@ -17,10 +17,56 @@ pub struct Rectangle<T = f32> { } impl Rectangle<f32> { + /// Creates a new [`Rectangle`] with its top-left corner in the given + /// [`Point`] and with the provided [`Size`]. + pub fn new(top_left: Point, size: Size) -> Self { + Self { + x: top_left.x, + y: top_left.y, + width: size.width, + height: size.height, + } + } + + /// Creates a new [`Rectangle`] with its top-left corner at the origin + /// and with the provided [`Size`]. + pub fn with_size(size: Size) -> Self { + Self { + x: 0.0, + y: 0.0, + width: size.width, + height: size.height, + } + } + + /// Returns the [`Point`] at the center of the [`Rectangle`]. + pub fn center(&self) -> Point { + Point::new(self.center_x(), self.center_y()) + } + + /// Returns the X coordinate of the [`Point`] at the center of the + /// [`Rectangle`]. + pub fn center_x(&self) -> f32 { + self.x + self.width / 2.0 + } + + /// Returns the Y coordinate of the [`Point`] at the center of the + /// [`Rectangle`]. + pub fn center_y(&self) -> f32 { + self.y + self.height / 2.0 + } + + /// Returns the position of the top left corner of the [`Rectangle`]. + pub fn position(&self) -> Point { + Point::new(self.x, self.y) + } + + /// Returns the [`Size`] of the [`Rectangle`]. + pub fn size(&self) -> Size { + Size::new(self.width, self.height) + } + /// Returns true if the given [`Point`] is contained in the [`Rectangle`]. - /// - /// [`Point`]: struct.Point.html - /// [`Rectangle`]: struct.Rectangle.html pub fn contains(&self, point: Point) -> bool { self.x <= point.x && point.x <= self.x + self.width @@ -29,8 +75,6 @@ impl Rectangle<f32> { } /// Computes the intersection with the given [`Rectangle`]. - /// - /// [`Rectangle`]: struct.Rectangle.html pub fn intersection( &self, other: &Rectangle<f32>, @@ -55,17 +99,27 @@ impl Rectangle<f32> { None } } + + /// Snaps the [`Rectangle`] to __unsigned__ integer coordinates. + pub fn snap(self) -> Rectangle<u32> { + Rectangle { + x: self.x as u32, + y: self.y as u32, + width: self.width.ceil() as u32, + height: self.height.ceil() as u32, + } + } } -impl std::ops::Mul<f32> for Rectangle<u32> { +impl std::ops::Mul<f32> for Rectangle<f32> { type Output = Self; fn mul(self, scale: f32) -> Self { Self { - x: (self.x as f32 * scale).round() as u32, - y: (self.y as f32 * scale).round() as u32, - width: (self.width as f32 * scale).round() as u32, - height: (self.height as f32 * scale).round() as u32, + x: self.x as f32 * scale, + y: self.y as f32 * scale, + width: self.width * scale, + height: self.height * scale, } } } @@ -81,13 +135,17 @@ impl From<Rectangle<u32>> for Rectangle<f32> { } } -impl From<Rectangle<f32>> for Rectangle<u32> { - fn from(rectangle: Rectangle<f32>) -> Rectangle<u32> { +impl<T> std::ops::Add<Vector<T>> for Rectangle<T> +where + T: std::ops::Add<Output = T>, +{ + type Output = Rectangle<T>; + + fn add(self, translation: Vector<T>) -> Self { Rectangle { - x: rectangle.x as u32, - y: rectangle.y as u32, - width: rectangle.width.ceil() as u32, - height: rectangle.height.ceil() as u32, + x: self.x + translation.x, + y: self.y + translation.y, + ..self } } } diff --git a/core/src/size.rs b/core/src/size.rs index 389b3247..9ea9e686 100644 --- a/core/src/size.rs +++ b/core/src/size.rs @@ -1,35 +1,33 @@ +use crate::Vector; use std::f32; /// An amount of space in 2 dimensions. #[derive(Debug, Clone, Copy, PartialEq)] -pub struct Size { +pub struct Size<T = f32> { /// The width. - pub width: f32, + pub width: T, /// The height. - pub height: f32, + pub height: T, +} + +impl<T> Size<T> { + /// Creates a new [`Size`] with the given width and height. + pub const fn new(width: T, height: T) -> Self { + Size { width, height } + } } impl Size { /// A [`Size`] with zero width and height. - /// - /// [`Size`]: struct.Size.html pub const ZERO: Size = Size::new(0., 0.); + /// A [`Size`] with a width and height of 1 unit. + pub const UNIT: Size = Size::new(1., 1.); + /// A [`Size`] with infinite width and height. - /// - /// [`Size`]: struct.Size.html pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY); - /// A [`Size`] of infinite width and height. - /// - /// [`Size`]: struct.Size.html - pub const fn new(width: f32, height: f32) -> Self { - Size { width, height } - } - /// Increments the [`Size`] to account for the given padding. - /// - /// [`Size`]: struct.Size.html pub fn pad(&self, padding: f32) -> Self { Size { width: self.width + padding * 2.0, @@ -49,3 +47,24 @@ impl From<[u16; 2]> for Size { Size::new(width.into(), height.into()) } } + +impl From<Vector<f32>> for Size { + fn from(vector: Vector<f32>) -> Self { + Size { + width: vector.x, + height: vector.y, + } + } +} + +impl From<Size> for [f32; 2] { + fn from(size: Size) -> [f32; 2] { + [size.width, size.height] + } +} + +impl From<Size> for Vector<f32> { + fn from(size: Size) -> Self { + Vector::new(size.width, size.height) + } +} diff --git a/core/src/vector.rs b/core/src/vector.rs index a75053a0..92bb7648 100644 --- a/core/src/vector.rs +++ b/core/src/vector.rs @@ -2,20 +2,14 @@ #[derive(Debug, Clone, Copy, PartialEq)] pub struct Vector<T = f32> { /// The X component of the [`Vector`] - /// - /// [`Vector`]: struct.Vector.html pub x: T, /// The Y component of the [`Vector`] - /// - /// [`Vector`]: struct.Vector.html pub y: T, } impl<T> Vector<T> { /// Creates a new [`Vector`] with the given components. - /// - /// [`Vector`]: struct.Vector.html pub const fn new(x: T, y: T) -> Self { Self { x, y } } @@ -43,6 +37,17 @@ where } } +impl<T> std::ops::Mul<T> for Vector<T> +where + T: std::ops::Mul<Output = T> + Copy, +{ + type Output = Self; + + fn mul(self, scale: T) -> Self { + Self::new(self.x * scale, self.y * scale) + } +} + impl<T> Default for Vector<T> where T: Default, @@ -54,3 +59,18 @@ where } } } + +impl<T> From<[T; 2]> for Vector<T> { + fn from([x, y]: [T; 2]) -> Self { + Self::new(x, y) + } +} + +impl<T> From<Vector<T>> for [T; 2] +where + T: Copy, +{ + fn from(other: Vector<T>) -> Self { + [other.x, other.y] + } +} |