Introduce text::Shaping enum and replace magic boolean

This commit is contained in:
Héctor Ramón Jiménez 2023-04-19 02:00:45 +02:00
parent 33b5a90019
commit 4bd290afe7
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
25 changed files with 203 additions and 132 deletions

View file

@ -62,7 +62,7 @@ impl text::Renderer for Null {
_size: f32, _size: f32,
_font: Font, _font: Font,
_bounds: Size, _bounds: Size,
_needs_shaping: bool, _shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
(0.0, 20.0) (0.0, 20.0)
} }
@ -73,9 +73,9 @@ impl text::Renderer for Null {
_size: f32, _size: f32,
_font: Self::Font, _font: Self::Font,
_bounds: Size, _bounds: Size,
_shaping: text::Shaping,
_point: Point, _point: Point,
_nearest_only: bool, _nearest_only: bool,
_advanced_shape: bool,
) -> Option<text::Hit> { ) -> Option<text::Hit> {
None None
} }

View file

@ -28,14 +28,32 @@ pub struct Text<'a, Font> {
/// The vertical alignment of the [`Text`]. /// The vertical alignment of the [`Text`].
pub vertical_alignment: alignment::Vertical, 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 /// 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 /// script, the font used needs it, and/or multiple fonts in your system
/// may be needed to display all of the glyphs. /// may be needed to display all of the glyphs.
/// ///
/// Advanced shaping is expensive! You should only enable it when necessary. /// Advanced shaping is expensive! You should only enable it when necessary.
pub advanced_shape: bool, Advanced,
} }
/// The result of hit testing on text. /// The result of hit testing on text.
@ -86,7 +104,7 @@ pub trait Renderer: crate::Renderer {
size: f32, size: f32,
font: Self::Font, font: Self::Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: Shaping,
) -> (f32, f32); ) -> (f32, f32);
/// Measures the width of the text as if it were laid out in a single line. /// 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, content: &str,
size: f32, size: f32,
font: Self::Font, font: Self::Font,
advanced_shape: bool, shaping: Shaping,
) -> f32 { ) -> f32 {
let (width, _) = let (width, _) =
self.measure(content, size, font, Size::INFINITY, advanced_shape); self.measure(content, size, font, Size::INFINITY, shaping);
width width
} }
@ -116,9 +134,9 @@ pub trait Renderer: crate::Renderer {
size: f32, size: f32,
font: Self::Font, font: Self::Font,
bounds: Size, bounds: Size,
shaping: Shaping,
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<Hit>; ) -> Option<Hit>;
/// Loads a [`Self::Font`] from its bytes. /// Loads a [`Self::Font`] from its bytes.

View file

@ -24,8 +24,8 @@ where
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
shaping: text::Shaping,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
advanced_shape: bool,
} }
impl<'a, Renderer> Text<'a, Renderer> impl<'a, Renderer> Text<'a, Renderer>
@ -43,8 +43,8 @@ where
height: Length::Shrink, height: Length::Shrink,
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
shaping: text::Shaping::Basic,
style: Default::default(), style: Default::default(),
advanced_shape: false,
} }
} }
@ -101,17 +101,9 @@ where
self self
} }
/// Enables advanced text shaping and font fallback for the [`Text`]. /// Sets the [`text::Shaping`] strategy of the [`Text`].
/// pub fn shaping(mut self, shaping: text::Shaping) -> Self {
/// You will need to enable this if the text contains a complex script, the self.shaping = shaping;
/// font used needs it, and/or multiple fonts in your system may be needed
/// to display all of the glyphs.
///
/// If your text isn't displaying properly, try enabling this!
///
/// Advanced shaping is expensive! You should only enable it when necessary.
pub fn advanced_shape(mut self) -> Self {
self.advanced_shape = true;
self self
} }
} }
@ -145,7 +137,7 @@ where
size, size,
self.font.unwrap_or_else(|| renderer.default_font()), self.font.unwrap_or_else(|| renderer.default_font()),
bounds, bounds,
self.advanced_shape, self.shaping,
); );
let size = limits.resolve(Size::new(width, height)); let size = limits.resolve(Size::new(width, height));
@ -173,7 +165,7 @@ where
theme.appearance(self.style.clone()), theme.appearance(self.style.clone()),
self.horizontal_alignment, self.horizontal_alignment,
self.vertical_alignment, self.vertical_alignment,
self.advanced_shape, self.shaping,
); );
} }
} }
@ -198,7 +190,7 @@ pub fn draw<Renderer>(
appearance: Appearance, appearance: Appearance,
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
advanced_shape: bool, shaping: text::Shaping,
) where ) where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
@ -224,7 +216,7 @@ pub fn draw<Renderer>(
font: font.unwrap_or_else(|| renderer.default_font()), font: font.unwrap_or_else(|| renderer.default_font()),
horizontal_alignment, horizontal_alignment,
vertical_alignment, vertical_alignment,
advanced_shape, shaping,
}); });
} }
@ -254,7 +246,7 @@ where
vertical_alignment: self.vertical_alignment, vertical_alignment: self.vertical_alignment,
font: self.font, font: self.font,
style: self.style.clone(), style: self.style.clone(),
advanced_shape: self.advanced_shape, shaping: self.shaping,
} }
} }
} }

