diff options
author | 2021-07-22 12:37:39 -0500 | |
---|---|---|
committer | 2021-07-22 12:37:39 -0500 | |
commit | e822f654e44d2d7375b7fda966bb772055f377d4 (patch) | |
tree | 8707561f1bb09c9e58cc9d9884bfb16d956f9f65 /core | |
parent | 1c06920158e1a47977b2762bf8b34e56fd1a935a (diff) | |
parent | dc0b96ce407283f2ffd9add5ad339f89097555d3 (diff) | |
download | iced-e822f654e44d2d7375b7fda966bb772055f377d4.tar.gz iced-e822f654e44d2d7375b7fda966bb772055f377d4.tar.bz2 iced-e822f654e44d2d7375b7fda966bb772055f377d4.zip |
Merge branch 'master' of https://github.com/hecrj/iced into wgpu_outdatedframe
Diffstat (limited to 'core')
-rw-r--r-- | core/Cargo.toml | 3 | ||||
-rw-r--r-- | core/README.md | 2 | ||||
-rw-r--r-- | core/src/keyboard.rs | 2 | ||||
-rw-r--r-- | core/src/keyboard/hotkey.rs | 18 | ||||
-rw-r--r-- | core/src/keyboard/modifiers.rs | 76 | ||||
-rw-r--r-- | core/src/lib.rs | 4 | ||||
-rw-r--r-- | core/src/menu.rs | 145 | ||||
-rw-r--r-- | core/src/mouse/event.rs | 9 | ||||
-rw-r--r-- | core/src/padding.rs | 107 | ||||
-rw-r--r-- | core/src/rectangle.rs | 4 | ||||
-rw-r--r-- | core/src/size.rs | 8 |
11 files changed, 338 insertions, 40 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml index a859c868..54d927af 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iced_core" -version = "0.3.0" +version = "0.4.0" authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] edition = "2018" description = "The essential concepts of Iced" @@ -8,6 +8,7 @@ license = "MIT" repository = "https://github.com/hecrj/iced" [dependencies] +bitflags = "1.2" [dependencies.palette] version = "0.5.0" diff --git a/core/README.md b/core/README.md index 3ec053ac..86d631d2 100644 --- a/core/README.md +++ b/core/README.md @@ -18,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.3" +iced_core = "0.4" ``` __Iced moves fast and the `master` branch can contain breaking changes!__ If diff --git a/core/src/keyboard.rs b/core/src/keyboard.rs index 61e017ad..cb64701a 100644 --- a/core/src/keyboard.rs +++ b/core/src/keyboard.rs @@ -1,8 +1,10 @@ //! Reuse basic keyboard types. mod event; +mod hotkey; mod key_code; mod modifiers; pub use event::Event; +pub use hotkey::Hotkey; pub use key_code::KeyCode; pub use modifiers::Modifiers; diff --git a/core/src/keyboard/hotkey.rs b/core/src/keyboard/hotkey.rs new file mode 100644 index 00000000..310ef286 --- /dev/null +++ b/core/src/keyboard/hotkey.rs @@ -0,0 +1,18 @@ +use crate::keyboard::{KeyCode, Modifiers}; + +/// Representation of a hotkey, consists on the combination of a [`KeyCode`] and [`Modifiers`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Hotkey { + /// The key that represents this hotkey. + pub key: KeyCode, + + /// The list of modifiers that represents this hotkey. + pub modifiers: Modifiers, +} + +impl Hotkey { + /// Creates a new [`Hotkey`] with the given [`Modifiers`] and [`KeyCode`]. + pub fn new(modifiers: Modifiers, key: KeyCode) -> Self { + Self { modifiers, key } + } +} diff --git a/core/src/keyboard/modifiers.rs b/core/src/keyboard/modifiers.rs index d2a0500e..383b9370 100644 --- a/core/src/keyboard/modifiers.rs +++ b/core/src/keyboard/modifiers.rs @@ -1,20 +1,53 @@ -/// 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, +use bitflags::bitflags; - /// 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, +bitflags! { + /// The current state of the keyboard modifiers. + #[derive(Default)] + pub struct Modifiers: u32{ + /// The "shift" key. + const SHIFT = 0b100 << 0; + // const LSHIFT = 0b010 << 0; + // const RSHIFT = 0b001 << 0; + // + /// The "control" key. + const CTRL = 0b100 << 3; + // const LCTRL = 0b010 << 3; + // const RCTRL = 0b001 << 3; + // + /// The "alt" key. + const ALT = 0b100 << 6; + // const LALT = 0b010 << 6; + // const RALT = 0b001 << 6; + // + /// The "windows" key on Windows, "command" key on Mac, and + /// "super" key on Linux. + const LOGO = 0b100 << 9; + // const LLOGO = 0b010 << 9; + // const RLOGO = 0b001 << 9; + } } impl Modifiers { + /// Returns true if the [`SHIFT`] key is pressed in the [`Modifiers`]. + pub fn shift(self) -> bool { + self.contains(Self::SHIFT) + } + + /// Returns true if the [`CTRL`] key is pressed in the [`Modifiers`]. + pub fn control(self) -> bool { + self.contains(Self::CTRL) + } + + /// Returns true if the [`ALT`] key is pressed in the [`Modifiers`]. + pub fn alt(self) -> bool { + self.contains(Self::ALT) + } + + /// Returns true if the [`LOGO`] key is pressed in the [`Modifiers`]. + pub fn logo(self) -> bool { + self.contains(Self::LOGO) + } + /// 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 @@ -22,24 +55,13 @@ impl Modifiers { /// /// - It is the `logo` or command key (⌘) on macOS /// - It is the `control` key on other platforms - pub fn is_command_pressed(self) -> bool { + pub fn command(self) -> bool { #[cfg(target_os = "macos")] - let is_pressed = self.logo; + let is_pressed = self.logo(); #[cfg(not(target_os = "macos"))] - let is_pressed = self.control; + 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/lib.rs b/core/src/lib.rs index f2d21a5f..c4288158 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -15,6 +15,7 @@ #![forbid(unsafe_code)] #![forbid(rust_2018_idioms)] pub mod keyboard; +pub mod menu; pub mod mouse; mod align; @@ -22,6 +23,7 @@ mod background; mod color; mod font; mod length; +mod padding; mod point; mod rectangle; mod size; @@ -32,6 +34,8 @@ pub use background::Background; pub use color::Color; pub use font::Font; pub use length::Length; +pub use menu::Menu; +pub use padding::Padding; pub use point::Point; pub use rectangle::Rectangle; pub use size::Size; diff --git a/core/src/menu.rs b/core/src/menu.rs new file mode 100644 index 00000000..8a679085 --- /dev/null +++ b/core/src/menu.rs @@ -0,0 +1,145 @@ +//! Build menus for your application. +use crate::keyboard::Hotkey; + +/// Menu representation. +/// +/// This can be used by `shell` implementations to create a menu. +#[derive(Debug, Clone)] +pub struct Menu<Message> { + entries: Vec<Entry<Message>>, +} + +impl<Message> PartialEq for Menu<Message> { + fn eq(&self, other: &Self) -> bool { + self.entries == other.entries + } +} + +impl<Message> Menu<Message> { + /// Creates an empty [`Menu`]. + pub fn new() -> Self { + Self::with_entries(Vec::new()) + } + + /// Creates a new [`Menu`] with the given entries. + pub fn with_entries(entries: Vec<Entry<Message>>) -> Self { + Self { entries } + } + + /// Returns a [`MenuEntry`] iterator. + pub fn iter(&self) -> impl Iterator<Item = &Entry<Message>> { + self.entries.iter() + } + + /// Adds an [`Entry`] to the [`Menu`]. + pub fn push(mut self, entry: Entry<Message>) -> Self { + self.entries.push(entry); + self + } + + /// Maps the `Message` of the [`Menu`] using the provided function. + /// + /// This is useful to compose menus and split them into different + /// abstraction levels. + pub fn map<B>(self, f: impl Fn(Message) -> B + Copy) -> Menu<B> { + // TODO: Use a boxed trait to avoid reallocation of entries + Menu { + entries: self + .entries + .into_iter() + .map(|entry| entry.map(f)) + .collect(), + } + } +} + +/// Represents one of the possible entries used to build a [`Menu`]. +#[derive(Debug, Clone)] +pub enum Entry<Message> { + /// Item for a [`Menu`] + Item { + /// The title of the item + title: String, + /// The [`Hotkey`] to activate the item, if any + hotkey: Option<Hotkey>, + /// The message generated when the item is activated + on_activation: Message, + }, + /// Dropdown for a [`Menu`] + Dropdown { + /// Title of the dropdown + title: String, + /// The submenu of the dropdown + submenu: Menu<Message>, + }, + /// Separator for a [`Menu`] + Separator, +} + +impl<Message> Entry<Message> { + /// Creates an [`Entry::Item`]. + pub fn item<S: Into<String>>( + title: S, + hotkey: impl Into<Option<Hotkey>>, + on_activation: Message, + ) -> Self { + let title = title.into(); + let hotkey = hotkey.into(); + + Self::Item { + title, + hotkey, + on_activation, + } + } + + /// Creates an [`Entry::Dropdown`]. + pub fn dropdown<S: Into<String>>(title: S, submenu: Menu<Message>) -> Self { + let title = title.into(); + + Self::Dropdown { title, submenu } + } + + fn map<B>(self, f: impl Fn(Message) -> B + Copy) -> Entry<B> { + match self { + Self::Item { + title, + hotkey, + on_activation, + } => Entry::Item { + title, + hotkey, + on_activation: f(on_activation), + }, + Self::Dropdown { title, submenu } => Entry::Dropdown { + title, + submenu: submenu.map(f), + }, + Self::Separator => Entry::Separator, + } + } +} + +impl<Message> PartialEq for Entry<Message> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Entry::Item { title, hotkey, .. }, + Entry::Item { + title: other_title, + hotkey: other_hotkey, + .. + }, + ) => title == other_title && hotkey == other_hotkey, + ( + Entry::Dropdown { title, submenu }, + Entry::Dropdown { + title: other_title, + submenu: other_submenu, + }, + ) => title == other_title && submenu == other_submenu, + (Entry::Separator, Entry::Separator) => true, + _ => false, + } + } +} diff --git a/core/src/mouse/event.rs b/core/src/mouse/event.rs index 2f07b207..321b8399 100644 --- a/core/src/mouse/event.rs +++ b/core/src/mouse/event.rs @@ -1,3 +1,5 @@ +use crate::Point; + use super::Button; /// A mouse event. @@ -16,11 +18,8 @@ pub enum Event { /// The mouse cursor was moved CursorMoved { - /// The X coordinate of the mouse position - x: f32, - - /// The Y coordinate of the mouse position - y: f32, + /// The new position of the mouse cursor + position: Point, }, /// A mouse button was pressed. diff --git a/core/src/padding.rs b/core/src/padding.rs new file mode 100644 index 00000000..22467d6b --- /dev/null +++ b/core/src/padding.rs @@ -0,0 +1,107 @@ +/// An amount of space to pad for each side of a box +/// +/// You can leverage the `From` trait to build [`Padding`] conveniently: +/// +/// ``` +/// # use iced_core::Padding; +/// # +/// let padding = Padding::from(20); // 20px on all sides +/// let padding = Padding::from([10, 20]); // top/bottom, left/right +/// let padding = Padding::from([5, 10, 15, 20]); // top, right, bottom, left +/// ``` +/// +/// Normally, the `padding` method of a widget will ask for an `Into<Padding>`, +/// so you can easily write: +/// +/// ``` +/// # use iced_core::Padding; +/// # +/// # struct Widget; +/// # +/// impl Widget { +/// # pub fn new() -> Self { Self } +/// # +/// pub fn padding(mut self, padding: impl Into<Padding>) -> Self { +/// // ... +/// self +/// } +/// } +/// +/// let widget = Widget::new().padding(20); // 20px on all sides +/// let widget = Widget::new().padding([10, 20]); // top/bottom, left/right +/// let widget = Widget::new().padding([5, 10, 15, 20]); // top, right, bottom, left +/// ``` +#[derive(Debug, Hash, Copy, Clone)] +pub struct Padding { + /// Top padding + pub top: u16, + /// Right padding + pub right: u16, + /// Bottom padding + pub bottom: u16, + /// Left padding + pub left: u16, +} + +impl Padding { + /// Padding of zero + pub const ZERO: Padding = Padding { + top: 0, + right: 0, + bottom: 0, + left: 0, + }; + + /// Create a Padding that is equal on all sides + pub const fn new(padding: u16) -> Padding { + Padding { + top: padding, + right: padding, + bottom: padding, + left: padding, + } + } + + /// Returns the total amount of vertical [`Padding`]. + pub fn vertical(self) -> u16 { + self.top + self.bottom + } + + /// Returns the total amount of horizontal [`Padding`]. + pub fn horizontal(self) -> u16 { + self.left + self.right + } +} + +impl std::convert::From<u16> for Padding { + fn from(p: u16) -> Self { + Padding { + top: p, + right: p, + bottom: p, + left: p, + } + } +} + +impl std::convert::From<[u16; 2]> for Padding { + fn from(p: [u16; 2]) -> Self { + Padding { + top: p[0], + right: p[1], + bottom: p[0], + left: p[1], + } + } +} + +impl std::convert::From<[u16; 4]> for Padding { + fn from(p: [u16; 4]) -> Self { + Padding { + top: p[0], + right: p[1], + bottom: p[2], + left: p[3], + } + } +} diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index 0a7f5fe2..4e082051 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -105,8 +105,8 @@ impl Rectangle<f32> { Rectangle { x: self.x as u32, y: self.y as u32, - width: self.width.ceil() as u32, - height: self.height.ceil() as u32, + width: self.width as u32, + height: self.height as u32, } } } diff --git a/core/src/size.rs b/core/src/size.rs index 9ea9e686..6745c6c8 100644 --- a/core/src/size.rs +++ b/core/src/size.rs @@ -1,4 +1,4 @@ -use crate::Vector; +use crate::{Padding, Vector}; use std::f32; /// An amount of space in 2 dimensions. @@ -28,10 +28,10 @@ impl Size { pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY); /// Increments the [`Size`] to account for the given padding. - pub fn pad(&self, padding: f32) -> Self { + pub fn pad(&self, padding: Padding) -> Self { Size { - width: self.width + padding * 2.0, - height: self.height + padding * 2.0, + width: self.width + padding.horizontal() as f32, + height: self.height + padding.vertical() as f32, } } } |