summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorLibravatar Billy Messenger <BillyDM@tutamail.com>2021-07-22 12:37:39 -0500
committerLibravatar Billy Messenger <BillyDM@tutamail.com>2021-07-22 12:37:39 -0500
commite822f654e44d2d7375b7fda966bb772055f377d4 (patch)
tree8707561f1bb09c9e58cc9d9884bfb16d956f9f65 /core
parent1c06920158e1a47977b2762bf8b34e56fd1a935a (diff)
parentdc0b96ce407283f2ffd9add5ad339f89097555d3 (diff)
downloadiced-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.toml3
-rw-r--r--core/README.md2
-rw-r--r--core/src/keyboard.rs2
-rw-r--r--core/src/keyboard/hotkey.rs18
-rw-r--r--core/src/keyboard/modifiers.rs76
-rw-r--r--core/src/lib.rs4
-rw-r--r--core/src/menu.rs145
-rw-r--r--core/src/mouse/event.rs9
-rw-r--r--core/src/padding.rs107
-rw-r--r--core/src/rectangle.rs4
-rw-r--r--core/src/size.rs8
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,
}
}
}