View file

@ -364,7 +364,8 @@ impl Task {
self.completed, self.completed,
TaskMessage::Completed, TaskMessage::Completed,
) )
.width(Length::Fill); .width(Length::Fill)
.text_shaping(text::Shaping::Advanced);
row![ row![
checkbox, checkbox,

View file

@ -48,7 +48,7 @@ pub trait Text {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: text::Shaping,
) -> (f32, f32); ) -> (f32, f32);
/// Tests whether the provided point is within the boundaries of [`Text`] /// Tests whether the provided point is within the boundaries of [`Text`]
@ -64,9 +64,9 @@ pub trait Text {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping,
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<text::Hit>; ) -> Option<text::Hit>;
/// Loads a [`Font`] from its bytes. /// Loads a [`Font`] from its bytes.

View file

@ -1,5 +1,6 @@
use iced_core::alignment; use crate::core::alignment;
use iced_core::{Color, Font, Point}; use crate::core::text::Shaping;
use crate::core::{Color, Font, Point};
/// A bunch of text that can be drawn to a canvas /// A bunch of text that can be drawn to a canvas
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -25,15 +26,8 @@ pub struct Text {
pub horizontal_alignment: alignment::Horizontal, pub horizontal_alignment: alignment::Horizontal,
/// The vertical alignment of the text /// The vertical alignment of the text
pub vertical_alignment: alignment::Vertical, pub vertical_alignment: alignment::Vertical,
/// Whether the text needs advanced shaping and font fallback. /// The shaping strategy of the text.
/// pub shaping: Shaping,
/// 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,
} }
impl Default for Text { impl Default for Text {
@ -46,7 +40,7 @@ impl Default for Text {
font: Font::default(), font: Font::default(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
advanced_shape: false, shaping: Shaping::Basic,
} }
} }
} }

View file

@ -1,7 +1,8 @@
use iced_core::alignment; use crate::core::alignment;
use iced_core::image; use crate::core::image;
use iced_core::svg; use crate::core::svg;
use iced_core::{Background, Color, Font, Gradient, Rectangle, Size, Vector}; use crate::core::text;
use crate::core::{Background, Color, Font, Gradient, Rectangle, Size, Vector};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use std::sync::Arc; use std::sync::Arc;
@ -26,15 +27,8 @@ pub enum Primitive {
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
/// The vertical alignment of the text /// The vertical alignment of the text
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
/// Whether the text needs advanced shaping and font fallback. /// The shaping strategy of the text.
/// shaping: text::Shaping,
/// 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_shape: bool,
}, },
/// A quad primitive /// A quad primitive
Quad { Quad {

View file

@ -138,10 +138,9 @@ where
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
needs_shaping: bool, shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.backend() self.backend().measure(content, size, font, bounds, shaping)
.measure(content, size, font, bounds, needs_shaping)
} }
fn hit_test( fn hit_test(
@ -150,18 +149,18 @@ where
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping,
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<text::Hit> { ) -> Option<text::Hit> {
self.backend().hit_test( self.backend().hit_test(
content, content,
size, size,
font, font,
bounds, bounds,
shaping,
point, point,
nearest_only, nearest_only,
advanced_shape,
) )
} }
@ -178,7 +177,7 @@ where
font: text.font, font: text.font,
horizontal_alignment: text.horizontal_alignment, horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment, vertical_alignment: text.vertical_alignment,
advanced_shape: text.advanced_shape, shaping: text.shaping,
}); });
} }
} }

