summaryrefslogtreecommitdiffstats
path: root/native
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2023-02-24 20:52:10 +0100
committerLibravatar GitHub <noreply@github.com>2023-02-24 20:52:10 +0100
commit368cadd25a8b57ee5c41e45d1abe8d1dfb194c69 (patch)
tree191cb7cc7807a5fe513b3d485b2fda21d3bf0bde /native
parent573d27eb52bbfacf1b06983b4282f00eb5265bdc (diff)
parent8059c40142d601588e01c152ce1bb72a1295dde8 (diff)
downloadiced-368cadd25a8b57ee5c41e45d1abe8d1dfb194c69.tar.gz
iced-368cadd25a8b57ee5c41e45d1abe8d1dfb194c69.tar.bz2
iced-368cadd25a8b57ee5c41e45d1abe8d1dfb194c69.zip
Merge pull request #1697 from iced-rs/text-glyphon
Text shaping, font fallback, and `iced_wgpu` overhaul
Diffstat (limited to '')
-rw-r--r--native/src/command/action.rs16
-rw-r--r--native/src/font.rs19
-rw-r--r--native/src/lib.rs6
-rw-r--r--native/src/overlay/menu.rs23
-rw-r--r--native/src/program.rs3
-rw-r--r--native/src/renderer/null.rs12
-rw-r--r--native/src/text.rs23
-rw-r--r--native/src/widget/checkbox.rs16
-rw-r--r--native/src/widget/pick_list.rs45
-rw-r--r--native/src/widget/radio.rs10
-rw-r--r--native/src/widget/text.rs22
-rw-r--r--native/src/widget/text_input.rs57
-rw-r--r--native/src/widget/toggler.rs12
13 files changed, 161 insertions, 103 deletions
diff --git a/native/src/command/action.rs b/native/src/command/action.rs
index a51b8c21..d1589c05 100644
--- a/native/src/command/action.rs
+++ b/native/src/command/action.rs
@@ -1,10 +1,12 @@
use crate::clipboard;
+use crate::font;
use crate::system;
use crate::widget;
use crate::window;
use iced_futures::MaybeSend;
+use std::borrow::Cow;
use std::fmt;
/// An action that a [`Command`] can perform.
@@ -27,6 +29,15 @@ pub enum Action<T> {
/// Run a widget action.
Widget(widget::Action<T>),
+
+ /// Load a font from its bytes.
+ LoadFont {
+ /// The bytes of the font to load.
+ bytes: Cow<'static, [u8]>,
+
+ /// The message to produce when the font has been loaded.
+ tagger: Box<dyn Fn(Result<(), font::Error>) -> T>,
+ },
}
impl<T> Action<T> {
@@ -49,6 +60,10 @@ impl<T> Action<T> {
Self::Window(window) => Action::Window(window.map(f)),
Self::System(system) => Action::System(system.map(f)),
Self::Widget(widget) => Action::Widget(widget.map(f)),
+ Self::LoadFont { bytes, tagger } => Action::LoadFont {
+ bytes,
+ tagger: Box::new(move |result| f(tagger(result))),
+ },
}
}
}
@@ -63,6 +78,7 @@ impl<T> fmt::Debug for Action<T> {
Self::Window(action) => write!(f, "Action::Window({action:?})"),
Self::System(action) => write!(f, "Action::System({action:?})"),
Self::Widget(_action) => write!(f, "Action::Widget"),
+ Self::LoadFont { .. } => write!(f, "Action::LoadFont"),
}
}
}
diff --git a/native/src/font.rs b/native/src/font.rs
new file mode 100644
index 00000000..15359694
--- /dev/null
+++ b/native/src/font.rs
@@ -0,0 +1,19 @@
+//! Load and use fonts.
+pub use iced_core::font::*;
+
+use crate::command::{self, Command};
+use std::borrow::Cow;
+
+/// An error while loading a font.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Error {}
+
+/// Load a font from its bytes.
+pub fn load(
+ bytes: impl Into<Cow<'static, [u8]>>,
+) -> Command<Result<(), Error>> {
+ Command::single(command::Action::LoadFont {
+ bytes: bytes.into(),
+ tagger: Box::new(std::convert::identity),
+ })
+}
diff --git a/native/src/lib.rs b/native/src/lib.rs
index ebdc8490..27b6fc0d 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -47,6 +47,7 @@
pub mod clipboard;
pub mod command;
pub mod event;
+pub mod font;
pub mod image;
pub mod keyboard;
pub mod layout;
@@ -80,8 +81,8 @@ mod debug;
pub use iced_core::alignment;
pub use iced_core::time;
pub use iced_core::{
- color, Alignment, Background, Color, ContentFit, Font, Length, Padding,
- Pixels, Point, Rectangle, Size, Vector,
+ color, Alignment, Background, Color, ContentFit, Length, Padding, Pixels,
+ Point, Rectangle, Size, Vector,
};
pub use iced_futures::{executor, futures};
pub use iced_style::application;
@@ -95,6 +96,7 @@ pub use command::Command;
pub use debug::Debug;
pub use element::Element;
pub use event::Event;
+pub use font::Font;
pub use hasher::Hasher;
pub use layout::Layout;
pub use overlay::Overlay;
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index 50f741ef..bd58a122 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -31,7 +31,7 @@ where
width: f32,
padding: Padding,
text_size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -58,7 +58,7 @@ where
width: 0.0,
padding: Padding::ZERO,
text_size: None,
- font: Default::default(),
+ font: None,
style: Default::default(),
}
}
@@ -82,8 +82,8 @@ where
}
/// Sets the font of the [`Menu`].
- pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.font = Some(font.into());
self
}
@@ -311,7 +311,7 @@ where
last_selection: &'a mut Option<T>,
padding: Padding,
text_size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -344,7 +344,7 @@ where
let size = {
let intrinsic = Size::new(
0.0,
- (text_size + self.padding.vertical())
+ (text_size * 1.2 + self.padding.vertical())
* self.options.len() as f32,
);
@@ -386,7 +386,7 @@ where
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
- / (text_size + self.padding.vertical()))
+ / (text_size * 1.2 + self.padding.vertical()))
as usize,
);
}
@@ -401,7 +401,7 @@ where
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
- / (text_size + self.padding.vertical()))
+ / (text_size * 1.2 + self.padding.vertical()))
as usize,
);
@@ -450,7 +450,8 @@ where
let text_size =
self.text_size.unwrap_or_else(|| renderer.default_size());
- let option_height = (text_size + self.padding.vertical()) as usize;
+ let option_height =
+ (text_size * 1.2 + self.padding.vertical()) as usize;
let offset = viewport.y - bounds.y;
let start = (offset / option_height as f32) as usize;
@@ -467,7 +468,7 @@ where
x: bounds.x,
y: bounds.y + (option_height * i) as f32,
width: bounds.width,
- height: text_size + self.padding.vertical(),
+ height: text_size * 1.2 + self.padding.vertical(),
};
if is_selected {
@@ -491,7 +492,7 @@ where
..bounds
},
size: text_size,
- font: self.font.clone(),
+ font: self.font.unwrap_or_else(|| renderer.default_font()),
color: if is_selected {
appearance.selected_text_color
} else {
diff --git a/native/src/program.rs b/native/src/program.rs
index c71c237f..25cab332 100644
--- a/native/src/program.rs
+++ b/native/src/program.rs
@@ -1,4 +1,5 @@
//! Build interactive programs using The Elm Architecture.
+use crate::text;
use crate::{Command, Element, Renderer};
mod state;
@@ -8,7 +9,7 @@ pub use state::State;
/// The core of a user interface application following The Elm Architecture.
pub trait Program: Sized {
/// The graphics backend to use to draw the [`Program`].
- type Renderer: Renderer;
+ type Renderer: Renderer + text::Renderer;
/// The type of __messages__ your [`Program`] will produce.
type Message: std::fmt::Debug + Send;
diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs
index 9376d540..150ee786 100644
--- a/native/src/renderer/null.rs
+++ b/native/src/renderer/null.rs
@@ -2,6 +2,8 @@ use crate::renderer::{self, Renderer};
use crate::text::{self, Text};
use crate::{Background, Font, Point, Rectangle, Size, Theme, Vector};
+use std::borrow::Cow;
+
/// A renderer that does nothing.
///
/// It can be useful if you are writing tests!
@@ -40,14 +42,20 @@ impl Renderer for Null {
impl text::Renderer for Null {
type Font = Font;
- const ICON_FONT: Font = Font::Default;
+ const ICON_FONT: Font = Font::SansSerif;
const CHECKMARK_ICON: char = '0';
const ARROW_DOWN_ICON: char = '0';
+ fn default_font(&self) -> Self::Font {
+ Font::SansSerif
+ }
+
fn default_size(&self) -> f32 {
- 20.0
+ 16.0
}
+ fn load_font(&mut self, _font: Cow<'static, [u8]>) {}
+
fn measure(
&self,
_content: &str,
diff --git a/native/src/text.rs b/native/src/text.rs
index 55c3cfd3..4c72abc3 100644
--- a/native/src/text.rs
+++ b/native/src/text.rs
@@ -1,6 +1,8 @@
//! Draw and interact with text.
use crate::alignment;
-use crate::{Color, Point, Rectangle, Size, Vector};
+use crate::{Color, Point, Rectangle, Size};
+
+use std::borrow::Cow;
/// A paragraph.
#[derive(Debug, Clone, Copy)]
@@ -32,10 +34,6 @@ pub struct Text<'a, Font> {
pub enum Hit {
/// The point was within the bounds of the returned character index.
CharOffset(usize),
- /// The provided point was not within the bounds of a glyph. The index
- /// of the character with the closest centeroid position is returned,
- /// as well as its delta.
- NearestCharOffset(usize, Vector),
}
impl Hit {
@@ -43,13 +41,6 @@ impl Hit {
pub fn cursor(self) -> usize {
match self {
Self::CharOffset(i) => i,
- Self::NearestCharOffset(i, delta) => {
- if delta.x > f32::EPSILON {
- i + 1
- } else {
- i
- }
- }
}
}
}
@@ -57,7 +48,7 @@ impl Hit {
/// A renderer capable of measuring and drawing [`Text`].
pub trait Renderer: crate::Renderer {
/// The font type used.
- type Font: Default + Clone;
+ type Font: Copy;
/// The icon font of the backend.
const ICON_FONT: Self::Font;
@@ -72,6 +63,9 @@ pub trait Renderer: crate::Renderer {
/// [`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;
@@ -109,6 +103,9 @@ pub trait Renderer: crate::Renderer {
nearest_only: bool,
) -> Option<Hit>;
+ /// Loads a [`Self::Font`] from its bytes.
+ fn load_font(&mut self, font: Cow<'static, [u8]>);
+
/// Draws the given [`Text`].
fn fill_text(&mut self, text: Text<'_, Self::Font>);
}
diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs
index 9b69e574..cd8b9c6b 100644
--- a/native/src/widget/checkbox.rs
+++ b/native/src/widget/checkbox.rs
@@ -55,7 +55,7 @@ where
size: f32,
spacing: f32,
text_size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
icon: Icon<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -91,7 +91,7 @@ where
size: Self::DEFAULT_SIZE,
spacing: Self::DEFAULT_SPACING,
text_size: None,
- font: Renderer::Font::default(),
+ font: None,
icon: Icon {
font: Renderer::ICON_FONT,
code_point: Renderer::CHECKMARK_ICON,
@@ -128,8 +128,8 @@ where
/// Sets the [`Font`] of the text of the [`Checkbox`].
///
/// [`Font`]: crate::text::Renderer::Font
- pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.font = Some(font.into());
self
}
@@ -175,7 +175,7 @@ where
.push(Row::new().width(self.size).height(self.size))
.push(
Text::new(&self.label)
- .font(self.font.clone())
+ .font(self.font.unwrap_or_else(|| renderer.default_font()))
.width(self.width)
.size(
self.text_size
@@ -267,12 +267,12 @@ where
code_point,
size,
} = &self.icon;
- let size = size.map(f32::from).unwrap_or(bounds.height * 0.7);
+ let size = size.unwrap_or(bounds.height * 0.7);
if self.is_checked {
renderer.fill_text(text::Text {
content: &code_point.to_string(),
- font: font.clone(),
+ font: *font,
size,
bounds: Rectangle {
x: bounds.center_x(),
@@ -295,7 +295,7 @@ where
label_layout,
&self.label,
self.text_size,
- self.font.clone(),
+ self.font,
widget::text::Appearance {
color: custom_style.text_color,
},
diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs
index 17528db4..8ff82f3b 100644
--- a/native/src/widget/pick_list.rs
+++ b/native/src/widget/pick_list.rs
@@ -35,7 +35,7 @@ where
width: Length,
padding: Padding,
text_size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
handle: Handle<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -70,7 +70,7 @@ where
width: Length::Shrink,
padding: Self::DEFAULT_PADDING,
text_size: None,
- font: Default::default(),
+ font: None,
handle: Default::default(),
style: Default::default(),
}
@@ -101,8 +101,8 @@ where
}
/// Sets the font of the [`PickList`].
- pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.font = Some(font.into());
self
}
@@ -163,7 +163,7 @@ where
self.width,
self.padding,
self.text_size,
- &self.font,
+ self.font,
self.placeholder.as_deref(),
&self.options,
)
@@ -212,6 +212,7 @@ where
cursor_position: Point,
_viewport: &Rectangle,
) {
+ let font = self.font.unwrap_or_else(|| renderer.default_font());
draw(
renderer,
theme,
@@ -219,7 +220,7 @@ where
cursor_position,
self.padding,
self.text_size,
- &self.font,
+ font,
self.placeholder.as_deref(),
self.selected.as_ref(),
&self.handle,
@@ -232,7 +233,7 @@ where
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
- _renderer: &Renderer,
+ renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
let state = tree.state.downcast_mut::<State<T>>();
@@ -241,7 +242,7 @@ where
state,
self.padding,
self.text_size,
- self.font.clone(),
+ self.font.unwrap_or_else(|| renderer.default_font()),
&self.options,
self.style.clone(),
)
@@ -343,7 +344,7 @@ pub fn layout<Renderer, T>(
width: Length,
padding: Padding,
text_size: Option<f32>,
- font: &Renderer::Font,
+ font: Option<Renderer::Font>,
placeholder: Option<&str>,
options: &[T],
) -> layout::Node
@@ -362,7 +363,7 @@ where
let (width, _) = renderer.measure(
label,
text_size,
- font.clone(),
+ font.unwrap_or_else(|| renderer.default_font()),
Size::new(f32::INFINITY, f32::INFINITY),
);
@@ -384,7 +385,7 @@ where
let size = {
let intrinsic =
- Size::new(max_width + text_size + padding.left, text_size);
+ Size::new(max_width + text_size + padding.left, text_size * 1.2);
limits.resolve(intrinsic).pad(padding)
};
@@ -560,7 +561,7 @@ pub fn draw<'a, T, Renderer>(
cursor_position: Point,
padding: Padding,
text_size: Option<f32>,
- font: &Renderer::Font,
+ font: Renderer::Font,
placeholder: Option<&str>,
selected: Option<&T>,
handle: &Handle<Renderer::Font>,
@@ -599,12 +600,12 @@ pub fn draw<'a, T, Renderer>(
font,
code_point,
size,
- }) => Some((font.clone(), *code_point, *size)),
+ }) => Some((*font, *code_point, *size)),
Handle::Dynamic { open, closed } => {
if state().is_open {
- Some((open.font.clone(), open.code_point, open.size))
+ Some((open.font, open.code_point, open.size))
} else {
- Some((closed.font.clone(), closed.code_point, closed.size))
+ Some((closed.font, closed.code_point, closed.size))
}
}
Handle::None => None,
@@ -620,12 +621,12 @@ pub fn draw<'a, T, Renderer>(
color: style.handle_color,
bounds: Rectangle {
x: bounds.x + bounds.width - padding.horizontal(),
- y: bounds.center_y() - size / 2.0,
- height: size,
+ y: bounds.center_y(),
+ height: size * 1.2,
..bounds
},
horizontal_alignment: alignment::Horizontal::Right,
- vertical_alignment: alignment::Vertical::Top,
+ vertical_alignment: alignment::Vertical::Center,
});
}
@@ -637,7 +638,7 @@ pub fn draw<'a, T, Renderer>(
renderer.fill_text(Text {
content: label,
size: text_size,
- font: font.clone(),
+ font,
color: if is_selected {
style.text_color
} else {
@@ -645,12 +646,12 @@ pub fn draw<'a, T, Renderer>(
},
bounds: Rectangle {
x: bounds.x + padding.left,
- y: bounds.center_y() - text_size / 2.0,
+ y: bounds.center_y(),
width: bounds.width - padding.horizontal(),
- height: text_size,
+ height: text_size * 1.2,
},
horizontal_alignment: alignment::Horizontal::Left,
- vertical_alignment: alignment::Vertical::Top,
+ vertical_alignment: alignment::Vertical::Center,
});
}
}
diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs
index 9daddfbc..5f60eaef 100644
--- a/native/src/widget/radio.rs
+++ b/native/src/widget/radio.rs
@@ -53,7 +53,7 @@ where
size: f32,
spacing: f32,
text_size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -95,7 +95,7 @@ where
size: Self::DEFAULT_SIZE,
spacing: Self::DEFAULT_SPACING, //15
text_size: None,
- font: Default::default(),
+ font: None,
style: Default::default(),
}
}
@@ -125,8 +125,8 @@ where
}
/// Sets the text font of the [`Radio`] button.
- pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.font = Some(font.into());
self
}
@@ -275,7 +275,7 @@ where
label_layout,
&self.label,
self.text_size,
- self.font.clone(),
+ self.font,
widget::text::Appearance {
color: custom_style.text_color,
},
diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs
index 3fee48f2..aede754a 100644
--- a/native/src/widget/text.rs
+++ b/native/src/widget/text.rs
@@ -37,7 +37,7 @@ where
height: Length,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -51,7 +51,7 @@ where
Text {
content: content.into(),
size: None,
- font: Default::default(),
+ font: None,
width: Length::Shrink,
height: Length::Shrink,
horizontal_alignment: alignment::Horizontal::Left,
@@ -70,7 +70,7 @@ where
///
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
- self.font = font.into();
+ self.font = Some(font.into());
self
}
@@ -138,8 +138,12 @@ where
let bounds = limits.max();
- let (width, height) =
- renderer.measure(&self.content, size, self.font.clone(), bounds);
+ let (width, height) = renderer.measure(
+ &self.content,
+ size,
+ self.font.unwrap_or_else(|| renderer.default_font()),
+ bounds,
+ );
let size = limits.resolve(Size::new(width, height));
@@ -162,7 +166,7 @@ where
layout,
&self.content,
self.size,
- self.font.clone(),
+ self.font,
theme.appearance(self.style),
self.horizontal_alignment,
self.vertical_alignment,
@@ -186,7 +190,7 @@ pub fn draw<Renderer>(
layout: Layout<'_>,
content: &str,
size: Option<f32>,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
appearance: Appearance,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
@@ -212,7 +216,7 @@ pub fn draw<Renderer>(
size: size.unwrap_or_else(|| renderer.default_size()),
bounds: Rectangle { x, y, ..bounds },
color: appearance.color.unwrap_or(style.text_color),
- font,
+ font: font.unwrap_or_else(|| renderer.default_font()),
horizontal_alignment,
vertical_alignment,
});
@@ -242,7 +246,7 @@ where
height: self.height,
horizontal_alignment: self.horizontal_alignment,
vertical_alignment: self.vertical_alignment,
- font: self.font.clone(),
+ font: self.font,
style: self.style,
}
}
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index ee0473ea..65a9bd3b 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -61,7 +61,7 @@ where
placeholder: String,
value: Value,
is_secure: bool,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
width: Length,
padding: Padding,
size: Option<f32>,
@@ -92,7 +92,7 @@ where
placeholder: String::from(placeholder),
value: Value::new(value),
is_secure: false,
- font: Default::default(),
+ font: None,
width: Length::Fill,
padding: Padding::new(5.0),
size: None,
@@ -129,7 +129,7 @@ where
///
/// [`Font`]: text::Renderer::Font
pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ self.font = Some(font);
self
}
/// Sets the width of the [`TextInput`].
@@ -188,7 +188,7 @@ where
value.unwrap_or(&self.value),
&self.placeholder,
self.size,
- &self.font,
+ self.font,
self.is_secure,
&self.style,
)
@@ -258,7 +258,7 @@ where
shell,
&mut self.value,
self.size,
- &self.font,
+ self.font,
self.is_secure,
self.on_change.as_ref(),
self.on_paste.as_deref(),
@@ -286,7 +286,7 @@ where
&self.value,
&self.placeholder,
self.size,
- &self.font,
+ self.font,
self.is_secure,
&self.style,
)
@@ -385,9 +385,8 @@ where
Renderer: text::Renderer,
{
let text_size = size.unwrap_or_else(|| renderer.default_size());
-
let padding = padding.fit(Size::ZERO, limits.max());
- let limits = limits.width(width).pad(padding).height(text_size);
+ let limits = limits.width(width).pad(padding).height(text_size * 1.2);
let mut text = layout::Node::new(limits.resolve(Size::ZERO));
text.move_to(Point::new(padding.left, padding.top));
@@ -406,7 +405,7 @@ pub fn update<'a, Message, Renderer>(
shell: &mut Shell<'_, Message>,
value: &mut Value,
size: Option<f32>,
- font: &Renderer::Font,
+ font: Option<Renderer::Font>,
is_secure: bool,
on_change: &dyn Fn(String) -> Message,
on_paste: Option<&dyn Fn(String) -> Message>,
@@ -455,7 +454,7 @@ where
find_cursor_position(
renderer,
text_layout.bounds(),
- font.clone(),
+ font,
size,
&value,
state,
@@ -483,7 +482,7 @@ where
let position = find_cursor_position(
renderer,
text_layout.bounds(),
- font.clone(),
+ font,
size,
value,
state,
@@ -532,7 +531,7 @@ where
let position = find_cursor_position(
renderer,
text_layout.bounds(),
- font.clone(),
+ font,
size,
&value,
state,
@@ -812,7 +811,7 @@ pub fn draw<Renderer>(
value: &Value,
placeholder: &str,
size: Option<f32>,
- font: &Renderer::Font,
+ font: Option<Renderer::Font>,
is_secure: bool,
style: &<Renderer::Theme as StyleSheet>::Style,
) where
@@ -846,6 +845,7 @@ pub fn draw<Renderer>(
);
let text = value.to_string();
+ let font = font.unwrap_or_else(|| renderer.default_font());
let size = size.unwrap_or_else(|| renderer.default_size());
let (cursor, offset) = if let Some(focus) = &state.is_focused {
@@ -858,7 +858,7 @@ pub fn draw<Renderer>(
value,
size,
position,
- font.clone(),
+ font,
);
let is_cursor_visible = ((focus.now - focus.updated_at)
@@ -899,7 +899,7 @@ pub fn draw<Renderer>(
value,
size,
left,
- font.clone(),
+ font,
);
let (right_position, right_offset) =
@@ -909,7 +909,7 @@ pub fn draw<Renderer>(
value,
size,
right,
- font.clone(),
+ font,
);
let width = right_position - left_position;
@@ -944,7 +944,7 @@ pub fn draw<Renderer>(
let text_width = renderer.measure_width(
if text.is_empty() { placeholder } else { &text },
size,
- font.clone(),
+ font,
);
let render = |renderer: &mut Renderer| {
@@ -959,7 +959,7 @@ pub fn draw<Renderer>(
} else {
theme.value_color(style)
},
- font: font.clone(),
+ font,
bounds: Rectangle {
y: text_bounds.center_y(),
width: f32::INFINITY,
@@ -1180,7 +1180,7 @@ where
fn find_cursor_position<Renderer>(
renderer: &Renderer,
text_bounds: Rectangle,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
size: Option<f32>,
value: &Value,
state: &State,
@@ -1189,21 +1189,30 @@ fn find_cursor_position<Renderer>(
where
Renderer: text::Renderer,
{
+ let font = font.unwrap_or_else(|| renderer.default_font());
let size = size.unwrap_or_else(|| renderer.default_size());
- let offset =
- offset(renderer, text_bounds, font.clone(), size, value, state);
+ let offset = offset(renderer, text_bounds, font, size, value, state);
+ let value = value.to_string();
- renderer
+ let char_offset = renderer
.hit_test(
- &value.to_string(),
+ &value,
size,
font,
Size::INFINITY,
Point::new(x + offset, text_bounds.height / 2.0),
true,
)
- .map(text::Hit::cursor)
+ .map(text::Hit::cursor)?;
+
+ Some(
+ unicode_segmentation::UnicodeSegmentation::graphemes(
+ &value[..char_offset],
+ true,
+ )
+ .count(),
+ )
}
const CURSOR_BLINK_INTERVAL_MILLIS: u128 = 500;
diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs
index a434af65..d9c80ebe 100644
--- a/native/src/widget/toggler.rs
+++ b/native/src/widget/toggler.rs
@@ -42,7 +42,7 @@ where
text_size: Option<f32>,
text_alignment: alignment::Horizontal,
spacing: f32,
- font: Renderer::Font,
+ font: Option<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@@ -79,7 +79,7 @@ where
text_size: None,
text_alignment: alignment::Horizontal::Left,
spacing: 0.0,
- font: Renderer::Font::default(),
+ font: None,
style: Default::default(),
}
}
@@ -117,8 +117,8 @@ where
/// Sets the [`Font`] of the text of the [`Toggler`]
///
/// [`Font`]: crate::text::Renderer::Font
- pub fn font(mut self, font: Renderer::Font) -> Self {
- self.font = font;
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.font = Some(font.into());
self
}
@@ -160,7 +160,7 @@ where
row = row.push(
Text::new(label)
.horizontal_alignment(self.text_alignment)
- .font(self.font.clone())
+ .font(self.font.unwrap_or_else(|| renderer.default_font()))
.width(self.width)
.size(
self.text_size
@@ -243,7 +243,7 @@ where
label_layout,
label,
self.text_size,
- self.font.clone(),
+ self.font,
Default::default(),
self.text_alignment,
alignment::Vertical::Center,