Support configurable LineHeight in text widgets

This commit is contained in:
Héctor Ramón Jiménez 2023-05-04 13:00:16 +02:00
parent 8e8808f0e1
commit 9499a8f9e6
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
24 changed files with 337 additions and 42 deletions

View file

@ -1,3 +1,5 @@
use crate::Pixels;
/// The strategy used to fill space in a specific dimension. /// The strategy used to fill space in a specific dimension.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Length { 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 { impl From<f32> for Length {
fn from(amount: f32) -> Self { fn from(amount: f32) -> Self {
Length::Fixed(amount) Length::Fixed(amount)

View file

@ -20,3 +20,9 @@ impl From<u16> for Pixels {
Self(f32::from(amount)) Self(f32::from(amount))
} }
} }
impl From<Pixels> for f32 {
fn from(pixels: Pixels) -> Self {
pixels.0
}
}

View file

@ -60,6 +60,7 @@ impl text::Renderer for Null {
&self, &self,
_content: &str, _content: &str,
_size: f32, _size: f32,
_line_height: text::LineHeight,
_font: Font, _font: Font,
_bounds: Size, _bounds: Size,
_shaping: text::Shaping, _shaping: text::Shaping,
@ -71,6 +72,7 @@ impl text::Renderer for Null {
&self, &self,
_contents: &str, _contents: &str,
_size: f32, _size: f32,
_line_height: text::LineHeight,
_font: Self::Font, _font: Self::Font,
_bounds: Size, _bounds: Size,
_shaping: text::Shaping, _shaping: text::Shaping,

View file

@ -1,8 +1,9 @@
//! Draw and interact with text. //! Draw and interact with text.
use crate::alignment; use crate::alignment;
use crate::{Color, Point, Rectangle, Size}; use crate::{Color, Pixels, Point, Rectangle, Size};
use std::borrow::Cow; use std::borrow::Cow;
use std::hash::{Hash, Hasher};
/// A paragraph. /// A paragraph.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -13,9 +14,12 @@ pub struct Text<'a, Font> {
/// The bounds of the paragraph. /// The bounds of the paragraph.
pub bounds: Rectangle, pub bounds: Rectangle,
/// The size of the [`Text`]. /// The size of the [`Text`] in logical pixels.
pub size: f32, pub size: f32,
/// The line height of the [`Text`].
pub line_height: LineHeight,
/// The color of the [`Text`]. /// The color of the [`Text`].
pub color: Color, pub color: Color,
@ -56,6 +60,59 @@ pub enum Shaping {
Advanced, 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<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. /// The result of hit testing on text.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Hit { pub enum Hit {
@ -102,6 +159,7 @@ pub trait Renderer: crate::Renderer {
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Self::Font, font: Self::Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,
@ -115,8 +173,14 @@ pub trait Renderer: crate::Renderer {
font: Self::Font, font: Self::Font,
shaping: Shaping, shaping: Shaping,
) -> f32 { ) -> f32 {
let (width, _) = let (width, _) = self.measure(
self.measure(content, size, font, Size::INFINITY, shaping); content,
size,
LineHeight::Absolute(Pixels(size)),
font,
Size::INFINITY,
shaping,
);
width width
} }
@ -132,6 +196,7 @@ pub trait Renderer: crate::Renderer {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Self::Font, font: Self::Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,

View file

@ -19,6 +19,7 @@ where
{ {
content: Cow<'a, str>, content: Cow<'a, str>,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
width: Length, width: Length,
height: Length, height: Length,
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
@ -38,6 +39,7 @@ where
Text { Text {
content: content.into(), content: content.into(),
size: None, size: None,
line_height: text::LineHeight::default(),
font: None, font: None,
width: Length::Shrink, width: Length::Shrink,
height: Length::Shrink, height: Length::Shrink,
@ -54,6 +56,15 @@ where
self self
} }
/// Sets the [`LineHeight`] of the [`Text`].
pub fn line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.line_height = line_height.into();
self
}
/// Sets the [`Font`] of the [`Text`]. /// Sets the [`Font`] of the [`Text`].
/// ///
/// [`Font`]: crate::text::Renderer::Font /// [`Font`]: crate::text::Renderer::Font
@ -135,6 +146,7 @@ where
let (width, height) = renderer.measure( let (width, height) = renderer.measure(
&self.content, &self.content,
size, size,
self.line_height,
self.font.unwrap_or_else(|| renderer.default_font()), self.font.unwrap_or_else(|| renderer.default_font()),
bounds, bounds,
self.shaping, self.shaping,
@ -161,6 +173,7 @@ where
layout, layout,
&self.content, &self.content,
self.size, self.size,
self.line_height,
self.font, self.font,
theme.appearance(self.style.clone()), theme.appearance(self.style.clone()),
self.horizontal_alignment, self.horizontal_alignment,
@ -186,6 +199,7 @@ pub fn draw<Renderer>(
layout: Layout<'_>, layout: Layout<'_>,
content: &str, content: &str,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
appearance: Appearance, appearance: Appearance,
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
@ -208,9 +222,12 @@ pub fn draw<Renderer>(
alignment::Vertical::Bottom => bounds.y + bounds.height, alignment::Vertical::Bottom => bounds.y + bounds.height,
}; };
let size = size.unwrap_or_else(|| renderer.default_size());
renderer.fill_text(crate::Text { renderer.fill_text(crate::Text {
content, content,
size: size.unwrap_or_else(|| renderer.default_size()), size,
line_height,
bounds: Rectangle { x, y, ..bounds }, bounds: Rectangle { x, y, ..bounds },
color: appearance.color.unwrap_or(style.text_color), color: appearance.color.unwrap_or(style.text_color),
font: font.unwrap_or_else(|| renderer.default_font()), font: font.unwrap_or_else(|| renderer.default_font()),
@ -240,6 +257,7 @@ where
Self { Self {
content: self.content.clone(), content: self.content.clone(),
size: self.size, size: self.size,
line_height: self.line_height,
width: self.width, width: self.width,
height: self.height, height: self.height,
horizontal_alignment: self.horizontal_alignment, horizontal_alignment: self.horizontal_alignment,

View file

@ -46,6 +46,7 @@ pub trait Text {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
@ -62,6 +63,7 @@ pub trait Text {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,

View file

@ -1,5 +1,5 @@
use crate::core::alignment; use crate::core::alignment;
use crate::core::text::Shaping; use crate::core::text::{LineHeight, Shaping};
use crate::core::{Color, Font, Point}; 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
@ -20,6 +20,8 @@ pub struct Text {
pub color: Color, pub color: Color,
/// The size of the text /// The size of the text
pub size: f32, pub size: f32,
/// The line height of the text.
pub line_height: LineHeight,
/// The font of the text /// The font of the text
pub font: Font, pub font: Font,
/// The horizontal alignment of the text /// The horizontal alignment of the text
@ -37,6 +39,7 @@ impl Default for Text {
position: Point::ORIGIN, position: Point::ORIGIN,
color: Color::BLACK, color: Color::BLACK,
size: 16.0, size: 16.0,
line_height: LineHeight::Relative(1.2),
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,

View file

@ -19,8 +19,10 @@ pub enum Primitive {
bounds: Rectangle, bounds: Rectangle,
/// The color of the text /// The color of the text
color: Color, color: Color,
/// The size of the text /// The size of the text in logical pixels
size: f32, size: f32,
/// The line height of the text
line_height: text::LineHeight,
/// The font of the text /// The font of the text
font: Font, font: Font,
/// The horizontal alignment of the text /// The horizontal alignment of the text

View file

@ -136,17 +136,26 @@ where
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.backend().measure(content, size, font, bounds, shaping) self.backend().measure(
content,
size,
line_height,
font,
bounds,
shaping,
)
} }
fn hit_test( fn hit_test(
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
@ -156,6 +165,7 @@ where
self.backend().hit_test( self.backend().hit_test(
content, content,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,
@ -173,6 +183,7 @@ where
content: text.content.to_string(), content: text.content.to_string(),
bounds: text.bounds, bounds: text.bounds,
size: text.size, size: text.size,
line_height: text.line_height,
color: text.color, color: text.color,
font: text.font, font: text.font,
horizontal_alignment: text.horizontal_alignment, horizontal_alignment: text.horizontal_alignment,

View file

@ -46,6 +46,7 @@ impl backend::Text for Backend {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
@ -53,7 +54,7 @@ impl backend::Text for Backend {
delegate!( delegate!(
self, self,
backend, backend,
backend.measure(contents, size, font, bounds, shaping) backend.measure(contents, size, line_height, font, bounds, shaping)
) )
} }
@ -61,6 +62,7 @@ impl backend::Text for Backend {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
@ -73,6 +75,7 @@ impl backend::Text for Backend {
backend.hit_test( backend.hit_test(
contents, contents,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,

View file

@ -216,6 +216,7 @@ impl Backend {
bounds, bounds,
color, color,
size, size,
line_height,
font, font,
horizontal_alignment, horizontal_alignment,
vertical_alignment, vertical_alignment,
@ -233,13 +234,15 @@ impl Backend {
self.text_pipeline.draw( self.text_pipeline.draw(
content, content,
(*bounds + translation) * scale_factor, *bounds + translation,
*color, *color,
*size * scale_factor, *size,
*line_height,
*font, *font,
*horizontal_alignment, *horizontal_alignment,
*vertical_alignment, *vertical_alignment,
*shaping, *shaping,
scale_factor,
pixels, pixels,
clip_mask, clip_mask,
); );
@ -626,18 +629,26 @@ impl backend::Text for Backend {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.text_pipeline self.text_pipeline.measure(
.measure(contents, size, font, bounds, shaping) contents,
size,
line_height,
font,
bounds,
shaping,
)
} }
fn hit_test( fn hit_test(
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: text::Shaping, shaping: text::Shaping,
@ -647,6 +658,7 @@ impl backend::Text for Backend {
self.text_pipeline.hit_test( self.text_pipeline.hit_test(
contents, contents,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,

View file

@ -111,6 +111,7 @@ impl Frame {
}, },
color: text.color, color: text.color,
size: text.size, size: text.size,
line_height: text.line_height,
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,

View file

@ -1,7 +1,7 @@
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, Shaping}; use crate::core::text::{Hit, LineHeight, Shaping};
use crate::core::{Color, Point, Rectangle, Size}; use crate::core::{Color, Pixels, Point, Rectangle, Size};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use std::borrow::Cow; use std::borrow::Cow;
@ -46,13 +46,21 @@ impl Pipeline {
bounds: Rectangle, bounds: Rectangle,
color: Color, color: Color,
size: f32, size: f32,
line_height: LineHeight,
font: Font, font: Font,
horizontal_alignment: alignment::Horizontal, horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
shaping: Shaping, shaping: Shaping,
scale_factor: f32,
pixels: &mut tiny_skia::PixmapMut<'_>, pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: Option<&tiny_skia::Mask>, clip_mask: Option<&tiny_skia::Mask>,
) { ) {
let line_height =
f32::from(line_height.to_absolute(Pixels(size))) * scale_factor;
let bounds = bounds * scale_factor;
let size = size * scale_factor;
let font_system = self.font_system.get_mut(); let font_system = self.font_system.get_mut();
let key = Key { let key = Key {
bounds: { bounds: {
@ -64,6 +72,7 @@ impl Pipeline {
content, content,
font, font,
size, size,
line_height,
shaping, shaping,
}; };
@ -76,7 +85,7 @@ impl Pipeline {
(i + 1, buffer.line_w.max(max)) (i + 1, buffer.line_w.max(max))
}); });
let total_height = total_lines as f32 * size * 1.2; let total_height = total_lines as f32 * line_height;
let x = match horizontal_alignment { let x = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x, alignment::Horizontal::Left => bounds.x,
@ -130,17 +139,21 @@ impl Pipeline {
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
let (_, paragraph) = measurement_cache.allocate( let (_, paragraph) = measurement_cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
content, content,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,
@ -154,13 +167,14 @@ impl Pipeline {
(i + 1, buffer.line_w.max(max)) (i + 1, buffer.line_w.max(max))
}); });
(max_width, size * 1.2 * total_lines as f32) (max_width, line_height * total_lines as f32)
} }
pub fn hit_test( pub fn hit_test(
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,
@ -169,11 +183,14 @@ impl Pipeline {
) -> Option<Hit> { ) -> Option<Hit> {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
let (_, paragraph) = measurement_cache.allocate( let (_, paragraph) = measurement_cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
content, content,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,
@ -380,9 +397,11 @@ impl Cache {
key.content.hash(&mut hasher); key.content.hash(&mut hasher);
key.size.to_bits().hash(&mut hasher); key.size.to_bits().hash(&mut hasher);
key.line_height.to_bits().hash(&mut hasher);
key.font.hash(&mut hasher); key.font.hash(&mut hasher);
key.bounds.width.to_bits().hash(&mut hasher); key.bounds.width.to_bits().hash(&mut hasher);
key.bounds.height.to_bits().hash(&mut hasher); key.bounds.height.to_bits().hash(&mut hasher);
key.shaping.hash(&mut hasher);
hasher.finish() hasher.finish()
}; };
@ -432,6 +451,7 @@ impl Cache {
struct Key<'a> { struct Key<'a> {
content: &'a str, content: &'a str,
size: f32, size: f32,
line_height: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,

View file

@ -352,18 +352,26 @@ impl backend::Text for Backend {
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: core::text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: core::text::Shaping, shaping: core::text::Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
self.text_pipeline self.text_pipeline.measure(
.measure(contents, size, font, bounds, shaping) contents,
size,
line_height,
font,
bounds,
shaping,
)
} }
fn hit_test( fn hit_test(
&self, &self,
contents: &str, contents: &str,
size: f32, size: f32,
line_height: core::text::LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: core::text::Shaping, shaping: core::text::Shaping,
@ -373,6 +381,7 @@ impl backend::Text for Backend {
self.text_pipeline.hit_test( self.text_pipeline.hit_test(
contents, contents,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,

View file

@ -331,6 +331,7 @@ impl Frame {
}, },
color: text.color, color: text.color,
size: text.size, size: text.size,
line_height: text.line_height,
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,

View file

@ -62,6 +62,7 @@ impl<'a> Layer<'a> {
), ),
color: Color::new(0.9, 0.9, 0.9, 1.0), color: Color::new(0.9, 0.9, 0.9, 1.0),
size: 20.0, size: 20.0,
line_height: core::text::LineHeight::Relative(1.2),
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,
@ -114,6 +115,7 @@ impl<'a> Layer<'a> {
content, content,
bounds, bounds,
size, size,
line_height,
color, color,
font, font,
horizontal_alignment, horizontal_alignment,
@ -126,6 +128,7 @@ impl<'a> Layer<'a> {
content, content,
bounds: *bounds + translation, bounds: *bounds + translation,
size: *size, size: *size,
line_height: *line_height,
color: *color, color: *color,
font: *font, font: *font,
horizontal_alignment: *horizontal_alignment, horizontal_alignment: *horizontal_alignment,

View file

@ -14,9 +14,12 @@ pub struct Text<'a> {
/// The color of the [`Text`], in __linear RGB_. /// The color of the [`Text`], in __linear RGB_.
pub color: Color, pub color: Color,
/// The size of the [`Text`]. /// The size of the [`Text`] in logical pixels.
pub size: f32, pub size: f32,
/// The line height of the [`Text`].
pub line_height: text::LineHeight,
/// The font of the [`Text`]. /// The font of the [`Text`].
pub font: Font, pub font: Font,

View file

@ -1,7 +1,7 @@
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, Shaping}; use crate::core::text::{Hit, LineHeight, Shaping};
use crate::core::{Point, Rectangle, Size}; use crate::core::{Pixels, Point, Rectangle, Size};
use crate::layer::Text; use crate::layer::Text;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -77,6 +77,11 @@ impl Pipeline {
Key { Key {
content: section.content, content: section.content,
size: section.size * scale_factor, size: section.size * scale_factor,
line_height: f32::from(
section
.line_height
.to_absolute(Pixels(section.size)),
) * scale_factor,
font: section.font, font: section.font,
bounds: Size { bounds: Size {
width: (section.bounds.width * scale_factor).ceil(), width: (section.bounds.width * scale_factor).ceil(),
@ -114,7 +119,7 @@ impl Pipeline {
}); });
let total_height = let total_height =
total_lines as f32 * section.size * 1.2 * scale_factor; total_lines as f32 * buffer.metrics().line_height;
let left = match section.horizontal_alignment { let left = match section.horizontal_alignment {
alignment::Horizontal::Left => x, alignment::Horizontal::Left => x,
@ -212,17 +217,21 @@ impl Pipeline {
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,
) -> (f32, f32) { ) -> (f32, f32) {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
let (_, paragraph) = measurement_cache.allocate( let (_, paragraph) = measurement_cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
content, content,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,
@ -236,13 +245,14 @@ impl Pipeline {
(i + 1, buffer.line_w.max(max)) (i + 1, buffer.line_w.max(max))
}); });
(max_width, size * 1.2 * total_lines as f32) (max_width, line_height * total_lines as f32)
} }
pub fn hit_test( pub fn hit_test(
&self, &self,
content: &str, content: &str,
size: f32, size: f32,
line_height: LineHeight,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,
@ -251,11 +261,14 @@ impl Pipeline {
) -> Option<Hit> { ) -> Option<Hit> {
let mut measurement_cache = self.measurement_cache.borrow_mut(); let mut measurement_cache = self.measurement_cache.borrow_mut();
let line_height = f32::from(line_height.to_absolute(Pixels(size)));
let (_, paragraph) = measurement_cache.allocate( let (_, paragraph) = measurement_cache.allocate(
&mut self.font_system.borrow_mut(), &mut self.font_system.borrow_mut(),
Key { Key {
content, content,
size, size,
line_height,
font, font,
bounds, bounds,
shaping, shaping,
@ -353,21 +366,23 @@ impl Cache {
key.content.hash(&mut hasher); key.content.hash(&mut hasher);
key.size.to_bits().hash(&mut hasher); key.size.to_bits().hash(&mut hasher);
key.line_height.to_bits().hash(&mut hasher);
key.font.hash(&mut hasher); key.font.hash(&mut hasher);
key.bounds.width.to_bits().hash(&mut hasher); key.bounds.width.to_bits().hash(&mut hasher);
key.bounds.height.to_bits().hash(&mut hasher); key.bounds.height.to_bits().hash(&mut hasher);
key.shaping.hash(&mut hasher);
hasher.finish() hasher.finish()
}; };
if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) {
let metrics = glyphon::Metrics::new(key.size, key.size * 1.2); let metrics = glyphon::Metrics::new(key.size, key.line_height);
let mut buffer = glyphon::Buffer::new(font_system, metrics); let mut buffer = glyphon::Buffer::new(font_system, metrics);
buffer.set_size( buffer.set_size(
font_system, font_system,
key.bounds.width, key.bounds.width,
key.bounds.height.max(key.size * 1.2), key.bounds.height.max(key.line_height),
); );
buffer.set_text( buffer.set_text(
font_system, font_system,
@ -399,6 +414,7 @@ impl Cache {
struct Key<'a> { struct Key<'a> {
content: &'a str, content: &'a str,
size: f32, size: f32,
line_height: f32,
font: Font, font: Font,
bounds: Size, bounds: Size,
shaping: Shaping, shaping: Shaping,

View file

@ -46,6 +46,7 @@ where
size: f32, size: f32,
spacing: f32, spacing: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
icon: Icon<Renderer::Font>, icon: Icon<Renderer::Font>,
@ -83,6 +84,7 @@ where
size: Self::DEFAULT_SIZE, size: Self::DEFAULT_SIZE,
spacing: Self::DEFAULT_SPACING, spacing: Self::DEFAULT_SPACING,
text_size: None, text_size: None,
text_line_height: text::LineHeight::default(),
text_shaping: text::Shaping::Basic, text_shaping: text::Shaping::Basic,
font: None, font: None,
icon: Icon { icon: Icon {
@ -119,6 +121,15 @@ where
self self
} }
/// Sets the text [`LineHeight`] of the [`Checkbox`].
pub fn text_line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.text_line_height = line_height.into();
self
}
/// Sets the [`text::Shaping`] strategy of the [`Checkbox`]. /// Sets the [`text::Shaping`] strategy of the [`Checkbox`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping; self.text_shaping = shaping;
@ -181,6 +192,7 @@ where
self.text_size self.text_size
.unwrap_or_else(|| renderer.default_size()), .unwrap_or_else(|| renderer.default_size()),
) )
.line_height(self.text_line_height)
.shaping(self.text_shaping), .shaping(self.text_shaping),
) )
.layout(renderer, limits) .layout(renderer, limits)
@ -276,6 +288,7 @@ where
content: &code_point.to_string(), content: &code_point.to_string(),
font: *font, font: *font,
size, size,
line_height: text::LineHeight::default(),
bounds: Rectangle { bounds: Rectangle {
x: bounds.center_x(), x: bounds.center_x(),
y: bounds.center_y(), y: bounds.center_y(),
@ -298,6 +311,7 @@ where
label_layout, label_layout,
&self.label, &self.label,
self.text_size, self.text_size,
self.text_line_height,
self.font, self.font,
crate::text::Appearance { crate::text::Appearance {
color: custom_style.text_color, color: custom_style.text_color,

View file

@ -31,6 +31,7 @@ where
width: f32, width: f32,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -59,6 +60,7 @@ where
width: 0.0, width: 0.0,
padding: Padding::ZERO, padding: Padding::ZERO,
text_size: None, text_size: None,
text_line_height: text::LineHeight::default(),
text_shaping: text::Shaping::Basic, text_shaping: text::Shaping::Basic,
font: None, font: None,
style: Default::default(), style: Default::default(),
@ -83,6 +85,15 @@ where
self self
} }
/// Sets the text [`LineHeight`] of the [`Menu`].
pub fn text_line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.text_line_height = line_height.into();
self
}
/// Sets the [`text::Shaping`] strategy of the [`Menu`]. /// Sets the [`text::Shaping`] strategy of the [`Menu`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping; self.text_shaping = shaping;
@ -176,6 +187,7 @@ where
padding, padding,
font, font,
text_size, text_size,
text_line_height,
text_shaping, text_shaping,
style, style,
} = menu; } = menu;
@ -186,6 +198,7 @@ where
last_selection, last_selection,
font, font,
text_size, text_size,
text_line_height,
text_shaping, text_shaping,
padding, padding,
style: style.clone(), style: style.clone(),
@ -321,6 +334,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_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -352,10 +366,13 @@ where
let text_size = let text_size =
self.text_size.unwrap_or_else(|| renderer.default_size()); self.text_size.unwrap_or_else(|| renderer.default_size());
let text_line_height =
self.text_line_height.to_absolute(Pixels(text_size));
let size = { let size = {
let intrinsic = Size::new( let intrinsic = Size::new(
0.0, 0.0,
(text_size * 1.2 + self.padding.vertical()) (f32::from(text_line_height) + self.padding.vertical())
* self.options.len() as f32, * self.options.len() as f32,
); );
@ -395,9 +412,12 @@ where
.text_size .text_size
.unwrap_or_else(|| renderer.default_size()); .unwrap_or_else(|| renderer.default_size());
let option_height = f32::from(
self.text_line_height.to_absolute(Pixels(text_size)),
) + self.padding.vertical();
*self.hovered_option = Some( *self.hovered_option = Some(
((cursor_position.y - bounds.y) ((cursor_position.y - bounds.y) / option_height)
/ (text_size * 1.2 + self.padding.vertical()))
as usize, as usize,
); );
} }
@ -410,9 +430,12 @@ where
.text_size .text_size
.unwrap_or_else(|| renderer.default_size()); .unwrap_or_else(|| renderer.default_size());
let option_height = f32::from(
self.text_line_height.to_absolute(Pixels(text_size)),
) + self.padding.vertical();
*self.hovered_option = Some( *self.hovered_option = Some(
((cursor_position.y - bounds.y) ((cursor_position.y - bounds.y) / option_height)
/ (text_size * 1.2 + self.padding.vertical()))
as usize, as usize,
); );
@ -462,12 +485,12 @@ where
let text_size = let text_size =
self.text_size.unwrap_or_else(|| renderer.default_size()); self.text_size.unwrap_or_else(|| renderer.default_size());
let option_height = let option_height =
(text_size * 1.2 + self.padding.vertical()) as usize; f32::from(self.text_line_height.to_absolute(Pixels(text_size)))
+ self.padding.vertical();
let offset = viewport.y - bounds.y; let offset = viewport.y - bounds.y;
let start = (offset / option_height as f32) as usize; let start = (offset / option_height) as usize;
let end = let end = ((offset + viewport.height) / option_height).ceil() as usize;
((offset + viewport.height) / option_height as f32).ceil() as usize;
let visible_options = &self.options[start..end.min(self.options.len())]; let visible_options = &self.options[start..end.min(self.options.len())];
@ -477,9 +500,9 @@ where
let bounds = Rectangle { let bounds = Rectangle {
x: bounds.x, x: bounds.x,
y: bounds.y + (option_height * i) as f32, y: bounds.y + (option_height * i as f32),
width: bounds.width, width: bounds.width,
height: text_size * 1.2 + self.padding.vertical(), height: option_height,
}; };
if is_selected { if is_selected {
@ -503,6 +526,7 @@ where
..bounds ..bounds
}, },
size: text_size, size: text_size,
line_height: self.text_line_height,
font: self.font.unwrap_or_else(|| renderer.default_font()), font: self.font.unwrap_or_else(|| renderer.default_font()),
color: if is_selected { color: if is_selected {
appearance.selected_text_color appearance.selected_text_color

View file

@ -36,6 +36,7 @@ where
width: Length, width: Length,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
handle: Handle<Renderer::Font>, handle: Handle<Renderer::Font>,
@ -72,6 +73,7 @@ where
width: Length::Shrink, width: Length::Shrink,
padding: Self::DEFAULT_PADDING, padding: Self::DEFAULT_PADDING,
text_size: None, text_size: None,
text_line_height: text::LineHeight::default(),
text_shaping: text::Shaping::Basic, text_shaping: text::Shaping::Basic,
font: None, font: None,
handle: Default::default(), handle: Default::default(),
@ -103,6 +105,15 @@ where
self self
} }
/// Sets the text [`LineHeight`] of the [`PickList`].
pub fn text_line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.text_line_height = line_height.into();
self
}
/// Sets the [`text::Shaping`] strategy of the [`PickList`]. /// Sets the [`text::Shaping`] strategy of the [`PickList`].
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping; self.text_shaping = shaping;
@ -172,6 +183,7 @@ where
self.width, self.width,
self.padding, self.padding,
self.text_size, self.text_size,
self.text_line_height,
self.text_shaping, self.text_shaping,
self.font, self.font,
self.placeholder.as_deref(), self.placeholder.as_deref(),
@ -230,6 +242,7 @@ where
cursor_position, cursor_position,
self.padding, self.padding,
self.text_size, self.text_size,
self.text_line_height,
self.text_shaping, self.text_shaping,
font, font,
self.placeholder.as_deref(), self.placeholder.as_deref(),
@ -358,6 +371,7 @@ pub fn layout<Renderer, T>(
width: Length, width: Length,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
placeholder: Option<&str>, placeholder: Option<&str>,
@ -375,11 +389,10 @@ where
let max_width = match width { let max_width = match width {
Length::Shrink => { Length::Shrink => {
let measure = |label: &str| -> f32 { let measure = |label: &str| -> f32 {
let (width, _) = renderer.measure( let width = renderer.measure_width(
label, label,
text_size, text_size,
font.unwrap_or_else(|| renderer.default_font()), font.unwrap_or_else(|| renderer.default_font()),
Size::new(f32::INFINITY, f32::INFINITY),
text_shaping, text_shaping,
); );
@ -400,8 +413,10 @@ where
}; };
let size = { let size = {
let intrinsic = let intrinsic = Size::new(
Size::new(max_width + text_size + padding.left, text_size * 1.2); max_width + text_size + padding.left,
f32::from(text_line_height.to_absolute(Pixels(text_size))),
);
limits.resolve(intrinsic).pad(padding) limits.resolve(intrinsic).pad(padding)
}; };
@ -579,6 +594,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_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Renderer::Font, font: Renderer::Font,
placeholder: Option<&str>, placeholder: Option<&str>,
@ -645,6 +661,7 @@ pub fn draw<'a, T, Renderer>(
renderer.fill_text(Text { renderer.fill_text(Text {
content: &code_point.to_string(), content: &code_point.to_string(),
size, size,
line_height: text::LineHeight::default(),
font, font,
color: style.handle_color, color: style.handle_color,
bounds: Rectangle { bounds: Rectangle {
@ -667,6 +684,7 @@ pub fn draw<'a, T, Renderer>(
renderer.fill_text(Text { renderer.fill_text(Text {
content: label, content: label,
size: text_size, size: text_size,
line_height: text_line_height,
font, font,
color: if is_selected { color: if is_selected {
style.text_color style.text_color

View file

@ -81,6 +81,7 @@ where
size: f32, size: f32,
spacing: f32, spacing: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_shaping: text::Shaping, text_shaping: text::Shaping,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
@ -124,6 +125,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_line_height: text::LineHeight::default(),
text_shaping: text::Shaping::Basic, text_shaping: text::Shaping::Basic,
font: None, font: None,
style: Default::default(), style: Default::default(),
@ -154,6 +156,15 @@ where
self self
} }
/// Sets the text [`LineHeight`] of the [`Radio`] button.
pub fn text_line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.text_line_height = line_height.into();
self
}
/// Sets the [`text::Shaping`] strategy of the [`Radio`] button. /// Sets the [`text::Shaping`] strategy of the [`Radio`] button.
pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { pub fn text_shaping(mut self, shaping: text::Shaping) -> Self {
self.text_shaping = shaping; self.text_shaping = shaping;
@ -207,6 +218,7 @@ where
self.text_size self.text_size
.unwrap_or_else(|| renderer.default_size()), .unwrap_or_else(|| renderer.default_size()),
) )
.line_height(self.text_line_height)
.shaping(self.text_shaping), .shaping(self.text_shaping),
) )
.layout(renderer, limits) .layout(renderer, limits)
@ -317,6 +329,7 @@ where
label_layout, label_layout,
&self.label, &self.label,
self.text_size, self.text_size,
self.text_line_height,
self.font, self.font,
crate::text::Appearance { crate::text::Appearance {
color: custom_style.text_color, color: custom_style.text_color,

View file

@ -68,6 +68,7 @@ where
width: Length, width: Length,
padding: Padding, padding: Padding,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
on_input: Option<Box<dyn Fn(String) -> Message + 'a>>, on_input: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>, on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_submit: Option<Message>, on_submit: Option<Message>,
@ -96,6 +97,7 @@ where
width: Length::Fill, width: Length::Fill,
padding: Padding::new(5.0), padding: Padding::new(5.0),
size: None, size: None,
line_height: text::LineHeight::default(),
on_input: None, on_input: None,
on_paste: None, on_paste: None,
on_submit: None, on_submit: None,
@ -177,6 +179,15 @@ where
self self
} }
/// Sets the [`LineHeight`] of the [`TextInput`].
pub fn line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.line_height = line_height.into();
self
}
/// Sets the style of the [`TextInput`]. /// Sets the style of the [`TextInput`].
pub fn style( pub fn style(
mut self, mut self,
@ -208,6 +219,7 @@ where
value.unwrap_or(&self.value), value.unwrap_or(&self.value),
&self.placeholder, &self.placeholder,
self.size, self.size,
self.line_height,
self.font, self.font,
self.on_input.is_none(), self.on_input.is_none(),
self.is_secure, self.is_secure,
@ -263,6 +275,7 @@ where
self.width, self.width,
self.padding, self.padding,
self.size, self.size,
self.line_height,
self.icon.as_ref(), self.icon.as_ref(),
) )
} }
@ -299,6 +312,7 @@ where
shell, shell,
&mut self.value, &mut self.value,
self.size, self.size,
self.line_height,
self.font, self.font,
self.is_secure, self.is_secure,
self.on_input.as_deref(), self.on_input.as_deref(),
@ -327,6 +341,7 @@ where
&self.value, &self.value,
&self.placeholder, &self.placeholder,
self.size, self.size,
self.line_height,
self.font, self.font,
self.on_input.is_none(), self.on_input.is_none(),
self.is_secure, self.is_secure,
@ -447,6 +462,7 @@ pub fn layout<Renderer>(
width: Length, width: Length,
padding: Padding, padding: Padding,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
icon: Option<&Icon<Renderer::Font>>, icon: Option<&Icon<Renderer::Font>>,
) -> layout::Node ) -> layout::Node
where where
@ -454,7 +470,10 @@ where
{ {
let text_size = size.unwrap_or_else(|| renderer.default_size()); let text_size = size.unwrap_or_else(|| renderer.default_size());
let padding = padding.fit(Size::ZERO, limits.max()); let padding = padding.fit(Size::ZERO, limits.max());
let limits = limits.width(width).pad(padding).height(text_size * 1.2); let limits = limits
.width(width)
.pad(padding)
.height(line_height.to_absolute(Pixels(text_size)));
let text_bounds = limits.resolve(Size::ZERO); let text_bounds = limits.resolve(Size::ZERO);
@ -515,6 +534,7 @@ pub fn update<'a, Message, Renderer>(
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
value: &mut Value, value: &mut Value,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
is_secure: bool, is_secure: bool,
on_input: Option<&dyn Fn(String) -> Message>, on_input: Option<&dyn Fn(String) -> Message>,
@ -567,6 +587,7 @@ where
text_layout.bounds(), text_layout.bounds(),
font, font,
size, size,
line_height,
&value, &value,
state, state,
target, target,
@ -595,6 +616,7 @@ where
text_layout.bounds(), text_layout.bounds(),
font, font,
size, size,
line_height,
value, value,
state, state,
target, target,
@ -644,6 +666,7 @@ where
text_layout.bounds(), text_layout.bounds(),
font, font,
size, size,
line_height,
&value, &value,
state, state,
target, target,
@ -926,6 +949,7 @@ pub fn draw<Renderer>(
value: &Value, value: &Value,
placeholder: &str, placeholder: &str,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
is_disabled: bool, is_disabled: bool,
is_secure: bool, is_secure: bool,
@ -971,6 +995,7 @@ pub fn draw<Renderer>(
renderer.fill_text(Text { renderer.fill_text(Text {
content: &icon.code_point.to_string(), content: &icon.code_point.to_string(),
size: icon.size.unwrap_or_else(|| renderer.default_size()), size: icon.size.unwrap_or_else(|| renderer.default_size()),
line_height: text::LineHeight::default(),
font: icon.font, font: icon.font,
color: appearance.icon_color, color: appearance.icon_color,
bounds: Rectangle { bounds: Rectangle {
@ -1110,6 +1135,7 @@ pub fn draw<Renderer>(
..text_bounds ..text_bounds
}, },
size, size,
line_height,
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
shaping: text::Shaping::Advanced, shaping: text::Shaping::Advanced,
@ -1336,6 +1362,7 @@ fn find_cursor_position<Renderer>(
text_bounds: Rectangle, text_bounds: Rectangle,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
size: Option<f32>, size: Option<f32>,
line_height: text::LineHeight,
value: &Value, value: &Value,
state: &State, state: &State,
x: f32, x: f32,
@ -1353,6 +1380,7 @@ where
.hit_test( .hit_test(
&value, &value,
size, size,
line_height,
font, font,
Size::INFINITY, Size::INFINITY,
text::Shaping::Advanced, text::Shaping::Advanced,

View file

@ -42,6 +42,7 @@ where
width: Length, width: Length,
size: f32, size: f32,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight,
text_alignment: alignment::Horizontal, text_alignment: alignment::Horizontal,
text_shaping: text::Shaping, text_shaping: text::Shaping,
spacing: f32, spacing: f32,
@ -80,6 +81,7 @@ where
width: Length::Fill, width: Length::Fill,
size: Self::DEFAULT_SIZE, size: Self::DEFAULT_SIZE,
text_size: None, text_size: None,
text_line_height: text::LineHeight::default(),
text_alignment: alignment::Horizontal::Left, text_alignment: alignment::Horizontal::Left,
text_shaping: text::Shaping::Basic, text_shaping: text::Shaping::Basic,
spacing: 0.0, spacing: 0.0,
@ -106,6 +108,15 @@ where
self self
} }
/// Sets the text [`LineHeight`] of the [`Toggler`].
pub fn text_line_height(
mut self,
line_height: impl Into<text::LineHeight>,
) -> Self {
self.text_line_height = line_height.into();
self
}
/// Sets the horizontal alignment of the text of the [`Toggler`] /// Sets the horizontal alignment of the text of the [`Toggler`]
pub fn text_alignment(mut self, alignment: alignment::Horizontal) -> Self { pub fn text_alignment(mut self, alignment: alignment::Horizontal) -> Self {
self.text_alignment = alignment; self.text_alignment = alignment;
@ -176,6 +187,7 @@ where
self.text_size self.text_size
.unwrap_or_else(|| renderer.default_size()), .unwrap_or_else(|| renderer.default_size()),
) )
.line_height(self.text_line_height)
.shaping(self.text_shaping), .shaping(self.text_shaping),
); );
} }
@ -254,6 +266,7 @@ where
label_layout, label_layout,
label, label,
self.text_size, self.text_size,
self.text_line_height,
self.font, self.font,
Default::default(), Default::default(),
self.text_alignment, self.text_alignment,