View file

@ -48,12 +48,12 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
delegate!( delegate!(
self, self,
backend, backend,
backend.measure(contents, size, font, bounds, advanced_shape) backend.measure(contents, size, font, bounds, shaping)
) )
} }
@ -63,9 +63,9 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping,
position: Point, position: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<text::Hit> { ) -> Option<text::Hit> {
delegate!( delegate!(
self, self,
@ -75,9 +75,9 @@ impl backend::Text for Backend {
size, size,
font, font,
bounds, bounds,
shaping,
position, position,
nearest_only, nearest_only,
advanced_shape
) )
) )
} }

View file

@ -219,7 +219,7 @@ impl Backend {
font, font,
horizontal_alignment, horizontal_alignment,
vertical_alignment, vertical_alignment,
advanced_shape, shaping,
} => { } => {
let physical_bounds = let physical_bounds =
(primitive.bounds() + translation) * scale_factor; (primitive.bounds() + translation) * scale_factor;
@ -239,7 +239,7 @@ impl Backend {
*font, *font,
*horizontal_alignment, *horizontal_alignment,
*vertical_alignment, *vertical_alignment,
*advanced_shape, *shaping,
pixels, pixels,
clip_mask, clip_mask,
); );
@ -628,10 +628,10 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.text_pipeline self.text_pipeline
.measure(contents, size, font, bounds, advanced_shape) .measure(contents, size, font, bounds, shaping)
} }
fn hit_test( fn hit_test(
@ -640,18 +640,18 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping,
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<text::Hit> { ) -> Option<text::Hit> {
self.text_pipeline.hit_test( self.text_pipeline.hit_test(
contents, contents,
size, size,
font, font,
bounds, bounds,
shaping,
point, point,
nearest_only, nearest_only,
advanced_shape,
) )
} }

View file

@ -114,7 +114,7 @@ impl Frame {
font: text.font, font: text.font,
horizontal_alignment: text.horizontal_alignment, horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment, vertical_alignment: text.vertical_alignment,
advanced_shape: text.advanced_shape, shaping: text.shaping,
}); });
} }

View file

@ -1,6 +1,6 @@
use crate::core::alignment; use crate::core::alignment;
use crate::core::font::{self, Font}; use crate::core::font::{self, Font};
use crate::core::text::Hit; use crate::core::text::{Hit, Shaping};
use crate::core::{Color, Point, Rectangle, Size}; use crate::core::{Color, Point, Rectangle, Size};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -49,7 +49,7 @@ impl Pipeline {
font: Font, font: Font,
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
advanced_shape: bool, shaping: Shaping,
pixels: &mut tiny_skia::PixmapMut<'_>, pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: Option<&tiny_skia::Mask>, clip_mask: Option<&tiny_skia::Mask>,
) { ) {
@ -64,7 +64,7 @@ impl Pipeline {
content, content,
font, font,
size, size,
advanced_shape, shaping,
}; };
let (_, buffer) = self.render_cache.allocate(font_system, key); let (_, buffer) = self.render_cache.allocate(font_system, key);
@ -132,7 +132,7 @@ impl Pipeline {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
@ -143,7 +143,7 @@ impl Pipeline {
size, size,
font, font,
bounds, bounds,
advanced_shape, shaping,
}, },
); );
@ -163,9 +163,9 @@ impl Pipeline {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping,
point: Point, point: Point,
_nearest_only: bool, _nearest_only: bool,
advanced_shape: bool,
) -> Option<Hit> { ) -> Option<Hit> {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
@ -176,7 +176,7 @@ impl Pipeline {
size, size,
font, font,
bounds, bounds,
advanced_shape, shaping,
}, },
); );
@ -396,7 +396,7 @@ impl Cache {
.family(to_family(key.font.family)) .family(to_family(key.font.family))
.weight(to_weight(key.font.weight)) .weight(to_weight(key.font.weight))
.stretch(to_stretch(key.font.stretch)), .stretch(to_stretch(key.font.stretch)),
!key.advanced_shape, matches!(key.shaping, Shaping::Basic),
); );
let _ = entry.insert(buffer); let _ = entry.insert(buffer);
@ -427,7 +427,7 @@ struct Key<'a> {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: Shaping,
} }
type KeyHash = u64; type KeyHash = u64;

