summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/src/color.rs127
-rw-r--r--core/src/keyboard/event.rs7
-rw-r--r--core/src/keyboard/key.rs533
-rw-r--r--core/src/mouse/click.rs13
-rw-r--r--core/src/mouse/interaction.rs7
-rw-r--r--core/src/renderer/null.rs1
-rw-r--r--core/src/text.rs19
-rw-r--r--core/src/text/editor.rs3
-rw-r--r--core/src/text/paragraph.rs1
-rw-r--r--core/src/vector.rs11
-rw-r--r--core/src/widget/operation.rs46
-rw-r--r--core/src/widget/operation/scrollable.rs45
-rw-r--r--core/src/widget/text.rs15
-rw-r--r--core/src/window/settings/linux.rs6
-rw-r--r--core/src/window/settings/windows.rs7
15 files changed, 816 insertions, 25 deletions
diff --git a/core/src/color.rs b/core/src/color.rs
index 4e79defb..46fe9ecd 100644
--- a/core/src/color.rs
+++ b/core/src/color.rs
@@ -108,6 +108,53 @@ impl Color {
}
}
+ /// Parses a [`Color`] from a hex string.
+ ///
+ /// Supported formats are `#rrggbb`, `#rrggbbaa`, `#rgb`, and `#rgba`.
+ /// The starting "#" is optional. Both uppercase and lowercase are supported.
+ ///
+ /// If you have a static color string, using the [`color!`] macro should be preferred
+ /// since it leverages hexadecimal literal notation and arithmetic directly.
+ ///
+ /// [`color!`]: crate::color!
+ pub fn parse(s: &str) -> Option<Color> {
+ let hex = s.strip_prefix('#').unwrap_or(s);
+
+ let parse_channel = |from: usize, to: usize| {
+ let num =
+ usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0;
+
+ // If we only got half a byte (one letter), expand it into a full byte (two letters)
+ Some(if from == to { num + num * 16.0 } else { num })
+ };
+
+ Some(match hex.len() {
+ 3 => Color::from_rgb(
+ parse_channel(0, 0)?,
+ parse_channel(1, 1)?,
+ parse_channel(2, 2)?,
+ ),
+ 4 => Color::from_rgba(
+ parse_channel(0, 0)?,
+ parse_channel(1, 1)?,
+ parse_channel(2, 2)?,
+ parse_channel(3, 3)?,
+ ),
+ 6 => Color::from_rgb(
+ parse_channel(0, 1)?,
+ parse_channel(2, 3)?,
+ parse_channel(4, 5)?,
+ ),
+ 8 => Color::from_rgba(
+ parse_channel(0, 1)?,
+ parse_channel(2, 3)?,
+ parse_channel(4, 5)?,
+ parse_channel(6, 7)?,
+ ),
+ _ => None?,
+ })
+ }
+
/// Converts the [`Color`] into its RGBA8 equivalent.
#[must_use]
pub fn into_rgba8(self) -> [u8; 4] {
@@ -178,34 +225,65 @@ impl From<[f32; 4]> for Color {
///
/// ```
/// # use iced_core::{Color, color};
-/// assert_eq!(color!(0, 0, 0), Color::from_rgb(0., 0., 0.));
-/// assert_eq!(color!(0, 0, 0, 0.), Color::from_rgba(0., 0., 0., 0.));
-/// assert_eq!(color!(0xffffff), Color::from_rgb(1., 1., 1.));
-/// assert_eq!(color!(0xffffff, 0.), Color::from_rgba(1., 1., 1., 0.));
+/// assert_eq!(color!(0, 0, 0), Color::BLACK);
+/// assert_eq!(color!(0, 0, 0, 0.0), Color::TRANSPARENT);
+/// assert_eq!(color!(0xffffff), Color::from_rgb(1.0, 1.0, 1.0));
+/// assert_eq!(color!(0xffffff, 0.), Color::from_rgba(1.0, 1.0, 1.0, 0.0));
+/// assert_eq!(color!(0x123), Color::from_rgba8(0x11, 0x22, 0x33, 1.0));
+/// assert_eq!(color!(0x123), color!(0x112233));
/// ```
#[macro_export]
macro_rules! color {
($r:expr, $g:expr, $b:expr) => {
color!($r, $g, $b, 1.0)
};
- ($r:expr, $g:expr, $b:expr, $a:expr) => {
- $crate::Color {
- r: $r as f32 / 255.0,
- g: $g as f32 / 255.0,
- b: $b as f32 / 255.0,
- a: $a,
+ ($r:expr, $g:expr, $b:expr, $a:expr) => {{
+ let r = $r as f32 / 255.0;
+ let g = $g as f32 / 255.0;
+ let b = $b as f32 / 255.0;
+
+ #[allow(clippy::manual_range_contains)]
+ {
+ debug_assert!(
+ r >= 0.0 && r <= 1.0,
+ "R channel must be in [0, 255] range."
+ );
+ debug_assert!(
+ g >= 0.0 && g <= 1.0,
+ "G channel must be in [0, 255] range."
+ );
+ debug_assert!(
+ b >= 0.0 && b <= 1.0,
+ "B channel must be in [0, 255] range."
+ );
}
- };
+
+ $crate::Color { r, g, b, a: $a }
+ }};
($hex:expr) => {{
color!($hex, 1.0)
}};
($hex:expr, $a:expr) => {{
let hex = $hex as u32;
- let r = (hex & 0xff0000) >> 16;
- let g = (hex & 0xff00) >> 8;
- let b = (hex & 0xff);
- color!(r, g, b, $a)
+ if hex <= 0xfff {
+ let r = (hex & 0xf00) >> 8;
+ let g = (hex & 0x0f0) >> 4;
+ let b = (hex & 0x00f);
+
+ color!((r << 4 | r), (g << 4 | g), (b << 4 | b), $a)
+ } else {
+ debug_assert!(
+ hex <= 0xffffff,
+ "color! value must not exceed 0xffffff"
+ );
+
+ let r = (hex & 0xff0000) >> 16;
+ let g = (hex & 0xff00) >> 8;
+ let b = (hex & 0xff);
+
+ color!(r, g, b, $a)
+ }
}};
}
@@ -273,4 +351,23 @@ mod tests {
assert_relative_eq!(result.b, 0.3);
assert_relative_eq!(result.a, 1.0);
}
+
+ #[test]
+ fn parse() {
+ let tests = [
+ ("#ff0000", [255, 0, 0, 255]),
+ ("00ff0080", [0, 255, 0, 128]),
+ ("#F80", [255, 136, 0, 255]),
+ ("#00f1", [0, 0, 255, 17]),
+ ];
+
+ for (arg, expected) in tests {
+ assert_eq!(
+ Color::parse(arg).expect("color must parse").into_rgba8(),
+ expected
+ );
+ }
+
+ assert!(Color::parse("invalid").is_none());
+ }
}
diff --git a/core/src/keyboard/event.rs b/core/src/keyboard/event.rs
index 1eb42334..26c45717 100644
--- a/core/src/keyboard/event.rs
+++ b/core/src/keyboard/event.rs
@@ -1,3 +1,4 @@
+use crate::keyboard::key;
use crate::keyboard::{Key, Location, Modifiers};
use crate::SmolStr;
@@ -14,6 +15,12 @@ pub enum Event {
/// The key pressed.
key: Key,
+ /// The key pressed with all keyboard modifiers applied, except Ctrl.
+ modified_key: Key,
+
+ /// The physical key pressed.
+ physical_key: key::Physical,
+
/// The location of the key.
location: Location,
diff --git a/core/src/keyboard/key.rs b/core/src/keyboard/key.rs
index dbde5196..479d999b 100644
--- a/core/src/keyboard/key.rs
+++ b/core/src/keyboard/key.rs
@@ -742,3 +742,536 @@ pub enum Named {
/// General-purpose function key.
F35,
}
+
+/// Code representing the location of a physical key.
+///
+/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few
+/// exceptions:
+/// - The keys that the specification calls "MetaLeft" and "MetaRight" are named "SuperLeft" and
+/// "SuperRight" here.
+/// - The key that the specification calls "Super" is reported as `Unidentified` here.
+///
+/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+pub enum Code {
+ /// <kbd>`</kbd> on a US keyboard. This is also called a backtick or grave.
+ /// This is the <kbd>半角</kbd>/<kbd>全角</kbd>/<kbd>漢字</kbd>
+ /// (hankaku/zenkaku/kanji) key on Japanese keyboards
+ Backquote,
+ /// Used for both the US <kbd>\\</kbd> (on the 101-key layout) and also for the key
+ /// located between the <kbd>"</kbd> and <kbd>Enter</kbd> keys on row C of the 102-,
+ /// 104- and 106-key layouts.
+ /// Labeled <kbd>#</kbd> on a UK (102) keyboard.
+ Backslash,
+ /// <kbd>[</kbd> on a US keyboard.
+ BracketLeft,
+ /// <kbd>]</kbd> on a US keyboard.
+ BracketRight,
+ /// <kbd>,</kbd> on a US keyboard.
+ Comma,
+ /// <kbd>0</kbd> on a US keyboard.
+ Digit0,
+ /// <kbd>1</kbd> on a US keyboard.
+ Digit1,
+ /// <kbd>2</kbd> on a US keyboard.
+ Digit2,
+ /// <kbd>3</kbd> on a US keyboard.
+ Digit3,
+ /// <kbd>4</kbd> on a US keyboard.
+ Digit4,
+ /// <kbd>5</kbd> on a US keyboard.
+ Digit5,
+ /// <kbd>6</kbd> on a US keyboard.
+ Digit6,
+ /// <kbd>7</kbd> on a US keyboard.
+ Digit7,
+ /// <kbd>8</kbd> on a US keyboard.
+ Digit8,
+ /// <kbd>9</kbd> on a US keyboard.
+ Digit9,
+ /// <kbd>=</kbd> on a US keyboard.
+ Equal,
+ /// Located between the left <kbd>Shift</kbd> and <kbd>Z</kbd> keys.
+ /// Labeled <kbd>\\</kbd> on a UK keyboard.
+ IntlBackslash,
+ /// Located between the <kbd>/</kbd> and right <kbd>Shift</kbd> keys.
+ /// Labeled <kbd>\\</kbd> (ro) on a Japanese keyboard.
+ IntlRo,
+ /// Located between the <kbd>=</kbd> and <kbd>Backspace</kbd> keys.
+ /// Labeled <kbd>¥</kbd> (yen) on a Japanese keyboard. <kbd>\\</kbd> on a
+ /// Russian keyboard.
+ IntlYen,
+ /// <kbd>a</kbd> on a US keyboard.
+ /// Labeled <kbd>q</kbd> on an AZERTY (e.g., French) keyboard.
+ KeyA,
+ /// <kbd>b</kbd> on a US keyboard.
+ KeyB,
+ /// <kbd>c</kbd> on a US keyboard.
+ KeyC,
+ /// <kbd>d</kbd> on a US keyboard.
+ KeyD,
+ /// <kbd>e</kbd> on a US keyboard.
+ KeyE,
+ /// <kbd>f</kbd> on a US keyboard.
+ KeyF,
+ /// <kbd>g</kbd> on a US keyboard.
+ KeyG,
+ /// <kbd>h</kbd> on a US keyboard.
+ KeyH,
+ /// <kbd>i</kbd> on a US keyboard.
+ KeyI,
+ /// <kbd>j</kbd> on a US keyboard.
+ KeyJ,
+ /// <kbd>k</kbd> on a US keyboard.
+ KeyK,
+ /// <kbd>l</kbd> on a US keyboard.
+ KeyL,
+ /// <kbd>m</kbd> on a US keyboard.
+ KeyM,
+ /// <kbd>n</kbd> on a US keyboard.
+ KeyN,
+ /// <kbd>o</kbd> on a US keyboard.
+ KeyO,
+ /// <kbd>p</kbd> on a US keyboard.
+ KeyP,
+ /// <kbd>q</kbd> on a US keyboard.
+ /// Labeled <kbd>a</kbd> on an AZERTY (e.g., French) keyboard.
+ KeyQ,
+ /// <kbd>r</kbd> on a US keyboard.
+ KeyR,
+ /// <kbd>s</kbd> on a US keyboard.
+ KeyS,
+ /// <kbd>t</kbd> on a US keyboard.
+ KeyT,
+ /// <kbd>u</kbd> on a US keyboard.
+ KeyU,
+ /// <kbd>v</kbd> on a US keyboard.
+ KeyV,
+ /// <kbd>w</kbd> on a US keyboard.
+ /// Labeled <kbd>z</kbd> on an AZERTY (e.g., French) keyboard.
+ KeyW,
+ /// <kbd>x</kbd> on a US keyboard.
+ KeyX,
+ /// <kbd>y</kbd> on a US keyboard.
+ /// Labeled <kbd>z</kbd> on a QWERTZ (e.g., German) keyboard.
+ KeyY,
+ /// <kbd>z</kbd> on a US keyboard.
+ /// Labeled <kbd>w</kbd> on an AZERTY (e.g., French) keyboard, and <kbd>y</kbd> on a
+ /// QWERTZ (e.g., German) keyboard.
+ KeyZ,
+ /// <kbd>-</kbd> on a US keyboard.
+ Minus,
+ /// <kbd>.</kbd> on a US keyboard.
+ Period,
+ /// <kbd>'</kbd> on a US keyboard.
+ Quote,
+ /// <kbd>;</kbd> on a US keyboard.
+ Semicolon,
+ /// <kbd>/</kbd> on a US keyboard.
+ Slash,
+ /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.
+ AltLeft,
+ /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.
+ /// This is labeled <kbd>AltGr</kbd> on many keyboard layouts.
+ AltRight,
+ /// <kbd>Backspace</kbd> or <kbd>⌫</kbd>.
+ /// Labeled <kbd>Delete</kbd> on Apple keyboards.
+ Backspace,
+ /// <kbd>CapsLock</kbd> or <kbd>⇪</kbd>
+ CapsLock,
+ /// The application context menu key, which is typically found between the right
+ /// <kbd>Super</kbd> key and the right <kbd>Control</kbd> key.
+ ContextMenu,
+ /// <kbd>Control</kbd> or <kbd>⌃</kbd>
+ ControlLeft,
+ /// <kbd>Control</kbd> or <kbd>⌃</kbd>
+ ControlRight,
+ /// <kbd>Enter</kbd> or <kbd>↵</kbd>. Labeled <kbd>Return</kbd> on Apple keyboards.
+ Enter,
+ /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.
+ SuperLeft,
+ /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.
+ SuperRight,
+ /// <kbd>Shift</kbd> or <kbd>⇧</kbd>
+ ShiftLeft,
+ /// <kbd>Shift</kbd> or <kbd>⇧</kbd>
+ ShiftRight,
+ /// <kbd> </kbd> (space)
+ Space,
+ /// <kbd>Tab</kbd> or <kbd>⇥</kbd>
+ Tab,
+ /// Japanese: <kbd>変</kbd> (henkan)
+ Convert,
+ /// Japanese: <kbd>カタカナ</kbd>/<kbd>ひらがな</kbd>/<kbd>ローマ字</kbd>
+ /// (katakana/hiragana/romaji)
+ KanaMode,
+ /// Korean: HangulMode <kbd>한/영</kbd> (han/yeong)
+ ///
+ /// Japanese (Mac keyboard): <kbd>か</kbd> (kana)
+ Lang1,
+ /// Korean: Hanja <kbd>한</kbd> (hanja)
+ ///
+ /// Japanese (Mac keyboard): <kbd>英</kbd> (eisu)
+ Lang2,
+ /// Japanese (word-processing keyboard): Katakana
+ Lang3,
+ /// Japanese (word-processing keyboard): Hiragana
+ Lang4,
+ /// Japanese (word-processing keyboard): Zenkaku/Hankaku
+ Lang5,
+ /// Japanese: <kbd>無変換</kbd> (muhenkan)
+ NonConvert,
+ /// <kbd>⌦</kbd>. The forward delete key.
+ /// Note that on Apple keyboards, the key labelled <kbd>Delete</kbd> on the main part of
+ /// the keyboard is encoded as [`Backspace`].
+ ///
+ /// [`Backspace`]: Self::Backspace
+ Delete,
+ /// <kbd>Page Down</kbd>, <kbd>End</kbd>, or <kbd>↘</kbd>
+ End,
+ /// <kbd>Help</kbd>. Not present on standard PC keyboards.
+ Help,
+ /// <kbd>Home</kbd> or <kbd>↖</kbd>
+ Home,
+ /// <kbd>Insert</kbd> or <kbd>Ins</kbd>. Not present on Apple keyboards.
+ Insert,
+ /// <kbd>Page Down</kbd>, <kbd>PgDn</kbd>, or <kbd>⇟</kbd>
+ PageDown,
+ /// <kbd>Page Up</kbd>, <kbd>PgUp</kbd>, or <kbd>⇞</kbd>
+ PageUp,
+ /// <kbd>↓</kbd>
+ ArrowDown,
+ /// <kbd>←</kbd>
+ ArrowLeft,
+ /// <kbd>→</kbd>
+ ArrowRight,
+ /// <kbd>↑</kbd>
+ ArrowUp,
+ /// On the Mac, this is used for the numpad <kbd>Clear</kbd> key.
+ NumLock,
+ /// <kbd>0 Ins</kbd> on a keyboard. <kbd>0</kbd> on a phone or remote control
+ Numpad0,
+ /// <kbd>1 End</kbd> on a keyboard. <kbd>1</kbd> or <kbd>1 QZ</kbd> on a phone or remote
+ /// control
+ Numpad1,
+ /// <kbd>2 ↓</kbd> on a keyboard. <kbd>2 ABC</kbd> on a phone or remote control
+ Numpad2,
+ /// <kbd>3 PgDn</kbd> on a keyboard. <kbd>3 DEF</kbd> on a phone or remote control
+ Numpad3,
+ /// <kbd>4 ←</kbd> on a keyboard. <kbd>4 GHI</kbd> on a phone or remote control
+ Numpad4,
+ /// <kbd>5</kbd> on a keyboard. <kbd>5 JKL</kbd> on a phone or remote control
+ Numpad5,
+ /// <kbd>6 →</kbd> on a keyboard. <kbd>6 MNO</kbd> on a phone or remote control
+ Numpad6,
+ /// <kbd>7 Home</kbd> on a keyboard. <kbd>7 PQRS</kbd> or <kbd>7 PRS</kbd> on a phone
+ /// or remote control
+ Numpad7,
+ /// <kbd>8 ↑</kbd> on a keyboard. <kbd>8 TUV</kbd> on a phone or remote control
+ Numpad8,
+ /// <kbd>9 PgUp</kbd> on a keyboard. <kbd>9 WXYZ</kbd> or <kbd>9 WXY</kbd> on a phone
+ /// or remote control
+ Numpad9,
+ /// <kbd>+</kbd>
+ NumpadAdd,
+ /// Found on the Microsoft Natural Keyboard.
+ NumpadBackspace,
+ /// <kbd>C</kbd> or <kbd>A</kbd> (All Clear). Also for use with numpads that have a
+ /// <kbd>Clear</kbd> key that is separate from the <kbd>NumLock</kbd> key. On the Mac, the
+ /// numpad <kbd>Clear</kbd> key is encoded as [`NumLock`].
+ ///
+ /// [`NumLock`]: Self::NumLock
+ NumpadClear,
+ /// <kbd>C</kbd> (Clear Entry)
+ NumpadClearEntry,
+ /// <kbd>,</kbd> (thousands separator). For locales where the thousands separator
+ /// is a "." (e.g., Brazil), this key may generate a <kbd>.</kbd>.
+ NumpadComma,
+ /// <kbd>. Del</kbd>. For locales where the decimal separator is "," (e.g.,
+ /// Brazil), this key may generate a <kbd>,</kbd>.
+ NumpadDecimal,
+ /// <kbd>/</kbd>
+ NumpadDivide,
+ NumpadEnter,
+ /// <kbd>=</kbd>
+ NumpadEqual,
+ /// <kbd>#</kbd> on a phone or remote control device. This key is typically found
+ /// below the <kbd>9</kbd> key and to the right of the <kbd>0</kbd> key.
+ NumpadHash,
+ /// <kbd>M</kbd> Add current entry to the value stored in memory.
+ NumpadMemoryAdd,
+ /// <kbd>M</kbd> Clear the value stored in memory.
+ NumpadMemoryClear,
+ /// <kbd>M</kbd> Replace the current entry with the value stored in memory.
+ NumpadMemoryRecall,
+ /// <kbd>M</kbd> Replace the value stored in memory with the current entry.
+ NumpadMemoryStore,
+ /// <kbd>M</kbd> Subtract current entry from the value stored in memory.
+ NumpadMemorySubtract,
+ /// <kbd>*</kbd> on a keyboard. For use with numpads that provide mathematical
+ /// operations (<kbd>+</kbd>, <kbd>-</kbd> <kbd>*</kbd> and <kbd>/</kbd>).
+ ///
+ /// Use `NumpadStar` for the <kbd>*</kbd> key on phones and remote controls.
+ NumpadMultiply,
+ /// <kbd>(</kbd> Found on the Microsoft Natural Keyboard.
+ NumpadParenLeft,
+ /// <kbd>)</kbd> Found on the Microsoft Natural Keyboard.
+ NumpadParenRight,
+ /// <kbd>*</kbd> on a phone or remote control device.
+ ///
+ /// This key is typically found below the <kbd>7</kbd> key and to the left of
+ /// the <kbd>0</kbd> key.
+ ///
+ /// Use <kbd>"NumpadMultiply"</kbd> for the <kbd>*</kbd> key on
+ /// numeric keypads.
+ NumpadStar,
+ /// <kbd>-</kbd>
+ NumpadSubtract,
+ /// <kbd>Esc</kbd> or <kbd>⎋</kbd>
+ Escape,
+ /// <kbd>Fn</kbd> This is typically a hardware key that does not generate a separate code.
+ Fn,
+ /// <kbd>FLock</kbd> or <kbd>FnLock</kbd>. Function Lock key. Found on the Microsoft
+ /// Natural Keyboard.
+ FnLock,
+ /// <kbd>PrtScr SysRq</kbd> or <kbd>Print Screen</kbd>
+ PrintScreen,
+ /// <kbd>Scroll Lock</kbd>
+ ScrollLock,
+ /// <kbd>Pause Break</kbd>
+ Pause,
+ /// Some laptops place this key to the left of the <kbd>↑</kbd> key.
+ ///
+ /// This also the "back" button (triangle) on Android.
+ BrowserBack,
+ BrowserFavorites,
+ /// Some laptops place this key to the right of the <kbd>↑</kbd> key.
+ BrowserForward,
+ /// The "home" button on Android.
+ BrowserHome,
+ BrowserRefresh,
+ BrowserSearch,
+ BrowserStop,
+ /// <kbd>Eject</kbd> or <kbd>⏏</kbd>. This key is placed in the function section on some Apple
+ /// keyboards.
+ Eject,
+ /// Sometimes labelled <kbd>My Computer</kbd> on the keyboard
+ LaunchApp1,
+ /// Sometimes labelled <kbd>Calculator</kbd> on the keyboard
+ LaunchApp2,
+ LaunchMail,
+ MediaPlayPause,
+ MediaSelect,
+ MediaStop,
+ MediaTrackNext,
+ MediaTrackPrevious,
+ /// This key is placed in the function section on some Apple keyboards, replacing the
+ /// <kbd>Eject</kbd> key.
+ Power,
+ Sleep,
+ AudioVolumeDown,
+ AudioVolumeMute,
+ AudioVolumeUp,
+ WakeUp,
+ // Legacy modifier key. Also called "Super" in certain places.
+ Meta,
+ // Legacy modifier key.
+ Hyper,
+ Turbo,
+ Abort,
+ Resume,
+ Suspend,
+ /// Found on Sun’s USB keyboard.
+ Again,
+ /// Found on Sun’s USB keyboard.
+ Copy,
+ /// Found on Sun’s USB keyboard.
+ Cut,
+ /// Found on Sun’s USB keyboard.
+ Find,
+ /// Found on Sun’s USB keyboard.
+ Open,
+ /// Found on Sun’s USB keyboard.
+ Paste,
+ /// Found on Sun’s USB keyboard.
+ Props,
+ /// Found on Sun’s USB keyboard.
+ Select,
+ /// Found on Sun’s USB keyboard.
+ Undo,
+ /// Use for dedicated <kbd>ひらがな</kbd> key found on some Japanese word processing keyboards.
+ Hiragana,
+ /// Use for dedicated <kbd>カタカナ</kbd> key found on some Japanese word processing keyboards.
+ Katakana,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F1,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F2,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F3,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F4,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F5,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F6,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F7,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F8,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F9,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F10,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F11,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F12,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F13,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F14,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F15,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F16,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F17,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F18,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F19,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F20,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F21,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F22,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F23,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F24,
+ /// General-purpose function key.
+ F25,
+ /// General-purpose function key.
+ F26,
+ /// General-purpose function key.
+ F27,
+ /// General-purpose function key.
+ F28,
+ /// General-purpose function key.
+ F29,
+ /// General-purpose function key.
+ F30,
+ /// General-purpose function key.
+ F31,
+ /// General-purpose function key.
+ F32,
+ /// General-purpose function key.
+ F33,
+ /// General-purpose function key.
+ F34,
+ /// General-purpose function key.
+ F35,
+}
+
+/// Contains the platform-native physical key identifier.
+///
+/// The exact values vary from platform to platform (which is part of why this is a per-platform
+/// enum), but the values are primarily tied to the key's physical location on the keyboard.
+///
+/// This enum is primarily used to store raw keycodes when Winit doesn't map a given native
+/// physical key identifier to a meaningful [`Code`] variant. In the presence of identifiers we
+/// haven't mapped for you yet, this lets you use use [`Code`] to:
+///
+/// - Correctly match key press and release events.
+/// - On non-web platforms, support assigning keybinds to virtually any key through a UI.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum NativeCode {
+ /// An unidentified code.
+ Unidentified,
+ /// An Android "scancode".
+ Android(u32),
+ /// A macOS "scancode".
+ MacOS(u16),
+ /// A Windows "scancode".
+ Windows(u16),
+ /// An XKB "keycode".
+ Xkb(u32),
+}
+
+/// Represents the location of a physical key.
+///
+/// This type is a superset of [`Code`], including an [`Unidentified`][Self::Unidentified]
+/// variant.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Physical {
+ /// A known key code
+ Code(Code),
+ /// This variant is used when the key cannot be translated to a [`Code`]
+ ///
+ /// The native keycode is provided (if available) so you're able to more reliably match
+ /// key-press and key-release events by hashing the [`Physical`] key. It is also possible to use
+ /// this for keybinds for non-standard keys, but such keybinds are tied to a given platform.
+ Unidentified(NativeCode),
+}
+
+impl PartialEq<Code> for Physical {
+ #[inline]
+ fn eq(&self, rhs: &Code) -> bool {
+ match self {
+ Physical::Code(ref code) => code == rhs,
+ Physical::Unidentified(_) => false,
+ }
+ }
+}
+
+impl PartialEq<Physical> for Code {
+ #[inline]
+ fn eq(&self, rhs: &Physical) -> bool {
+ rhs == self
+ }
+}
+
+impl PartialEq<NativeCode> for Physical {
+ #[inline]
+ fn eq(&self, rhs: &NativeCode) -> bool {
+ match self {
+ Physical::Unidentified(ref code) => code == rhs,
+ Physical::Code(_) => false,
+ }
+ }
+}
+
+impl PartialEq<Physical> for NativeCode {
+ #[inline]
+ fn eq(&self, rhs: &Physical) -> bool {
+ rhs == self
+ }
+}
diff --git a/core/src/mouse/click.rs b/core/src/mouse/click.rs
index 6f3844be..07a4db5a 100644
--- a/core/src/mouse/click.rs
+++ b/core/src/mouse/click.rs
@@ -1,4 +1,5 @@
//! Track mouse clicks.
+use crate::mouse::Button;
use crate::time::Instant;
use crate::Point;
@@ -6,6 +7,7 @@ use crate::Point;
#[derive(Debug, Clone, Copy)]
pub struct Click {
kind: Kind,
+ button: Button,
position: Point,
time: Instant,
}
@@ -36,11 +38,17 @@ impl Kind {
impl Click {
/// Creates a new [`Click`] with the given position and previous last
/// [`Click`].
- pub fn new(position: Point, previous: Option<Click>) -> Click {
+ pub fn new(
+ position: Point,
+ button: Button,
+ previous: Option<Click>,
+ ) -> Click {
let time = Instant::now();
let kind = if let Some(previous) = previous {
- if previous.is_consecutive(position, time) {
+ if previous.is_consecutive(position, time)
+ && button == previous.button
+ {
previous.kind.next()
} else {
Kind::Single
@@ -51,6 +59,7 @@ impl Click {
Click {
kind,
+ button,
position,
time,
}
diff --git a/core/src/mouse/interaction.rs b/core/src/mouse/interaction.rs
index 065eb8e7..aad6a3ea 100644
--- a/core/src/mouse/interaction.rs
+++ b/core/src/mouse/interaction.rs
@@ -13,6 +13,13 @@ pub enum Interaction {
Grabbing,
ResizingHorizontally,
ResizingVertically,
+ ResizingDiagonallyUp,
+ ResizingDiagonallyDown,
NotAllowed,
ZoomIn,
+ ZoomOut,
+ Cell,
+ Move,
+ Copy,
+ Help,
}
diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs
index e3a07280..bbcdd8ff 100644
--- a/core/src/renderer/null.rs
+++ b/core/src/renderer/null.rs
@@ -161,6 +161,7 @@ impl text::Editor for () {
_new_font: Self::Font,
_new_size: Pixels,
_new_line_height: text::LineHeight,
+ _new_wrapping: text::Wrapping,
_new_highlighter: &mut impl text::Highlighter,
) {
}
diff --git a/core/src/text.rs b/core/src/text.rs
index dc8f5785..d7b7fee4 100644
--- a/core/src/text.rs
+++ b/core/src/text.rs
@@ -41,6 +41,9 @@ pub struct Text<Content = String, Font = crate::Font> {
/// The [`Shaping`] strategy of the [`Text`].
pub shaping: Shaping,
+
+ /// The [`Wrapping`] strategy of the [`Text`].
+ pub wrapping: Wrapping,
}
/// The shaping strategy of some text.
@@ -67,6 +70,22 @@ pub enum Shaping {
Advanced,
}
+/// The wrapping strategy of some text.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub enum Wrapping {
+ /// No wrapping.
+ None,
+ /// Wraps at the word level.
+ ///
+ /// This is the default.
+ #[default]
+ Word,
+ /// Wraps at the glyph level.
+ Glyph,
+ /// Wraps at the word level, or fallback to glyph level if a word can't fit on a line by itself.
+ WordOrGlyph,
+}
+
/// The height of a line of text in a paragraph.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineHeight {
diff --git a/core/src/text/editor.rs b/core/src/text/editor.rs
index 135707d1..cd30db3a 100644
--- a/core/src/text/editor.rs
+++ b/core/src/text/editor.rs
@@ -1,6 +1,6 @@
//! Edit text.
use crate::text::highlighter::{self, Highlighter};
-use crate::text::LineHeight;
+use crate::text::{LineHeight, Wrapping};
use crate::{Pixels, Point, Rectangle, Size};
use std::sync::Arc;
@@ -50,6 +50,7 @@ pub trait Editor: Sized + Default {
new_font: Self::Font,
new_size: Pixels,
new_line_height: LineHeight,
+ new_wrapping: Wrapping,
new_highlighter: &mut impl Highlighter,
);
diff --git a/core/src/text/paragraph.rs b/core/src/text/paragraph.rs
index 04a97f35..924276c3 100644
--- a/core/src/text/paragraph.rs
+++ b/core/src/text/paragraph.rs
@@ -95,6 +95,7 @@ impl<P: Paragraph> Plain<P> {
horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment,
shaping: text.shaping,
+ wrapping: text.wrapping,
}) {
Difference::None => {}
Difference::Bounds => {
diff --git a/core/src/vector.rs b/core/src/vector.rs
index 1380c3b3..ff848c4f 100644
--- a/core/src/vector.rs
+++ b/core/src/vector.rs
@@ -20,6 +20,17 @@ impl Vector {
pub const ZERO: Self = Self::new(0.0, 0.0);
}
+impl<T> std::ops::Neg for Vector<T>
+where
+ T: std::ops::Neg<Output = T>,
+{
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ Self::new(-self.x, -self.y)
+ }
+}
+
impl<T> std::ops::Add for Vector<T>
where
T: std::ops::Add<Output = T>,
diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs
index 4ee4b4a7..097c3601 100644
--- a/core/src/widget/operation.rs
+++ b/core/src/widget/operation.rs
@@ -38,6 +38,7 @@ pub trait Operation<T = ()>: Send {
_state: &mut dyn Scrollable,
_id: Option<&Id>,
_bounds: Rectangle,
+ _content_bounds: Rectangle,
_translation: Vector,
) {
}
@@ -76,9 +77,16 @@ where
state: &mut dyn Scrollable,
id: Option<&Id>,
bounds: Rectangle,
+ content_bounds: Rectangle,
translation: Vector,
) {
- self.as_mut().scrollable(state, id, bounds, translation);
+ self.as_mut().scrollable(
+ state,
+ id,
+ bounds,
+ content_bounds,
+ translation,
+ );
}
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
@@ -151,9 +159,16 @@ where
state: &mut dyn Scrollable,
id: Option<&Id>,
bounds: Rectangle,
+ content_bounds: Rectangle,
translation: Vector,
) {
- self.operation.scrollable(state, id, bounds, translation);
+ self.operation.scrollable(
+ state,
+ id,
+ bounds,
+ content_bounds,
+ translation,
+ );
}
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
@@ -222,9 +237,16 @@ where
state: &mut dyn Scrollable,
id: Option<&Id>,
bounds: Rectangle,
+ content_bounds: Rectangle,
translation: Vector,
) {
- self.operation.scrollable(state, id, bounds, translation);
+ self.operation.scrollable(
+ state,
+ id,
+ bounds,
+ content_bounds,
+ translation,
+ );
}
fn focusable(
@@ -262,9 +284,16 @@ where
state: &mut dyn Scrollable,
id: Option<&Id>,
bounds: Rectangle,
+ content_bounds: Rectangle,
translation: Vector,
) {
- self.operation.scrollable(state, id, bounds, translation);
+ self.operation.scrollable(
+ state,
+ id,
+ bounds,
+ content_bounds,
+ translation,
+ );
}
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
@@ -341,9 +370,16 @@ where
state: &mut dyn Scrollable,
id: Option<&Id>,
bounds: Rectangle,
+ content_bounds: Rectangle,
translation: crate::Vector,
) {
- self.operation.scrollable(state, id, bounds, translation);
+ self.operation.scrollable(
+ state,
+ id,
+ bounds,
+ content_bounds,
+ translation,
+ );
}
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
diff --git a/core/src/widget/operation/scrollable.rs b/core/src/widget/operation/scrollable.rs
index 12161255..c2fecf56 100644
--- a/core/src/widget/operation/scrollable.rs
+++ b/core/src/widget/operation/scrollable.rs
@@ -9,6 +9,14 @@ pub trait Scrollable {
/// Scroll the widget to the given [`AbsoluteOffset`] along the horizontal & vertical axis.
fn scroll_to(&mut self, offset: AbsoluteOffset);
+
+ /// Scroll the widget by the given [`AbsoluteOffset`] along the horizontal & vertical axis.
+ fn scroll_by(
+ &mut self,
+ offset: AbsoluteOffset,
+ bounds: Rectangle,
+ content_bounds: Rectangle,
+ );
}
/// Produces an [`Operation`] that snaps the widget with the given [`Id`] to
@@ -34,6 +42,7 @@ pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> {
state: &mut dyn Scrollable,
id: Option<&Id>,
_bounds: Rectangle,
+ _content_bounds: Rectangle,
_translation: Vector,
) {
if Some(&self.target) == id {
@@ -68,6 +77,7 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
state: &mut dyn Scrollable,
id: Option<&Id>,
_bounds: Rectangle,
+ _content_bounds: Rectangle,
_translation: Vector,
) {
if Some(&self.target) == id {
@@ -79,6 +89,41 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
ScrollTo { target, offset }
}
+/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] by
+/// the provided [`AbsoluteOffset`].
+pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
+ struct ScrollBy {
+ target: Id,
+ offset: AbsoluteOffset,
+ }
+
+ impl<T> Operation<T> for ScrollBy {
+ fn container(
+ &mut self,
+ _id: Option<&Id>,
+ _bounds: Rectangle,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
+ ) {
+ operate_on_children(self);
+ }
+
+ fn scrollable(
+ &mut self,
+ state: &mut dyn Scrollable,
+ id: Option<&Id>,
+ bounds: Rectangle,
+ content_bounds: Rectangle,
+ _translation: Vector,
+ ) {
+ if Some(&self.target) == id {
+ state.scroll_by(self.offset, bounds, content_bounds);
+ }
+ }
+ }
+
+ ScrollBy { target, offset }
+}
+
/// The amount of absolute offset in each direction of a [`Scrollable`].
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct AbsoluteOffset {
diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs
index 5c5b78dd..d8d6e4c6 100644
--- a/core/src/widget/text.rs
+++ b/core/src/widget/text.rs
@@ -11,7 +11,7 @@ use crate::{
Widget,
};
-pub use text::{LineHeight, Shaping};
+pub use text::{LineHeight, Shaping, Wrapping};
/// A paragraph of text.
#[allow(missing_debug_implementations)]
@@ -29,6 +29,7 @@ where
vertical_alignment: alignment::Vertical,
font: Option<Renderer::Font>,
shaping: Shaping,
+ wrapping: Wrapping,
class: Theme::Class<'a>,
}
@@ -48,7 +49,8 @@ where
height: Length::Shrink,
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
- shaping: Shaping::Basic,
+ shaping: Shaping::default(),
+ wrapping: Wrapping::default(),
class: Theme::default(),
}
}
@@ -115,6 +117,12 @@ where
self
}
+ /// Sets the [`Wrapping`] strategy of the [`Text`].
+ pub fn wrapping(mut self, wrapping: Wrapping) -> Self {
+ self.wrapping = wrapping;
+ self
+ }
+
/// Sets the style of the [`Text`].
#[must_use]
pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self
@@ -198,6 +206,7 @@ where
self.horizontal_alignment,
self.vertical_alignment,
self.shaping,
+ self.wrapping,
)
}
@@ -232,6 +241,7 @@ pub fn layout<Renderer>(
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
shaping: Shaping,
+ wrapping: Wrapping,
) -> layout::Node
where
Renderer: text::Renderer,
@@ -253,6 +263,7 @@ where
horizontal_alignment,
vertical_alignment,
shaping,
+ wrapping,
});
paragraph.min_bounds()
diff --git a/core/src/window/settings/linux.rs b/core/src/window/settings/linux.rs
index 009b9d9e..0a1e11cd 100644
--- a/core/src/window/settings/linux.rs
+++ b/core/src/window/settings/linux.rs
@@ -8,4 +8,10 @@ pub struct PlatformSpecific {
/// As a best practice, it is suggested to select an application id that match
/// the basename of the application’s .desktop file.
pub application_id: String,
+
+ /// Whether bypass the window manager mapping for x11 windows
+ ///
+ /// This flag is particularly useful for creating UI elements that need precise
+ /// positioning and immediate display without window manager interference.
+ pub override_redirect: bool,
}
diff --git a/core/src/window/settings/windows.rs b/core/src/window/settings/windows.rs
index 88fe2fbd..a47582a6 100644
--- a/core/src/window/settings/windows.rs
+++ b/core/src/window/settings/windows.rs
@@ -8,6 +8,12 @@ pub struct PlatformSpecific {
/// Whether show or hide the window icon in the taskbar.
pub skip_taskbar: bool,
+
+ /// Shows or hides the background drop shadow for undecorated windows.
+ ///
+ /// The shadow is hidden by default.
+ /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
+ pub undecorated_shadow: bool,
}
impl Default for PlatformSpecific {
@@ -15,6 +21,7 @@ impl Default for PlatformSpecific {
Self {
drag_and_drop: true,
skip_taskbar: false,
+ undecorated_shadow: false,
}
}
}