summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--core/Cargo.toml2
-rw-r--r--core/src/clipboard.rs23
-rw-r--r--core/src/element.rs (renamed from native/src/element.rs)67
-rw-r--r--core/src/event.rs (renamed from native/src/event.rs)2
-rw-r--r--core/src/font.rs111
-rw-r--r--core/src/gradient.rs (renamed from graphics/src/gradient.rs)0
-rw-r--r--core/src/gradient/linear.rs (renamed from graphics/src/gradient/linear.rs)0
-rw-r--r--core/src/hasher.rs (renamed from native/src/hasher.rs)0
-rw-r--r--core/src/image.rs (renamed from native/src/image.rs)12
-rw-r--r--core/src/layout.rs (renamed from native/src/layout.rs)0
-rw-r--r--core/src/layout/DRUID_LICENSE (renamed from native/src/layout/DRUID_LICENSE)0
-rw-r--r--core/src/layout/flex.rs (renamed from native/src/layout/flex.rs)0
-rw-r--r--core/src/layout/limits.rs (renamed from native/src/layout/limits.rs)0
-rw-r--r--core/src/layout/node.rs (renamed from native/src/layout/node.rs)0
-rw-r--r--core/src/length.rs8
-rw-r--r--core/src/lib.rs28
-rw-r--r--core/src/mouse.rs3
-rw-r--r--core/src/mouse/click.rs (renamed from native/src/mouse/click.rs)0
-rw-r--r--core/src/overlay.rs (renamed from native/src/overlay.rs)3
-rw-r--r--core/src/overlay/element.rs (renamed from native/src/overlay/element.rs)0
-rw-r--r--core/src/overlay/group.rs (renamed from native/src/overlay/group.rs)4
-rw-r--r--core/src/pixels.rs6
-rw-r--r--core/src/rectangle.rs48
-rw-r--r--core/src/renderer.rs (renamed from native/src/renderer.rs)1
-rw-r--r--core/src/renderer/null.rs (renamed from native/src/renderer/null.rs)20
-rw-r--r--core/src/shell.rs (renamed from native/src/shell.rs)0
-rw-r--r--core/src/size.rs2
-rw-r--r--core/src/svg.rs (renamed from native/src/svg.rs)4
-rw-r--r--core/src/text.rs212
-rw-r--r--core/src/touch.rs (renamed from native/src/touch.rs)0
-rw-r--r--core/src/widget.rs (renamed from native/src/widget.rs)90
-rw-r--r--core/src/widget/id.rs (renamed from native/src/widget/id.rs)2
-rw-r--r--core/src/widget/operation.rs226
-rw-r--r--core/src/widget/operation/focusable.rs (renamed from native/src/widget/operation/focusable.rs)0
-rw-r--r--core/src/widget/operation/scrollable.rs (renamed from native/src/widget/operation/scrollable.rs)0
-rw-r--r--core/src/widget/operation/text_input.rs (renamed from native/src/widget/operation/text_input.rs)0
-rw-r--r--core/src/widget/text.rs (renamed from native/src/widget/text.rs)110
-rw-r--r--core/src/widget/tree.rs (renamed from native/src/widget/tree.rs)0
-rw-r--r--core/src/window.rs13
-rw-r--r--core/src/window/event.rs (renamed from native/src/window/event.rs)0
-rw-r--r--core/src/window/icon.rs (renamed from native/src/window/icon.rs)0
-rw-r--r--core/src/window/mode.rs (renamed from native/src/window/mode.rs)0
-rw-r--r--core/src/window/redraw_request.rs (renamed from native/src/window/redraw_request.rs)0
-rw-r--r--core/src/window/user_attention.rs (renamed from native/src/window/user_attention.rs)0
44 files changed, 828 insertions, 169 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 3a00a53e..92d9773f 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -9,6 +9,8 @@ repository = "https://github.com/iced-rs/iced"
[dependencies]
bitflags = "1.2"
+thiserror = "1"
+twox-hash = { version = "1.5", default-features = false }
[dependencies.palette]
version = "0.6"
diff --git a/core/src/clipboard.rs b/core/src/clipboard.rs
new file mode 100644
index 00000000..081b4004
--- /dev/null
+++ b/core/src/clipboard.rs
@@ -0,0 +1,23 @@
+//! Access the clipboard.
+
+/// A buffer for short-term storage and transfer within and between
+/// applications.
+pub trait Clipboard {
+ /// Reads the current content of the [`Clipboard`] as text.
+ fn read(&self) -> Option<String>;
+
+ /// Writes the given text contents to the [`Clipboard`].
+ fn write(&mut self, contents: String);
+}
+
+/// A null implementation of the [`Clipboard`] trait.
+#[derive(Debug, Clone, Copy)]
+pub struct Null;
+
+impl Clipboard for Null {
+ fn read(&self) -> Option<String> {
+ None
+ }
+
+ fn write(&mut self, _contents: String) {}
+}
diff --git a/native/src/element.rs b/core/src/element.rs
index 0a677d20..98c53737 100644
--- a/native/src/element.rs
+++ b/core/src/element.rs
@@ -90,41 +90,65 @@ impl<'a, Message, Renderer> Element<'a, Message, Renderer> {
/// We compose the previous __messages__ with the index of the counter
/// producing them. Let's implement our __view logic__ now:
///
- /// ```
+ /// ```no_run
/// # mod counter {
- /// # type Text<'a> = iced_native::widget::Text<'a, iced_native::renderer::Null>;
- /// #
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {}
/// # pub struct Counter;
/// #
/// # impl Counter {
- /// # pub fn view(&mut self) -> Text {
- /// # Text::new("")
+ /// # pub fn view(
+ /// # &self,
+ /// # ) -> iced_core::Element<Message, iced_core::renderer::Null> {
+ /// # unimplemented!()
/// # }
/// # }
/// # }
/// #
- /// # mod iced_wgpu {
- /// # pub use iced_native::renderer::Null as Renderer;
- /// # }
+ /// # mod iced {
+ /// # pub use iced_core::renderer::Null as Renderer;
+ /// # pub use iced_core::Element;
/// #
- /// # use counter::Counter;
+ /// # pub mod widget {
+ /// # pub struct Row<Message> {
+ /// # _t: std::marker::PhantomData<Message>,
+ /// # }
/// #
- /// # struct ManyCounters {
- /// # counters: Vec<Counter>,
- /// # }
+ /// # impl<Message> Row<Message> {
+ /// # pub fn new() -> Self {
+ /// # unimplemented!()
+ /// # }
/// #
- /// # #[derive(Debug, Clone, Copy)]
- /// # pub enum Message {
- /// # Counter(usize, counter::Message)
+ /// # pub fn spacing(mut self, _: u32) -> Self {
+ /// # unimplemented!()
+ /// # }
+ /// #
+ /// # pub fn push(
+ /// # mut self,
+ /// # _: iced_core::Element<Message, iced_core::renderer::Null>,
+ /// # ) -> Self {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ /// # }
/// # }
- /// use iced_native::Element;
- /// use iced_native::widget::Row;
- /// use iced_wgpu::Renderer;
+ /// #
+ /// use counter::Counter;
+ ///
+ /// use iced::widget::Row;
+ /// use iced::{Element, Renderer};
+ ///
+ /// struct ManyCounters {
+ /// counters: Vec<Counter>,
+ /// }
+ ///
+ /// #[derive(Debug, Clone, Copy)]
+ /// pub enum Message {
+ /// Counter(usize, counter::Message),
+ /// }
///
/// impl ManyCounters {
- /// pub fn view(&mut self) -> Row<Message, Renderer> {
+ /// pub fn view(&mut self) -> Row<Message> {
/// // We can quickly populate a `Row` by folding over our counters
/// self.counters.iter_mut().enumerate().fold(
/// Row::new().spacing(20),
@@ -137,9 +161,10 @@ impl<'a, Message, Renderer> Element<'a, Message, Renderer> {
/// // Here we turn our `Element<counter::Message>` into
/// // an `Element<Message>` by combining the `index` and the
/// // message of the `element`.
- /// element.map(move |message| Message::Counter(index, message))
+ /// element
+ /// .map(move |message| Message::Counter(index, message)),
/// )
- /// }
+ /// },
/// )
/// }
/// }
diff --git a/native/src/event.rs b/core/src/event.rs
index bcfaf891..953cd73f 100644
--- a/native/src/event.rs
+++ b/core/src/event.rs
@@ -62,7 +62,7 @@ impl Status {
/// `Captured` takes precedence over `Ignored`:
///
/// ```
- /// use iced_native::event::Status;
+ /// use iced_core::event::Status;
///
/// assert_eq!(Status::Ignored.merge(Status::Ignored), Status::Ignored);
/// assert_eq!(Status::Ignored.merge(Status::Captured), Status::Captured);
diff --git a/core/src/font.rs b/core/src/font.rs
index d8c34e5a..bb425fd6 100644
--- a/core/src/font.rs
+++ b/core/src/font.rs
@@ -1,19 +1,102 @@
+//! Load and use fonts.
+use std::hash::Hash;
+
/// A font.
-#[derive(Debug, Clone, Copy, Default)]
-pub enum Font {
- /// The default font.
- ///
- /// This is normally a font configured in a renderer or loaded from the
- /// system.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub struct Font {
+ /// The [`Family`] of the [`Font`].
+ pub family: Family,
+ /// The [`Weight`] of the [`Font`].
+ pub weight: Weight,
+ /// The [`Stretch`] of the [`Font`].
+ pub stretch: Stretch,
+ /// Whether if the [`Font`] is monospaced or not.
+ pub monospaced: bool,
+}
+
+impl Font {
+ /// A non-monospaced sans-serif font with normal [`Weight`].
+ pub const DEFAULT: Font = Font {
+ family: Family::SansSerif,
+ weight: Weight::Normal,
+ stretch: Stretch::Normal,
+ monospaced: false,
+ };
+
+ /// A monospaced font with normal [`Weight`].
+ pub const MONOSPACE: Font = Font {
+ family: Family::Monospace,
+ monospaced: true,
+ ..Self::DEFAULT
+ };
+
+ /// Creates a non-monospaced [`Font`] with the given [`Family::Name`] and
+ /// normal [`Weight`].
+ pub const fn with_name(name: &'static str) -> Self {
+ Font {
+ family: Family::Name(name),
+ ..Self::DEFAULT
+ }
+ }
+}
+
+/// A font family.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub enum Family {
+ /// The name of a font family of choice.
+ Name(&'static str),
+
+ /// Serif fonts represent the formal text style for a script.
+ Serif,
+
+ /// Glyphs in sans-serif fonts, as the term is used in CSS, are generally low
+ /// contrast and have stroke endings that are plain — without any flaring,
+ /// cross stroke, or other ornamentation.
#[default]
- Default,
+ SansSerif,
+
+ /// Glyphs in cursive fonts generally use a more informal script style, and
+ /// the result looks more like handwritten pen or brush writing than printed
+ /// letterwork.
+ Cursive,
+
+ /// Fantasy fonts are primarily decorative or expressive fonts that contain
+ /// decorative or expressive representations of characters.
+ Fantasy,
+
+ /// The sole criterion of a monospace font is that all glyphs have the same
+ /// fixed width.
+ Monospace,
+}
- /// An external font.
- External {
- /// The name of the external font
- name: &'static str,
+/// The weight of some text.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub enum Weight {
+ Thin,
+ ExtraLight,
+ Light,
+ #[default]
+ Normal,
+ Medium,
+ Semibold,
+ Bold,
+ ExtraBold,
+ Black,
+}
- /// The bytes of the external font
- bytes: &'static [u8],
- },
+/// The width of some text.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub enum Stretch {
+ UltraCondensed,
+ ExtraCondensed,
+ Condensed,
+ SemiCondensed,
+ #[default]
+ Normal,
+ SemiExpanded,
+ Expanded,
+ ExtraExpanded,
+ UltraExpanded,
}
diff --git a/graphics/src/gradient.rs b/core/src/gradient.rs
index 61e919d6..61e919d6 100644
--- a/graphics/src/gradient.rs
+++ b/core/src/gradient.rs
diff --git a/graphics/src/gradient/linear.rs b/core/src/gradient/linear.rs
index c886db47..c886db47 100644
--- a/graphics/src/gradient/linear.rs
+++ b/core/src/gradient/linear.rs
diff --git a/native/src/hasher.rs b/core/src/hasher.rs
index fa52f16d..fa52f16d 100644
--- a/native/src/hasher.rs
+++ b/core/src/hasher.rs
diff --git a/native/src/image.rs b/core/src/image.rs
index 70fbade0..85d9d475 100644
--- a/native/src/image.rs
+++ b/core/src/image.rs
@@ -6,7 +6,7 @@ use std::path::PathBuf;
use std::sync::Arc;
/// A handle of some image data.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Handle {
id: u64,
data: Data,
@@ -110,6 +110,14 @@ impl std::hash::Hash for Bytes {
}
}
+impl PartialEq for Bytes {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_ref() == other.as_ref()
+ }
+}
+
+impl Eq for Bytes {}
+
impl AsRef<[u8]> for Bytes {
fn as_ref(&self) -> &[u8] {
self.0.as_ref().as_ref()
@@ -125,7 +133,7 @@ impl std::ops::Deref for Bytes {
}
/// The data of a raster image.
-#[derive(Clone, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Data {
/// File data
Path(PathBuf),
diff --git a/native/src/layout.rs b/core/src/layout.rs
index 04954fb9..04954fb9 100644
--- a/native/src/layout.rs
+++ b/core/src/layout.rs
diff --git a/native/src/layout/DRUID_LICENSE b/core/src/layout/DRUID_LICENSE
index d6456956..d6456956 100644
--- a/native/src/layout/DRUID_LICENSE
+++ b/core/src/layout/DRUID_LICENSE
diff --git a/native/src/layout/flex.rs b/core/src/layout/flex.rs
index 8b967849..8b967849 100644
--- a/native/src/layout/flex.rs
+++ b/core/src/layout/flex.rs
diff --git a/native/src/layout/limits.rs b/core/src/layout/limits.rs
index 5d3c1556..5d3c1556 100644
--- a/native/src/layout/limits.rs
+++ b/core/src/layout/limits.rs
diff --git a/native/src/layout/node.rs b/core/src/layout/node.rs
index 2b44a7d5..2b44a7d5 100644
--- a/native/src/layout/node.rs
+++ b/core/src/layout/node.rs
diff --git a/core/src/length.rs b/core/src/length.rs
index bb925c4b..3adb996e 100644
--- a/core/src/length.rs
+++ b/core/src/length.rs
@@ -1,3 +1,5 @@
+use crate::Pixels;
+
/// The strategy used to fill space in a specific dimension.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Length {
@@ -36,6 +38,12 @@ impl Length {
}
}
+impl From<Pixels> for Length {
+ fn from(amount: Pixels) -> Self {
+ Length::Fixed(f32::from(amount))
+ }
+}
+
impl From<f32> for Length {
fn from(amount: f32) -> Self {
Length::Fixed(amount)
diff --git a/core/src/lib.rs b/core/src/lib.rs
index da3cb874..89dfb828 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -25,31 +25,57 @@
#![forbid(unsafe_code, rust_2018_idioms)]
#![allow(clippy::inherent_to_string, clippy::type_complexity)]
pub mod alignment;
+pub mod clipboard;
+pub mod event;
+pub mod font;
+pub mod gradient;
+pub mod image;
pub mod keyboard;
+pub mod layout;
pub mod mouse;
+pub mod overlay;
+pub mod renderer;
+pub mod svg;
+pub mod text;
pub mod time;
+pub mod touch;
+pub mod widget;
+pub mod window;
mod background;
mod color;
mod content_fit;
-mod font;
+mod element;
+mod hasher;
mod length;
mod padding;
mod pixels;
mod point;
mod rectangle;
+mod shell;
mod size;
mod vector;
pub use alignment::Alignment;
pub use background::Background;
+pub use clipboard::Clipboard;
pub use color::Color;
pub use content_fit::ContentFit;
+pub use element::Element;
+pub use event::Event;
pub use font::Font;
+pub use gradient::Gradient;
+pub use hasher::Hasher;
+pub use layout::Layout;
pub use length::Length;
+pub use overlay::Overlay;
pub use padding::Padding;
pub use pixels::Pixels;
pub use point::Point;
pub use rectangle::Rectangle;
+pub use renderer::Renderer;
+pub use shell::Shell;
pub use size::Size;
+pub use text::Text;
pub use vector::Vector;
+pub use widget::Widget;
diff --git a/core/src/mouse.rs b/core/src/mouse.rs
index 48214f65..0c405ce6 100644
--- a/core/src/mouse.rs
+++ b/core/src/mouse.rs
@@ -1,8 +1,11 @@
//! Handle mouse events.
+pub mod click;
+
mod button;
mod event;
mod interaction;
pub use button::Button;
+pub use click::Click;
pub use event::{Event, ScrollDelta};
pub use interaction::Interaction;
diff --git a/native/src/mouse/click.rs b/core/src/mouse/click.rs
index 4a7d796c..4a7d796c 100644
--- a/native/src/mouse/click.rs
+++ b/core/src/mouse/click.rs
diff --git a/native/src/overlay.rs b/core/src/overlay.rs
index 6cada416..b9f3c735 100644
--- a/native/src/overlay.rs
+++ b/core/src/overlay.rs
@@ -2,11 +2,8 @@
mod element;
mod group;
-pub mod menu;
-
pub use element::Element;
pub use group::Group;
-pub use menu::Menu;
use crate::event::{self, Event};
use crate::layout;
diff --git a/native/src/overlay/element.rs b/core/src/overlay/element.rs
index 237d25d1..237d25d1 100644
--- a/native/src/overlay/element.rs
+++ b/core/src/overlay/element.rs
diff --git a/native/src/overlay/group.rs b/core/src/overlay/group.rs
index 1126f0cf..0c48df34 100644
--- a/native/src/overlay/group.rs
+++ b/core/src/overlay/group.rs
@@ -1,12 +1,10 @@
-use iced_core::{Point, Rectangle, Size};
-
use crate::event;
use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::widget;
-use crate::{Clipboard, Event, Layout, Overlay, Shell};
+use crate::{Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size};
/// An [`Overlay`] container that displays multiple overlay [`overlay::Element`]
/// children.
diff --git a/core/src/pixels.rs b/core/src/pixels.rs
index e42cd9f9..6a9e5c88 100644
--- a/core/src/pixels.rs
+++ b/core/src/pixels.rs
@@ -20,3 +20,9 @@ impl From<u16> for Pixels {
Self(f32::from(amount))
}
}
+
+impl From<Pixels> for f32 {
+ fn from(pixels: Pixels) -> Self {
+ pixels.0
+ }
+}
diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs
index 4fe91519..7ff324cb 100644
--- a/core/src/rectangle.rs
+++ b/core/src/rectangle.rs
@@ -66,6 +66,11 @@ impl Rectangle<f32> {
Size::new(self.width, self.height)
}
+ /// Returns the area of the [`Rectangle`].
+ pub fn area(&self) -> f32 {
+ self.width * self.height
+ }
+
/// Returns true if the given [`Point`] is contained in the [`Rectangle`].
pub fn contains(&self, point: Point) -> bool {
self.x <= point.x
@@ -74,6 +79,15 @@ impl Rectangle<f32> {
&& point.y <= self.y + self.height
}
+ /// Returns true if the current [`Rectangle`] is completely within the given
+ /// `container`.
+ pub fn is_within(&self, container: &Rectangle) -> bool {
+ container.contains(self.position())
+ && container.contains(
+ self.position() + Vector::new(self.width, self.height),
+ )
+ }
+
/// Computes the intersection with the given [`Rectangle`].
pub fn intersection(
&self,
@@ -100,6 +114,30 @@ impl Rectangle<f32> {
}
}
+ /// Returns whether the [`Rectangle`] intersects with the given one.
+ pub fn intersects(&self, other: &Self) -> bool {
+ self.intersection(other).is_some()
+ }
+
+ /// Computes the union with the given [`Rectangle`].
+ pub fn union(&self, other: &Self) -> Self {
+ let x = self.x.min(other.x);
+ let y = self.y.min(other.y);
+
+ let lower_right_x = (self.x + self.width).max(other.x + other.width);
+ let lower_right_y = (self.y + self.height).max(other.y + other.height);
+
+ let width = lower_right_x - x;
+ let height = lower_right_y - y;
+
+ Rectangle {
+ x,
+ y,
+ width,
+ height,
+ }
+ }
+
/// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.
pub fn snap(self) -> Rectangle<u32> {
Rectangle {
@@ -109,6 +147,16 @@ impl Rectangle<f32> {
height: self.height as u32,
}
}
+
+ /// Expands the [`Rectangle`] a given amount.
+ pub fn expand(self, amount: f32) -> Self {
+ Self {
+ x: self.x - amount,
+ y: self.y - amount,
+ width: self.width + amount * 2.0,
+ height: self.height + amount * 2.0,
+ }
+ }
}
impl std::ops::Mul<f32> for Rectangle<f32> {
diff --git a/native/src/renderer.rs b/core/src/renderer.rs
index 2ac78982..d6247e39 100644
--- a/native/src/renderer.rs
+++ b/core/src/renderer.rs
@@ -1,6 +1,7 @@
//! Write your own renderer.
#[cfg(debug_assertions)]
mod null;
+
#[cfg(debug_assertions)]
pub use null::Null;
diff --git a/native/src/renderer/null.rs b/core/src/renderer/null.rs
index 9376d540..f0cc952e 100644
--- a/native/src/renderer/null.rs
+++ b/core/src/renderer/null.rs
@@ -1,6 +1,8 @@
use crate::renderer::{self, Renderer};
use crate::text::{self, Text};
-use crate::{Background, Font, Point, Rectangle, Size, Theme, Vector};
+use crate::{Background, Font, Point, Rectangle, Size, Vector};
+
+use std::borrow::Cow;
/// A renderer that does nothing.
///
@@ -16,7 +18,7 @@ impl Null {
}
impl Renderer for Null {
- type Theme = Theme;
+ type Theme = ();
fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {}
@@ -40,20 +42,28 @@ impl Renderer for Null {
impl text::Renderer for Null {
type Font = Font;
- const ICON_FONT: Font = Font::Default;
+ const ICON_FONT: Font = Font::DEFAULT;
const CHECKMARK_ICON: char = '0';
const ARROW_DOWN_ICON: char = '0';
+ fn default_font(&self) -> Self::Font {
+ Font::default()
+ }
+
fn default_size(&self) -> f32 {
- 20.0
+ 16.0
}
+ fn load_font(&mut self, _font: Cow<'static, [u8]>) {}
+
fn measure(
&self,
_content: &str,
_size: f32,
+ _line_height: text::LineHeight,
_font: Font,
_bounds: Size,
+ _shaping: text::Shaping,
) -> (f32, f32) {
(0.0, 20.0)
}
@@ -62,8 +72,10 @@ impl text::Renderer for Null {
&self,
_contents: &str,
_size: f32,
+ _line_height: text::LineHeight,
_font: Self::Font,
_bounds: Size,
+ _shaping: text::Shaping,
_point: Point,
_nearest_only: bool,
) -> Option<text::Hit> {
diff --git a/native/src/shell.rs b/core/src/shell.rs
index 74a5c616..74a5c616 100644
--- a/native/src/shell.rs
+++ b/core/src/shell.rs
diff --git a/core/src/size.rs b/core/src/size.rs
index fbe940ef..7ef2f602 100644
--- a/core/src/size.rs
+++ b/core/src/size.rs
@@ -1,7 +1,7 @@
use crate::{Padding, Vector};
/// An amount of space in 2 dimensions.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Size<T = f32> {
/// The width.
pub width: T,
diff --git a/native/src/svg.rs b/core/src/svg.rs
index 9b98877a..54e9434e 100644
--- a/native/src/svg.rs
+++ b/core/src/svg.rs
@@ -7,7 +7,7 @@ use std::path::PathBuf;
use std::sync::Arc;
/// A handle of Svg data.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Handle {
id: u64,
data: Arc<Data>,
@@ -57,7 +57,7 @@ impl Hash for Handle {
}
/// The data of a vectorial image.
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, PartialEq, Eq)]
pub enum Data {
/// File data
Path(PathBuf),
diff --git a/core/src/text.rs b/core/src/text.rs
new file mode 100644
index 00000000..c154cc27
--- /dev/null
+++ b/core/src/text.rs
@@ -0,0 +1,212 @@
+//! Draw and interact with text.
+use crate::alignment;
+use crate::{Color, Pixels, Point, Rectangle, Size};
+
+use std::borrow::Cow;
+use std::hash::{Hash, Hasher};
+
+/// A paragraph.
+#[derive(Debug, Clone, Copy)]
+pub struct Text<'a, Font> {
+ /// The content of the paragraph.
+ pub content: &'a str,
+
+ /// The bounds of the paragraph.
+ pub bounds: Rectangle,
+
+ /// The size of the [`Text`] in logical pixels.
+ pub size: f32,
+
+ /// The line height of the [`Text`].
+ pub line_height: LineHeight,
+
+ /// The color of the [`Text`].
+ pub color: Color,
+
+ /// The font of the [`Text`].
+ pub font: Font,
+
+ /// The horizontal alignment of the [`Text`].
+ pub horizontal_alignment: alignment::Horizontal,
+
+ /// The vertical alignment of the [`Text`].
+ pub vertical_alignment: alignment::Vertical,
+
+ /// The [`Shaping`] strategy of the [`Text`].
+ pub shaping: Shaping,
+}
+
+/// The shaping strategy of some text.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
+pub enum Shaping {
+ /// No shaping and no font fallback.
+ ///
+ /// This shaping strategy is very cheap, but it will not display complex
+ /// scripts properly nor try to find missing glyphs in your system fonts.
+ ///
+ /// You should use this strategy when you have complete control of the text
+ /// and the font you are displaying in your application.
+ ///
+ /// This is the default.
+ #[default]
+ Basic,
+ /// Advanced text shaping and font fallback.
+ ///
+ /// You will need to enable this flag if the text contains a complex
+ /// script, the font used needs it, and/or multiple fonts in your system
+ /// may be needed to display all of the glyphs.
+ ///
+ /// Advanced shaping is expensive! You should only enable it when necessary.
+ Advanced,
+}
+
+/// The height of a line of text in a paragraph.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum LineHeight {
+ /// A factor of the size of the text.
+ Relative(f32),
+
+ /// An absolute height in logical pixels.
+ Absolute(Pixels),
+}
+
+impl LineHeight {
+ /// Returns the [`LineHeight`] in absolute logical pixels.
+ pub fn to_absolute(self, text_size: Pixels) -> Pixels {
+ match self {
+ Self::Relative(factor) => Pixels(factor * text_size.0),
+ Self::Absolute(pixels) => pixels,
+ }
+ }
+}
+
+impl Default for LineHeight {
+ fn default() -> Self {
+ Self::Relative(1.3)
+ }
+}
+
+impl From<f32> for LineHeight {
+ fn from(factor: f32) -> Self {
+ Self::Relative(factor)
+ }
+}
+
+impl From<Pixels> for LineHeight {
+ fn from(pixels: Pixels) -> Self {
+ Self::Absolute(pixels)
+ }
+}
+
+impl Hash for LineHeight {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ match self {
+ Self::Relative(factor) => {
+ state.write_u8(0);
+ factor.to_bits().hash(state);
+ }
+ Self::Absolute(pixels) => {
+ state.write_u8(1);
+ f32::from(*pixels).to_bits().hash(state);
+ }
+ }
+ }
+}
+
+/// The result of hit testing on text.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Hit {
+ /// The point was within the bounds of the returned character index.
+ CharOffset(usize),
+}
+
+impl Hit {
+ /// Computes the cursor position of the [`Hit`] .
+ pub fn cursor(self) -> usize {
+ match self {
+ Self::CharOffset(i) => i,
+ }
+ }
+}
+
+/// A renderer capable of measuring and drawing [`Text`].
+pub trait Renderer: crate::Renderer {
+ /// The font type used.
+ type Font: Copy;
+
+ /// The icon font of the backend.
+ const ICON_FONT: Self::Font;
+
+ /// The `char` representing a ✔ icon in the [`ICON_FONT`].
+ ///
+ /// [`ICON_FONT`]: Self::ICON_FONT
+ const CHECKMARK_ICON: char;
+
+ /// The `char` representing a ▼ icon in the built-in [`ICON_FONT`].
+ ///
+ /// [`ICON_FONT`]: Self::ICON_FONT
+ const ARROW_DOWN_ICON: char;
+
+ /// Returns the default [`Self::Font`].
+ fn default_font(&self) -> Self::Font;
+
+ /// Returns the default size of [`Text`].
+ fn default_size(&self) -> f32;
+
+ /// Measures the text in the given bounds and returns the minimum boundaries
+ /// that can fit the contents.
+ fn measure(
+ &self,
+ content: &str,
+ size: f32,
+ line_height: LineHeight,
+ font: Self::Font,
+ bounds: Size,
+ shaping: Shaping,
+ ) -> (f32, f32);
+
+ /// Measures the width of the text as if it were laid out in a single line.
+ fn measure_width(
+ &self,
+ content: &str,
+ size: f32,
+ font: Self::Font,
+ shaping: Shaping,
+ ) -> f32 {
+ let (width, _) = self.measure(
+ content,
+ size,
+ LineHeight::Absolute(Pixels(size)),
+ font,
+ Size::INFINITY,
+ shaping,
+ );
+
+ width
+ }
+
+ /// Tests whether the provided point is within the boundaries of text
+ /// laid out with the given parameters, returning information about
+ /// the nearest character.
+ ///
+ /// If `nearest_only` is true, the hit test does not consider whether the
+ /// the point is interior to any glyph bounds, returning only the character
+ /// with the nearest centeroid.
+ fn hit_test(
+ &self,
+ contents: &str,
+ size: f32,
+ line_height: LineHeight,
+ font: Self::Font,
+ bounds: Size,
+ shaping: Shaping,
+ point: Point,
+ nearest_only: bool,
+ ) -> Option<Hit>;
+
+ /// Loads a [`Self::Font`] from its bytes.
+ fn load_font(&mut self, font: Cow<'static, [u8]>);
+
+ /// Draws the given [`Text`].
+ fn fill_text(&mut self, text: Text<'_, Self::Font>);
+}
diff --git a/native/src/touch.rs b/core/src/touch.rs
index 18120644..18120644 100644
--- a/native/src/touch.rs
+++ b/core/src/touch.rs
diff --git a/native/src/widget.rs b/core/src/widget.rs
index 6b83f1fa..769f8659 100644
--- a/native/src/widget.rs
+++ b/core/src/widget.rs
@@ -1,101 +1,21 @@
-//! Use the built-in widgets or create your own.
-//!
-//! # Built-in widgets
-//! Every built-in drawable widget has its own module with a `Renderer` trait
-//! that must be implemented by a [renderer] before being able to use it as
-//! a [`Widget`].
-//!
-//! # Custom widgets
-//! If you want to implement a custom widget, you simply need to implement the
-//! [`Widget`] trait. You can use the API of the built-in widgets as a guide or
-//! source of inspiration.
-//!
-//! [renderer]: crate::renderer
-pub mod button;
-pub mod checkbox;
-pub mod column;
-pub mod container;
-pub mod helpers;
-pub mod image;
-pub mod mouse_area;
+//! Create custom widgets and operate on them.
pub mod operation;
-pub mod pane_grid;
-pub mod pick_list;
-pub mod progress_bar;
-pub mod radio;
-pub mod row;
-pub mod rule;
-pub mod scrollable;
-pub mod slider;
-pub mod space;
-pub mod svg;
pub mod text;
-pub mod text_input;
-pub mod toggler;
-pub mod tooltip;
pub mod tree;
-pub mod vertical_slider;
-mod action;
mod id;
-#[doc(no_inline)]
-pub use button::Button;
-#[doc(no_inline)]
-pub use checkbox::Checkbox;
-#[doc(no_inline)]
-pub use column::Column;
-#[doc(no_inline)]
-pub use container::Container;
-#[doc(no_inline)]
-pub use helpers::*;
-#[doc(no_inline)]
-pub use image::Image;
-#[doc(no_inline)]
-pub use mouse_area::MouseArea;
-#[doc(no_inline)]
-pub use pane_grid::PaneGrid;
-#[doc(no_inline)]
-pub use pick_list::PickList;
-#[doc(no_inline)]
-pub use progress_bar::ProgressBar;
-#[doc(no_inline)]
-pub use radio::Radio;
-#[doc(no_inline)]
-pub use row::Row;
-#[doc(no_inline)]
-pub use rule::Rule;
-#[doc(no_inline)]
-pub use scrollable::Scrollable;
-#[doc(no_inline)]
-pub use slider::Slider;
-#[doc(no_inline)]
-pub use space::Space;
-#[doc(no_inline)]
-pub use svg::Svg;
-#[doc(no_inline)]
-pub use text::Text;
-#[doc(no_inline)]
-pub use text_input::TextInput;
-#[doc(no_inline)]
-pub use toggler::Toggler;
-#[doc(no_inline)]
-pub use tooltip::Tooltip;
-#[doc(no_inline)]
-pub use tree::Tree;
-#[doc(no_inline)]
-pub use vertical_slider::VerticalSlider;
-
-pub use action::Action;
pub use id::Id;
pub use operation::Operation;
+pub use text::Text;
+pub use tree::Tree;
use crate::event::{self, Event};
-use crate::layout;
+use crate::layout::{self, Layout};
use crate::mouse;
use crate::overlay;
use crate::renderer;
-use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell};
+use crate::{Clipboard, Length, Point, Rectangle, Shell};
/// A component that displays information and allows interaction.
///
diff --git a/native/src/widget/id.rs b/core/src/widget/id.rs
index 4b8fedf1..ae739bb7 100644
--- a/native/src/widget/id.rs
+++ b/core/src/widget/id.rs
@@ -24,7 +24,7 @@ impl Id {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Internal {
+enum Internal {
Unique(usize),
Custom(borrow::Cow<'static, str>),
}
diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs
new file mode 100644
index 00000000..ad188c36
--- /dev/null
+++ b/core/src/widget/operation.rs
@@ -0,0 +1,226 @@
+//! Query or update internal widget state.
+pub mod focusable;
+pub mod scrollable;
+pub mod text_input;
+
+pub use focusable::Focusable;
+pub use scrollable::Scrollable;
+pub use text_input::TextInput;
+
+use crate::widget::Id;
+
+use std::any::Any;
+use std::fmt;
+use std::rc::Rc;
+
+/// A piece of logic that can traverse the widget tree of an application in
+/// order to query or update some widget state.
+pub trait Operation<T> {
+ /// Operates on a widget that contains other widgets.
+ ///
+ /// The `operate_on_children` function can be called to return control to
+ /// the widget tree and keep traversing it.
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
+ );
+
+ /// Operates on a widget that can be focused.
+ fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {}
+
+ /// Operates on a widget that can be scrolled.
+ fn scrollable(&mut self, _state: &mut dyn Scrollable, _id: Option<&Id>) {}
+
+ /// Operates on a widget that has text input.
+ fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {}
+
+ /// Operates on a custom widget with some state.
+ fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {}
+
+ /// Finishes the [`Operation`] and returns its [`Outcome`].
+ fn finish(&self) -> Outcome<T> {
+ Outcome::None
+ }
+}
+
+/// The result of an [`Operation`].
+pub enum Outcome<T> {
+ /// The [`Operation`] produced no result.
+ None,
+
+ /// The [`Operation`] produced some result.
+ Some(T),
+
+ /// The [`Operation`] needs to be followed by another [`Operation`].
+ Chain(Box<dyn Operation<T>>),
+}
+
+impl<T> fmt::Debug for Outcome<T>
+where
+ T: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::None => write!(f, "Outcome::None"),
+ Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
+ Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
+ }
+ }
+}
+
+/// Maps the output of an [`Operation`] using the given function.
+pub fn map<A, B>(
+ operation: Box<dyn Operation<A>>,
+ f: impl Fn(A) -> B + 'static,
+) -> impl Operation<B>
+where
+ A: 'static,
+ B: 'static,
+{
+ #[allow(missing_debug_implementations)]
+ struct Map<A, B> {
+ operation: Box<dyn Operation<A>>,
+ f: Rc<dyn Fn(A) -> B>,
+ }
+
+ impl<A, B> Operation<B> for Map<A, B>
+ where
+ A: 'static,
+ B: 'static,
+ {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
+ ) {
+ struct MapRef<'a, A> {
+ operation: &'a mut dyn Operation<A>,
+ }
+
+ impl<'a, A, B> Operation<B> for MapRef<'a, A> {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
+ ) {
+ let Self { operation, .. } = self;
+
+ operation.container(id, &mut |operation| {
+ operate_on_children(&mut MapRef { operation });
+ });
+ }
+
+ fn scrollable(
+ &mut self,
+ state: &mut dyn Scrollable,
+ id: Option<&Id>,
+ ) {
+ self.operation.scrollable(state, id);
+ }
+
+ fn focusable(
+ &mut self,
+ state: &mut dyn Focusable,
+ id: Option<&Id>,
+ ) {
+ self.operation.focusable(state, id);
+ }
+
+ fn text_input(
+ &mut self,
+ state: &mut dyn TextInput,
+ id: Option<&Id>,
+ ) {
+ self.operation.text_input(state, id);
+ }
+
+ fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
+ self.operation.custom(state, id);
+ }
+ }
+
+ let Self { operation, .. } = self;
+
+ MapRef {
+ operation: operation.as_mut(),
+ }
+ .container(id, operate_on_children);
+ }
+
+ fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
+ self.operation.focusable(state, id);
+ }
+
+ fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) {
+ self.operation.scrollable(state, id);
+ }
+
+ fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
+ self.operation.text_input(state, id);
+ }
+
+ fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
+ self.operation.custom(state, id);
+ }
+
+ fn finish(&self) -> Outcome<B> {
+ match self.operation.finish() {
+ Outcome::None => Outcome::None,
+ Outcome::Some(output) => Outcome::Some((self.f)(output)),
+ Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
+ operation: next,
+ f: self.f.clone(),
+ })),
+ }
+ }
+ }
+
+ Map {
+ operation,
+ f: Rc::new(f),
+ }
+}
+
+/// Produces an [`Operation`] that applies the given [`Operation`] to the
+/// children of a container with the given [`Id`].
+pub fn scope<T: 'static>(
+ target: Id,
+ operation: impl Operation<T> + 'static,
+) -> impl Operation<T> {
+ struct ScopedOperation<Message> {
+ target: Id,
+ operation: Box<dyn Operation<Message>>,
+ }
+
+ impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<Message>),
+ ) {
+ if id == Some(&self.target) {
+ operate_on_children(self.operation.as_mut());
+ } else {
+ operate_on_children(self);
+ }
+ }
+
+ fn finish(&self) -> Outcome<Message> {
+ match self.operation.finish() {
+ Outcome::Chain(next) => {
+ Outcome::Chain(Box::new(ScopedOperation {
+ target: self.target.clone(),
+ operation: next,
+ }))
+ }
+ outcome => outcome,
+ }
+ }
+ }
+
+ ScopedOperation {
+ target,
+ operation: Box::new(operation),
+ }
+}
diff --git a/native/src/widget/operation/focusable.rs b/core/src/widget/operation/focusable.rs
index 312e4894..312e4894 100644
--- a/native/src/widget/operation/focusable.rs
+++ b/core/src/widget/operation/focusable.rs
diff --git a/native/src/widget/operation/scrollable.rs b/core/src/widget/operation/scrollable.rs
index f947344d..f947344d 100644
--- a/native/src/widget/operation/scrollable.rs
+++ b/core/src/widget/operation/scrollable.rs
diff --git a/native/src/widget/operation/text_input.rs b/core/src/widget/operation/text_input.rs
index 4c773e99..4c773e99 100644
--- a/native/src/widget/operation/text_input.rs
+++ b/core/src/widget/operation/text_input.rs
diff --git a/native/src/widget/text.rs b/core/src/widget/text.rs
index 3fee48f2..90af88b7 100644
--- a/native/src/widget/text.rs
+++ b/core/src/widget/text.rs
@@ -4,27 +4,15 @@ use crate::layout;
use crate::renderer;
use crate::text;
use crate::widget::Tree;
-use crate::{Element, Layout, Length, Pixels, Point, Rectangle, Size, Widget};
+use crate::{
+ Color, Element, Layout, Length, Pixels, Point, Rectangle, Size, Widget,
+};
use std::borrow::Cow;
-pub use iced_style::text::{Appearance, StyleSheet};
+pub use text::{LineHeight, Shaping};
/// A paragraph of text.
-///
-/// # Example
-///
-/// ```
-/// # use iced_native::Color;
-/// #
-/// # type Text<'a> = iced_native::widget::Text<'a, iced_native::renderer::Null>;
-/// #
-/// Text::new("I <3 iced!")
-/// .size(40)
-/// .style(Color::from([0.0, 0.0, 1.0]));
-/// ```
-///
-/// ![Text drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text.png?raw=true)
#[allow(missing_debug_implementations)]
pub struct Text<'a, Renderer>
where
@@ -33,11 +21,13 @@ where
{
content: Cow<'a, str>,
size: Option<f32>,
+ line_height: LineHeight,
width: Length,
height: Length,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
+ shaping: Shaping,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -51,11 +41,13 @@ where
Text {
content: content.into(),
size: None,
- font: Default::default(),
+ line_height: LineHeight::default(),
+ font: None,
width: Length::Shrink,
height: Length::Shrink,
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
+ shaping: Shaping::Basic,
style: Default::default(),
}
}
@@ -66,11 +58,17 @@ where
self
}
+ /// Sets the [`LineHeight`] of the [`Text`].
+ pub fn line_height(mut self, line_height: impl Into<LineHeight>) -> Self {
+ self.line_height = line_height.into();
+ self
+ }
+
/// Sets the [`Font`] of the [`Text`].
///
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
- self.font = font.into();
+ self.font = Some(font.into());
self
}
@@ -112,6 +110,12 @@ where
self.vertical_alignment = alignment;
self
}
+
+ /// Sets the [`Shaping`] strategy of the [`Text`].
+ pub fn shaping(mut self, shaping: Shaping) -> Self {
+ self.shaping = shaping;
+ self
+ }
}
impl<'a, Message, Renderer> Widget<Message, Renderer> for Text<'a, Renderer>
@@ -138,8 +142,14 @@ where
let bounds = limits.max();
- let (width, height) =
- renderer.measure(&self.content, size, self.font.clone(), bounds);
+ let (width, height) = renderer.measure(
+ &self.content,
+ size,
+ self.line_height,
+ self.font.unwrap_or_else(|| renderer.default_font()),
+ bounds,
+ self.shaping,
+ );
let size = limits.resolve(Size::new(width, height));
@@ -162,10 +172,12 @@ where
layout,
&self.content,
self.size,
- self.font.clone(),
- theme.appearance(self.style),
+ self.line_height,
+ self.font,
+ theme.appearance(self.style.clone()),
self.horizontal_alignment,
self.vertical_alignment,
+ self.shaping,
);
}
}
@@ -186,10 +198,12 @@ pub fn draw<Renderer>(
layout: Layout<'_>,
content: &str,
size: Option<f32>,
- font: Renderer::Font,
+ line_height: LineHeight,
+ font: Option<Renderer::Font>,
appearance: Appearance,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
+ shaping: Shaping,
) where
Renderer: text::Renderer,
{
@@ -207,14 +221,18 @@ pub fn draw<Renderer>(
alignment::Vertical::Bottom => bounds.y + bounds.height,
};
- renderer.fill_text(crate::text::Text {
+ let size = size.unwrap_or_else(|| renderer.default_size());
+
+ renderer.fill_text(crate::Text {
content,
- size: size.unwrap_or_else(|| renderer.default_size()),
+ size,
+ line_height,
bounds: Rectangle { x, y, ..bounds },
color: appearance.color.unwrap_or(style.text_color),
- font,
+ font: font.unwrap_or_else(|| renderer.default_font()),
horizontal_alignment,
vertical_alignment,
+ shaping,
});
}
@@ -238,22 +256,52 @@ where
Self {
content: self.content.clone(),
size: self.size,
+ line_height: self.line_height,
width: self.width,
height: self.height,
horizontal_alignment: self.horizontal_alignment,
vertical_alignment: self.vertical_alignment,
- font: self.font.clone(),
- style: self.style,
+ font: self.font,
+ style: self.style.clone(),
+ shaping: self.shaping,
}
}
}
+impl<'a, Renderer> From<&'a str> for Text<'a, Renderer>
+where
+ Renderer: text::Renderer,
+ Renderer::Theme: StyleSheet,
+{
+ fn from(content: &'a str) -> Self {
+ Self::new(content)
+ }
+}
+
impl<'a, Message, Renderer> From<&'a str> for Element<'a, Message, Renderer>
where
Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
- fn from(contents: &'a str) -> Self {
- Text::new(contents).into()
+ fn from(content: &'a str) -> Self {
+ Text::from(content).into()
}
}
+
+/// The style sheet of some text.
+pub trait StyleSheet {
+ /// The supported style of the [`StyleSheet`].
+ type Style: Default + Clone;
+
+ /// Produces the [`Appearance`] of some text.
+ fn appearance(&self, style: Self::Style) -> Appearance;
+}
+
+/// The apperance of some text.
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Appearance {
+ /// The [`Color`] of the text.
+ ///
+ /// The default, `None`, means using the inherited color.
+ pub color: Option<Color>,
+}
diff --git a/native/src/widget/tree.rs b/core/src/widget/tree.rs
index 0af40c33..0af40c33 100644
--- a/native/src/widget/tree.rs
+++ b/core/src/widget/tree.rs
diff --git a/core/src/window.rs b/core/src/window.rs
new file mode 100644
index 00000000..81bd7e3d
--- /dev/null
+++ b/core/src/window.rs
@@ -0,0 +1,13 @@
+//! Build window-based GUI applications.
+pub mod icon;
+
+mod event;
+mod mode;
+mod redraw_request;
+mod user_attention;
+
+pub use event::Event;
+pub use icon::Icon;
+pub use mode::Mode;
+pub use redraw_request::RedrawRequest;
+pub use user_attention::UserAttention;
diff --git a/native/src/window/event.rs b/core/src/window/event.rs
index e2fb5e66..e2fb5e66 100644
--- a/native/src/window/event.rs
+++ b/core/src/window/event.rs
diff --git a/native/src/window/icon.rs b/core/src/window/icon.rs
index 31868ecf..31868ecf 100644
--- a/native/src/window/icon.rs
+++ b/core/src/window/icon.rs
diff --git a/native/src/window/mode.rs b/core/src/window/mode.rs
index fdce8e23..fdce8e23 100644
--- a/native/src/window/mode.rs
+++ b/core/src/window/mode.rs
diff --git a/native/src/window/redraw_request.rs b/core/src/window/redraw_request.rs
index 3b4f0fd3..3b4f0fd3 100644
--- a/native/src/window/redraw_request.rs
+++ b/core/src/window/redraw_request.rs
diff --git a/native/src/window/user_attention.rs b/core/src/window/user_attention.rs
index b03dfeef..b03dfeef 100644
--- a/native/src/window/user_attention.rs
+++ b/core/src/window/user_attention.rs