Binary file not shown.

View file

@ -354,10 +354,10 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: core::text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.text_pipeline self.text_pipeline
.measure(contents, size, font, bounds, advanced_shape) .measure(contents, size, font, bounds, shaping)
} }
fn hit_test( fn hit_test(
@ -366,18 +366,18 @@ impl backend::Text for Backend {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: core::text::Shaping,
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
advanced_shape: bool,
) -> Option<core::text::Hit> { ) -> Option<core::text::Hit> {
self.text_pipeline.hit_test( self.text_pipeline.hit_test(
contents, contents,
size, size,
font, font,
bounds, bounds,
shaping,
point, point,
nearest_only, nearest_only,
advanced_shape,
) )
} }

View file

@ -334,7 +334,7 @@ impl Frame {
font: text.font, font: text.font,
horizontal_alignment: text.horizontal_alignment, horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment, vertical_alignment: text.vertical_alignment,
advanced_shape: text.advanced_shape, shaping: text.shaping,
}); });
} }

View file

@ -10,6 +10,7 @@ pub use mesh::Mesh;
pub use quad::Quad; pub use quad::Quad;
pub use text::Text; pub use text::Text;
use crate::core;
use crate::core::alignment; use crate::core::alignment;
use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector};
use crate::graphics::{Primitive, Viewport}; use crate::graphics::{Primitive, Viewport};
@ -64,7 +65,7 @@ impl<'a> Layer<'a> {
font: Font::MONOSPACE, font: Font::MONOSPACE,
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
advanced_shape: false, shaping: core::text::Shaping::Basic,
}; };
overlay.text.push(text); overlay.text.push(text);
@ -117,7 +118,7 @@ impl<'a> Layer<'a> {
font, font,
horizontal_alignment, horizontal_alignment,
vertical_alignment, vertical_alignment,
advanced_shape, shaping,
} => { } => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
@ -129,7 +130,7 @@ impl<'a> Layer<'a> {
font: *font, font: *font,
horizontal_alignment: *horizontal_alignment, horizontal_alignment: *horizontal_alignment,
vertical_alignment: *vertical_alignment, vertical_alignment: *vertical_alignment,
advanced_shape: *advanced_shape, shaping: *shaping,
}); });
} }
Primitive::Quad { Primitive::Quad {

View file

@ -1,4 +1,5 @@
use crate::core::alignment; use crate::core::alignment;
use crate::core::text;
use crate::core::{Color, Font, Rectangle}; use crate::core::{Color, Font, Rectangle};
/// A paragraph of text. /// A paragraph of text.
@ -25,13 +26,6 @@ pub struct Text<'a> {
/// The vertical alignment of the [`Text`]. /// The vertical alignment of the [`Text`].
pub vertical_alignment: alignment::Vertical, pub vertical_alignment: alignment::Vertical,
/// Whether the text needs advanced shaping and font fallback. /// The shaping strategy of the text.
/// pub shaping: text::Shaping,
/// 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,
} }

View file

