From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- core/src/text.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 core/src/text.rs (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs new file mode 100644 index 00000000..4c72abc3 --- /dev/null +++ b/core/src/text.rs @@ -0,0 +1,111 @@ +//! Draw and interact with text. +use crate::alignment; +use crate::{Color, Point, Rectangle, Size}; + +use std::borrow::Cow; + +/// 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`]. + pub size: f32, + + /// 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 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, + font: Self::Font, + bounds: Size, + ) -> (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) -> f32 { + let (width, _) = self.measure(content, size, font, Size::INFINITY); + + 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, + font: Self::Font, + bounds: Size, + point: Point, + nearest_only: bool, + ) -> Option; + + /// 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>); +} -- cgit From 33b5a900197e2798a393d6d9a0834039666eddbb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 01:19:56 +0200 Subject: Make basic text shaping the default shaping strategy --- core/src/text.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs index 4c72abc3..0111cf31 100644 --- a/core/src/text.rs +++ b/core/src/text.rs @@ -27,6 +27,15 @@ pub struct Text<'a, Font> { /// The vertical alignment of the [`Text`]. pub vertical_alignment: alignment::Vertical, + + /// Whether the [`Text`] needs advanced 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. + pub advanced_shape: bool, } /// The result of hit testing on text. @@ -77,11 +86,19 @@ pub trait Renderer: crate::Renderer { size: f32, font: Self::Font, bounds: Size, + advanced_shape: bool, ) -> (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) -> f32 { - let (width, _) = self.measure(content, size, font, Size::INFINITY); + fn measure_width( + &self, + content: &str, + size: f32, + font: Self::Font, + advanced_shape: bool, + ) -> f32 { + let (width, _) = + self.measure(content, size, font, Size::INFINITY, advanced_shape); width } @@ -101,6 +118,7 @@ pub trait Renderer: crate::Renderer { bounds: Size, point: Point, nearest_only: bool, + advanced_shape: bool, ) -> Option; /// Loads a [`Self::Font`] from its bytes. -- cgit From 4bd290afe7d81d9aaf7467b3ce91491f6600261a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 02:00:45 +0200 Subject: Introduce `text::Shaping` enum and replace magic boolean --- core/src/text.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs index 0111cf31..c59d8fce 100644 --- a/core/src/text.rs +++ b/core/src/text.rs @@ -28,14 +28,32 @@ pub struct Text<'a, Font> { /// The vertical alignment of the [`Text`]. pub vertical_alignment: alignment::Vertical, - /// Whether the [`Text`] needs advanced shaping and font fallback. + /// 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. - pub advanced_shape: bool, + Advanced, } /// The result of hit testing on text. @@ -86,7 +104,7 @@ pub trait Renderer: crate::Renderer { size: f32, font: Self::Font, bounds: Size, - advanced_shape: bool, + shaping: Shaping, ) -> (f32, f32); /// Measures the width of the text as if it were laid out in a single line. @@ -95,10 +113,10 @@ pub trait Renderer: crate::Renderer { content: &str, size: f32, font: Self::Font, - advanced_shape: bool, + shaping: Shaping, ) -> f32 { let (width, _) = - self.measure(content, size, font, Size::INFINITY, advanced_shape); + self.measure(content, size, font, Size::INFINITY, shaping); width } @@ -116,9 +134,9 @@ pub trait Renderer: crate::Renderer { size: f32, font: Self::Font, bounds: Size, + shaping: Shaping, point: Point, nearest_only: bool, - advanced_shape: bool, ) -> Option; /// Loads a [`Self::Font`] from its bytes. -- cgit From 9499a8f9e6f9971dedfae563cb133232aa3cebc2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 May 2023 13:00:16 +0200 Subject: Support configurable `LineHeight` in text widgets --- core/src/text.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 4 deletions(-) (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs index c59d8fce..1a867be3 100644 --- a/core/src/text.rs +++ b/core/src/text.rs @@ -1,8 +1,9 @@ //! Draw and interact with text. use crate::alignment; -use crate::{Color, Point, Rectangle, Size}; +use crate::{Color, Pixels, Point, Rectangle, Size}; use std::borrow::Cow; +use std::hash::{Hash, Hasher}; /// A paragraph. #[derive(Debug, Clone, Copy)] @@ -13,9 +14,12 @@ pub struct Text<'a, Font> { /// The bounds of the paragraph. pub bounds: Rectangle, - /// The size of the [`Text`]. + /// 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, @@ -56,6 +60,59 @@ pub enum Shaping { 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.2) + } +} + +impl From for LineHeight { + fn from(factor: f32) -> Self { + Self::Relative(factor) + } +} + +impl From for LineHeight { + fn from(pixels: Pixels) -> Self { + Self::Absolute(pixels) + } +} + +impl Hash for LineHeight { + fn hash(&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 { @@ -102,6 +159,7 @@ pub trait Renderer: crate::Renderer { &self, content: &str, size: f32, + line_height: LineHeight, font: Self::Font, bounds: Size, shaping: Shaping, @@ -115,8 +173,14 @@ pub trait Renderer: crate::Renderer { font: Self::Font, shaping: Shaping, ) -> f32 { - let (width, _) = - self.measure(content, size, font, Size::INFINITY, shaping); + let (width, _) = self.measure( + content, + size, + LineHeight::Absolute(Pixels(size)), + font, + Size::INFINITY, + shaping, + ); width } @@ -132,6 +196,7 @@ pub trait Renderer: crate::Renderer { &self, contents: &str, size: f32, + line_height: LineHeight, font: Self::Font, bounds: Size, shaping: Shaping, -- cgit From f75b8bd9ec4677b4469910b91ca2aa9ec5636e7e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 May 2023 00:13:51 +0200 Subject: Increase default `LineHeight` to `Relative(1.3)` --- core/src/text.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs index 1a867be3..c154cc27 100644 --- a/core/src/text.rs +++ b/core/src/text.rs @@ -82,7 +82,7 @@ impl LineHeight { impl Default for LineHeight { fn default() -> Self { - Self::Relative(1.2) + Self::Relative(1.3) } } -- cgit From 78ad365db232e53cbdf12105e40c1dbe87a3238c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 28 Jun 2023 00:35:37 +0200 Subject: Reuse entries in `text::Cache` in `iced_wgpu` --- core/src/text.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'core/src/text.rs') diff --git a/core/src/text.rs b/core/src/text.rs index c154cc27..fc8aa20e 100644 --- a/core/src/text.rs +++ b/core/src/text.rs @@ -163,7 +163,7 @@ pub trait Renderer: crate::Renderer { font: Self::Font, bounds: Size, shaping: Shaping, - ) -> (f32, f32); + ) -> Size; /// Measures the width of the text as if it were laid out in a single line. fn measure_width( @@ -173,7 +173,7 @@ pub trait Renderer: crate::Renderer { font: Self::Font, shaping: Shaping, ) -> f32 { - let (width, _) = self.measure( + let bounds = self.measure( content, size, LineHeight::Absolute(Pixels(size)), @@ -182,7 +182,7 @@ pub trait Renderer: crate::Renderer { shaping, ); - width + bounds.width } /// Tests whether the provided point is within the boundaries of text -- cgit