@ -1,6 +1,6 @@
use crate::core::alignment; use crate::core::alignment;
use crate::core::font::{self, Font}; use crate::core::font::{self, Font};
use crate::core::text::Hit; use crate::core::text::{Hit, Shaping};
use crate::core::{Point, Rectangle, Size}; use crate::core::{Point, Rectangle, Size};
use crate::layer::Text; use crate::layer::Text;
@ -83,7 +83,7 @@ impl Pipeline {
height: (section.bounds.height * scale_factor) height: (section.bounds.height * scale_factor)
.ceil(), .ceil(),
}, },
advanced_shape: section.advanced_shape, shaping: section.shaping,
}, },
); );
@ -214,7 +214,7 @@ impl Pipeline {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
@ -225,7 +225,7 @@ impl Pipeline {
size, size,
font, font,
bounds, bounds,
advanced_shape, shaping,
}, },
); );
@ -245,9 +245,9 @@ impl Pipeline {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping,
point: Point, point: Point,
_nearest_only: bool, _nearest_only: bool,
advanced_shape: bool,
) -> Option<Hit> { ) -> Option<Hit> {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
@ -258,7 +258,7 @@ impl Pipeline {
size, size,
font, font,
bounds, bounds,
advanced_shape, shaping,
}, },
); );
@ -369,7 +369,7 @@ impl Cache {
.family(to_family(key.font.family)) .family(to_family(key.font.family))
.weight(to_weight(key.font.weight)) .weight(to_weight(key.font.weight))
.stretch(to_stretch(key.font.stretch)), .stretch(to_stretch(key.font.stretch)),
!key.advanced_shape, matches!(key.shaping, Shaping::Basic),
); );
let _ = entry.insert(buffer); let _ = entry.insert(buffer);
@ -394,7 +394,7 @@ struct Key<'a> {
size: f32, size: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
advanced_shape: bool, shaping: Shaping,
} }
type KeyHash = u64; type KeyHash = u64;

View file

@ -46,6 +46,7 @@ where
size: f32, size: f32,
spacing: f32, spacing: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
icon: Icon<Renderer::Font>, icon: Icon<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -82,11 +83,13 @@ where
size: Self::DEFAULT_SIZE, size: Self::DEFAULT_SIZE,
spacing: Self::DEFAULT_SPACING, spacing: Self::DEFAULT_SPACING,
text_size: None, text_size: None,
text_shaping: text::Shaping::Basic,
font: None, font: None,
icon: Icon { icon: Icon {
font: Renderer::ICON_FONT, font: Renderer::ICON_FONT,
code_point: Renderer::CHECKMARK_ICON, code_point: Renderer::CHECKMARK_ICON,
size: None, size: None,
shaping: text::Shaping::Basic,
}, },
style: Default::default(), style: Default::default(),
} }
@ -116,6 +119,12 @@ where
self self
} }
/// Sets the [`text::Shaping`] strategy of the [`Checkbox`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping;
self
}
/// Sets the [`Font`] of the text of the [`Checkbox`]. /// Sets the [`Font`] of the text of the [`Checkbox`].
/// ///
/// [`Font`]: crate::text::Renderer::Font /// [`Font`]: crate::text::Renderer::Font
@ -171,7 +180,8 @@ where
.size( .size(
self.text_size self.text_size
.unwrap_or_else(|| renderer.default_size()), .unwrap_or_else(|| renderer.default_size()),
), )
.shaping(self.text_shaping),
) )
.layout(renderer, limits) .layout(renderer, limits)
} }
@ -257,6 +267,7 @@ where
font, font,
code_point, code_point,
size, size,
shaping,
} = &self.icon; } = &self.icon;
let size = size.unwrap_or(bounds.height * 0.7); let size = size.unwrap_or(bounds.height * 0.7);
@ -273,7 +284,7 @@ where
color: custom_style.icon_color, color: custom_style.icon_color,
horizontal_alignment: alignment::Horizontal::Center, horizontal_alignment: alignment::Horizontal::Center,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
advanced_shape: true, shaping: *shaping,
}); });
} }
} }
@ -293,7 +304,7 @@ where
}, },
alignment::Horizontal::Left, alignment::Horizontal::Left,
alignment::Vertical::Center, alignment::Vertical::Center,
false, self.text_shaping,
); );
} }
} }
@ -322,4 +333,6 @@ pub struct Icon<Font> {
pub code_point: char, pub code_point: char,
/// Font size of the content. /// Font size of the content.
pub size: Option<f32>, pub size: Option<f32>,
/// The shaping strategy of the icon.
pub shaping: text::Shaping,
} }

View file

@ -31,6 +31,7 @@ where
width: f32, width: f32,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
} }
@ -58,6 +59,7 @@ where
width: 0.0, width: 0.0,
padding: Padding::ZERO, padding: Padding::ZERO,
text_size: None, text_size: None,
text_shaping: text::Shaping::Basic,
font: None, font: None,
style: Default::default(), style: Default::default(),
} }
@ -81,6 +83,12 @@ where
self self
} }
/// Sets the [`text::Shaping`] strategy of the [`Menu`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping;
self
}
/// Sets the font of the [`Menu`]. /// Sets the font of the [`Menu`].
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
self.font = Some(font.into()); self.font = Some(font.into());
@ -168,6 +176,7 @@ where
padding, padding,
font, font,
text_size, text_size,
text_shaping,
style, style,
} = menu; } = menu;
@ -177,6 +186,7 @@ where
last_selection, last_selection,
font, font,
text_size, text_size,
text_shaping,
padding, padding,
style: style.clone(), style: style.clone(),
})); }));
@ -311,6 +321,7 @@ where
last_selection: &'a mut Option<T>, last_selection: &'a mut Option<T>,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
} }
@ -500,7 +511,7 @@ where
}, },
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
advanced_shape: false, shaping: self.text_shaping,
}); });
} }
} }

View file

@ -36,6 +36,7 @@ where
width: Length, width: Length,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
handle: Handle<Renderer::Font>, handle: Handle<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -71,6 +72,7 @@ where
width: Length::Shrink, width: Length::Shrink,
padding: Self::DEFAULT_PADDING, padding: Self::DEFAULT_PADDING,
text_size: None, text_size: None,
text_shaping: text::Shaping::Basic,
font: None, font: None,
handle: Default::default(), handle: Default::default(),
style: Default::default(), style: Default::default(),
@ -101,6 +103,12 @@ where
self self
} }
/// Sets the [`text::Shaping`] strategy of the [`PickList`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping;
self
}
/// Sets the font of the [`PickList`]. /// Sets the font of the [`PickList`].
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
self.font = Some(font.into()); self.font = Some(font.into());
@ -164,6 +172,7 @@ where
self.width, self.width,
self.padding, self.padding,
self.text_size, self.text_size,
self.text_shaping,
self.font, self.font,
self.placeholder.as_deref(), self.placeholder.as_deref(),
&self.options, &self.options,
@ -221,6 +230,7 @@ where
cursor_position, cursor_position,
self.padding, self.padding,
self.text_size, self.text_size,
self.text_shaping,
font, font,
self.placeholder.as_deref(), self.placeholder.as_deref(),
self.selected.as_ref(), self.selected.as_ref(),
@ -243,6 +253,7 @@ where
state, state,
self.padding, self.padding,
self.text_size, self.text_size,
self.text_shaping,
self.font.unwrap_or_else(|| renderer.default_font()), self.font.unwrap_or_else(|| renderer.default_font()),
&self.options, &self.options,
self.style.clone(), self.style.clone(),
@ -336,6 +347,8 @@ pub struct Icon<Font> {
pub code_point: char, pub code_point: char,
/// Font size of the content. /// Font size of the content.
pub size: Option<f32>, pub size: Option<f32>,
/// The shaping strategy of the icon.
pub shaping: text::Shaping,
} }
/// Computes the layout of a [`PickList`]. /// Computes the layout of a [`PickList`].
@ -345,6 +358,7 @@ pub fn layout<Renderer, T>(
width: Length, width: Length,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
placeholder: Option<&str>, placeholder: Option<&str>,
options: &[T], options: &[T],
@ -366,7 +380,7 @@ where
text_size, text_size,
font.unwrap_or_else(|| renderer.default_font()), font.unwrap_or_else(|| renderer.default_font()),
Size::new(f32::INFINITY, f32::INFINITY), Size::new(f32::INFINITY, f32::INFINITY),
false, text_shaping,
); );
width.round() width.round()
@ -516,6 +530,7 @@ pub fn overlay<'a, T, Message, Renderer>(
state: &'a mut State<T>, state: &'a mut State<T>,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Renderer::Font, font: Renderer::Font,
options: &'a [T], options: &'a [T],
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -543,6 +558,7 @@ where
.width(bounds.width) .width(bounds.width)
.padding(padding) .padding(padding)
.font(font) .font(font)
.text_shaping(text_shaping)
.style(style); .style(style);
if let Some(text_size) = text_size { if let Some(text_size) = text_size {
@ -563,6 +579,7 @@ pub fn draw<'a, T, Renderer>(
cursor_position: Point, cursor_position: Point,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Renderer::Font, font: Renderer::Font,
placeholder: Option<&str>, placeholder: Option<&str>,
selected: Option<&T>, selected: Option<&T>,
@ -595,25 +612,34 @@ pub fn draw<'a, T, Renderer>(
); );
let handle = match handle { let handle = match handle {
Handle::Arrow { size } => { Handle::Arrow { size } => Some((
Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size)) Renderer::ICON_FONT,
} Renderer::ARROW_DOWN_ICON,
*size,
text::Shaping::Basic,
)),
Handle::Static(Icon { Handle::Static(Icon {
font, font,
code_point, code_point,
size, size,
}) => Some((*font, *code_point, *size)), shaping,
}) => Some((*font, *code_point, *size, *shaping)),
Handle::Dynamic { open, closed } => { Handle::Dynamic { open, closed } => {
if state().is_open { if state().is_open {
Some((open.font, open.code_point, open.size)) Some((open.font, open.code_point, open.size, open.shaping))
} else { } else {
Some((closed.font, closed.code_point, closed.size)) Some((
closed.font,
closed.code_point,
closed.size,
closed.shaping,
))
} }
} }
Handle::None => None, Handle::None => None,
}; };
if let Some((font, code_point, size)) = handle { if let Some((font, code_point, size, shaping)) = handle {
let size = size.unwrap_or_else(|| renderer.default_size()); let size = size.unwrap_or_else(|| renderer.default_size());
renderer.fill_text(Text { renderer.fill_text(Text {
@ -629,7 +655,7 @@ pub fn draw<'a, T, Renderer>(
}, },
horizontal_alignment: alignment::Horizontal::Right, horizontal_alignment: alignment::Horizontal::Right,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
advanced_shape: false, shaping,
}); });
} }
@ -655,7 +681,7 @@ pub fn draw<'a, T, Renderer>(
}, },
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
advanced_shape: false, shaping: text_shaping,
}); });
} }
} }

View file

@ -81,6 +81,7 @@ where
size: f32, size: f32,
spacing: f32, spacing: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
} }
@ -123,6 +124,7 @@ where
size: Self::DEFAULT_SIZE, size: Self::DEFAULT_SIZE,
spacing: Self::DEFAULT_SPACING, //15 spacing: Self::DEFAULT_SPACING, //15
text_size: None, text_size: None,
text_shaping: text::Shaping::Basic,
font: None, font: None,
style: Default::default(), style: Default::default(),
} }
@ -152,6 +154,12 @@ where
self self
} }
/// Sets the [`text::Shaping`] strategy of the [`Radio`] button.
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping;
self
}
/// Sets the text font of the [`Radio`] button. /// Sets the text font of the [`Radio`] button.
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
self.font = Some(font.into()); self.font = Some(font.into());
@ -192,9 +200,15 @@ where
.spacing(self.spacing) .spacing(self.spacing)
.align_items(Alignment::Center) .align_items(Alignment::Center)
.push(Row::new().width(self.size).height(self.size)) .push(Row::new().width(self.size).height(self.size))
.push(Text::new(&self.label).width(self.width).size( .push(
self.text_size.unwrap_or_else(|| renderer.default_size()), Text::new(&self.label)
)) .width(self.width)
.size(
self.text_size
.unwrap_or_else(|| renderer.default_size()),
)
.shaping(self.text_shaping),
)
.layout(renderer, limits) .layout(renderer, limits)
} }
@ -309,7 +323,7 @@ where
}, },
alignment::Horizontal::Left, alignment::Horizontal::Left,
alignment::Vertical::Center, alignment::Vertical::Center,
false, self.text_shaping,
); );
} }
} }

View file

@ -1,3 +1,4 @@
pub use crate::core::text::Shaping;
pub use crate::core::widget::text::*; pub use crate::core::widget::text::*;
pub type Text<'a, Renderer = crate::Renderer> = pub type Text<'a, Renderer = crate::Renderer> =

View file

@ -463,7 +463,7 @@ where
&icon.code_point.to_string(), &icon.code_point.to_string(),
icon.size.unwrap_or_else(|| renderer.default_size()), icon.size.unwrap_or_else(|| renderer.default_size()),
icon.font, icon.font,
true, text::Shaping::Advanced,
); );
let mut text_node = layout::Node::new( let mut text_node = layout::Node::new(
@ -976,7 +976,7 @@ pub fn draw<Renderer>(
bounds: icon_layout.bounds(), bounds: icon_layout.bounds(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
advanced_shape: true, shaping: text::Shaping::Advanced,
}); });
} }
@ -1081,7 +1081,7 @@ pub fn draw<Renderer>(
if text.is_empty() { placeholder } else { &text }, if text.is_empty() { placeholder } else { &text },
size, size,
font, font,
true, text::Shaping::Advanced,
); );
let render = |renderer: &mut Renderer| { let render = |renderer: &mut Renderer| {
@ -1109,7 +1109,7 @@ pub fn draw<Renderer>(
size, size,
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
advanced_shape: true, shaping: text::Shaping::Advanced,
}); });
}; };
@ -1314,8 +1314,12 @@ where
{ {
let text_before_cursor = value.until(cursor_index).to_string(); let text_before_cursor = value.until(cursor_index).to_string();
let text_value_width = let text_value_width = renderer.measure_width(
renderer.measure_width(&text_before_cursor, size, font, true); &text_before_cursor,
size,
font,
text::Shaping::Advanced,
);
let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0); let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0);
@ -1348,9 +1352,9 @@ where
size, size,
font, font,
Size::INFINITY, Size::INFINITY,
text::Shaping::Advanced,
Point::new(x + offset, text_bounds.height / 2.0), Point::new(x + offset, text_bounds.height / 2.0),
true, true,
true,
) )
.map(text::Hit::cursor)?; .map(text::Hit::cursor)?;

View file

@ -43,6 +43,7 @@ where
size: f32, size: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_alignment: alignment::Horizontal, text_alignment: alignment::Horizontal,
text_shaping: text::Shaping,
spacing: f32, spacing: f32,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -80,6 +81,7 @@ where
size: Self::DEFAULT_SIZE, size: Self::DEFAULT_SIZE,
text_size: None, text_size: None,
text_alignment: alignment::Horizontal::Left, text_alignment: alignment::Horizontal::Left,
text_shaping: text::Shaping::Basic,
spacing: 0.0, spacing: 0.0,
font: None, font: None,
style: Default::default(), style: Default::default(),
@ -110,6 +112,12 @@ where
self self
} }
/// Sets the [`text::Shaping`] strategy of the [`Toggler`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping;
self
}
/// Sets the spacing between the [`Toggler`] and the text. /// Sets the spacing between the [`Toggler`] and the text.
pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self { pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {
self.spacing = spacing.into().0; self.spacing = spacing.into().0;
@ -167,7 +175,8 @@ where
.size( .size(
self.text_size self.text_size
.unwrap_or_else(|| renderer.default_size()), .unwrap_or_else(|| renderer.default_size()),
), )
.shaping(self.text_shaping),
); );
} }
@ -249,7 +258,7 @@ where
Default::default(), Default::default(),
self.text_alignment, self.text_alignment,
alignment::Vertical::Center, alignment::Vertical::Center,
false, self.text_shaping,
); );
} }