From b29de28d1f0f608f8029c93d154cfd1b0f8b8cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sat, 4 Feb 2023 07:33:33 +0100 Subject: [PATCH] Overhaul `Font` type to allow font family selection --- core/src/font.rs | 57 +++++------ examples/todos/fonts/icons.ttf | Bin 5596 -> 5732 bytes examples/todos/src/main.rs | 5 +- graphics/fonts/Lato-Regular.ttf | Bin 75136 -> 0 bytes graphics/fonts/OFL.txt | 93 ------------------ graphics/src/backend.rs | 3 + graphics/src/layer.rs | 2 +- graphics/src/renderer.rs | 4 + graphics/src/widget/canvas/text.rs | 2 +- native/src/overlay/menu.rs | 12 +-- native/src/renderer/null.rs | 8 +- native/src/text.rs | 5 +- native/src/widget/checkbox.rs | 13 +-- native/src/widget/pick_list.rs | 25 ++--- native/src/widget/radio.rs | 11 ++- native/src/widget/text.rs | 20 ++-- native/src/widget/text_input.rs | 39 ++++---- native/src/widget/toggler.rs | 13 +-- src/application.rs | 1 - src/settings.rs | 18 +--- .../Icons.ttf => wgpu/fonts/Iced-Icons.ttf | Bin 5032 -> 5108 bytes wgpu/src/backend.rs | 21 ++-- wgpu/src/lib.rs | 4 +- wgpu/src/settings.rs | 37 ++----- wgpu/src/text.rs | 10 +- 25 files changed, 147 insertions(+), 256 deletions(-) delete mode 100644 graphics/fonts/Lato-Regular.ttf delete mode 100644 graphics/fonts/OFL.txt rename graphics/fonts/Icons.ttf => wgpu/fonts/Iced-Icons.ttf (62%) diff --git a/core/src/font.rs b/core/src/font.rs index 130e378e..1f774a70 100644 --- a/core/src/font.rs +++ b/core/src/font.rs @@ -1,40 +1,29 @@ -use std::hash::{Hash, Hasher}; +use std::hash::Hash; /// A font. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Font { - /// The default font. - /// - /// This is normally a font configured in a renderer or loaded from the - /// system. - Default, + /// The name of a font family of choice. + Name(&'static str), - /// An external font. - External { - /// The name of the external font - name: &'static str, + /// Serif fonts represent the formal text style for a script. + Serif, - /// The bytes of the external font - bytes: &'static [u8], - }, -} - -impl Default for Font { - fn default() -> Font { - Font::Default - } -} - -impl Hash for Font { - fn hash(&self, hasher: &mut H) { - match self { - Self::Default => { - 0.hash(hasher); - } - Self::External { name, .. } => { - 1.hash(hasher); - name.hash(hasher); - } - } - } + /// Glyphs in sans-serif fonts, as the term is used in CSS, are generally low + /// contrast and have stroke endings that are plain — without any flaring, + /// cross stroke, or other ornamentation. + SansSerif, + + /// Glyphs in cursive fonts generally use a more informal script style, and + /// the result looks more like handwritten pen or brush writing than printed + /// letterwork. + Cursive, + + /// Fantasy fonts are primarily decorative or expressive fonts that contain + /// decorative or expressive representations of characters. + Fantasy, + + /// The sole criterion of a monospace font is that all glyphs have the same + /// fixed width. + Monospace, } diff --git a/examples/todos/fonts/icons.ttf b/examples/todos/fonts/icons.ttf index 4498299db26811ff8490001ea6f681529a4118f4..7b65fd3634a48b1afc3bebe7b3bb83a6c4f508d7 100644 GIT binary patch delta 1263 zcma)6O=uHA6#iy6-8M#>)}JC6a6wTaO&ep?QnVt}XvH6}Au1GQ*=&<)l3kNk^pu;5 zCuLFbCjOx4N%SNhJqV)oQcw^Tj3R;u1yK~K-)yH<@#4VS_q{joe`fYYvf15$0MNlt z1juG{J1;%GdJE{uh#E)Z#O3&(3gah;WRjmdzhb*3 zpdtBd{q{v*>W+Rr7&MlyzaHAljhSVH8Uv$f2~`>r=tiA*oYCbHx)eP(2hxkb>#6;;RsA|MBx^6 ziE9cQ)IU;q4)WrM!ZEDS8bNQ{VS(UG>smHC3>yv#NFfK8+~s+tLamFcJiB4rDWr04 z!L6r;ZMRCz9y%0plvA-#qv#ZmmMwxTovZLeUZaJ>1~TYDntXsXlggY;)u=1=bgpT$ zKIYGalqO%pxNggZf9DAMneiT-ZYa-E zYwUGAY{10ouxR9+T7BHDnyY)#zvKS@oPwWidpYJ$tx0}IqN^5`eBT@B?Hyw~PPy#% z*lq>EiRf}$zAgbxXhIhe%{|=W*Q|QU@SLhWUJm!f)D+_3g^|C84*r$o4Udo{7mCy) Nc=i0gwEFAa{sQaH*{A>j delta 1080 zcmZ8fOK1~O6g_WdGHo-`RMQkGmByl0N$d|>v^0fEs4h~KHbz9DjBzrFon*#jDzykL z2wiCLH_(+L2!ab;NVlRJH{xffA_{IQ)SX3yB0{`x`U2WF+_~qRd*{60ti->>=D+}i zFb^5dk%^Osqt|!OlJbWleSD(3Z#16X39u8yGufiNSgQp7)^yBdN2$rIhsnN(bC-#TA`562S1&EF|!J$ zj(SmHRO3}f3WHix<(u9jOZN~BP{t*V zN!)^|-bLxNH!tlyw8if@;J!mtqMEO_QOa zU(n=LZuMzxm~TMj>Qi~u8({6JRo?sGP&=#oUQXvX05qfpR!N@}IEWZbfi;A2hwoNtpeZll zp}-7HEVO}-(V7}ryC}$1*e|d`I3aKVEo@9+mGrE@L1b7(U=4fNEAK|Qzb|K(T*I>L zal@Rp^m2{Xa>giE3U(>l+tpK(yy-|RoOfMku)Djab!F|M*Abq|=3t`)7X~bPY>X2! zF-=%U8Jnw{d4{^nbmRr!C5m2j(f_@v%i9q- Element<'_, Message> { } // Fonts -const ICONS: Font = Font::External { - name: "Icons", - bytes: include_bytes!("../../todos/fonts/icons.ttf"), -}; +const ICONS: Font = Font::Name("Iced-Todos-Icons"); fn icon(unicode: char) -> Text<'static> { text(unicode.to_string()) diff --git a/graphics/fonts/Lato-Regular.ttf b/graphics/fonts/Lato-Regular.ttf deleted file mode 100644 index 33eba8b192384487f04951539f13bf1f8dd9f9cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75136 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 ojk(g9PAtLVP?*9aY%s*7 Font; + /// Returns the default size of text. fn default_size(&self) -> f32; diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs index cc8f299c..f6eb2fdd 100644 --- a/graphics/src/layer.rs +++ b/graphics/src/layer.rs @@ -63,7 +63,7 @@ impl<'a> Layer<'a> { ), color: Color::new(0.9, 0.9, 0.9, 1.0), size: 20.0, - font: Font::Default, + font: Font::Monospace, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, }; diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 34b6eb1d..7ad53dec 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -130,6 +130,10 @@ where const CHECKMARK_ICON: char = B::CHECKMARK_ICON; const ARROW_DOWN_ICON: char = B::ARROW_DOWN_ICON; + fn default_font(&self) -> Self::Font { + self.backend().default_font() + } + fn default_size(&self) -> f32 { self.backend().default_size() } diff --git a/graphics/src/widget/canvas/text.rs b/graphics/src/widget/canvas/text.rs index 056f8204..8c0b2dfb 100644 --- a/graphics/src/widget/canvas/text.rs +++ b/graphics/src/widget/canvas/text.rs @@ -34,7 +34,7 @@ impl Default for Text { position: Point::ORIGIN, color: Color::BLACK, size: 16.0, - font: Font::Default, + font: Font::SansSerif, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, } diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs index 50f741ef..9c3a8a44 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, - font: Renderer::Font, + font: Option, style: ::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) -> Self { + self.font = Some(font.into()); self } @@ -311,7 +311,7 @@ where last_selection: &'a mut Option, padding: Padding, text_size: Option, - font: Renderer::Font, + font: Option, style: ::Style, } @@ -491,7 +491,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/renderer/null.rs b/native/src/renderer/null.rs index 9376d540..50d7d6d6 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -40,12 +40,16 @@ 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 measure( diff --git a/native/src/text.rs b/native/src/text.rs index 55c3cfd3..b7915a55 100644 --- a/native/src/text.rs +++ b/native/src/text.rs @@ -57,7 +57,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 +72,9 @@ pub trait Renderer: crate::Renderer { /// [`ICON_FONT`]: Self::ICON_FONT const ARROW_DOWN_ICON: char; + /// Returns the default [`Font`]. + fn default_font(&self) -> Self::Font; + /// Returns the default size of [`Text`]. fn default_size(&self) -> f32; diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 9b69e574..138c458c 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, - font: Renderer::Font, + font: Option, icon: Icon, style: ::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) -> 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 @@ -288,6 +288,7 @@ where { let label_layout = children.next().unwrap(); + let font = self.font.unwrap_or_else(|| renderer.default_font()); widget::text::draw( renderer, @@ -295,7 +296,7 @@ where label_layout, &self.label, self.text_size, - self.font.clone(), + 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 a128d1ae..c1ff0004 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, - font: Renderer::Font, + font: Option, handle: Handle, style: ::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) -> Self { + self.font = Some(font.into()); self } @@ -163,7 +163,7 @@ where self.width, self.padding, self.text_size, - &self.font, + self.font.unwrap_or_else(|| renderer.default_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> { let state = tree.state.downcast_mut::>(); @@ -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( width: Length, padding: Padding, text_size: Option, - font: &Renderer::Font, + font: Renderer::Font, placeholder: Option<&str>, options: &[T], ) -> layout::Node @@ -362,7 +363,7 @@ where let (width, _) = renderer.measure( label, text_size, - font.clone(), + font, Size::new(f32::INFINITY, f32::INFINITY), ); @@ -560,7 +561,7 @@ pub fn draw<'a, T, Renderer>( cursor_position: Point, padding: Padding, text_size: Option, - font: &Renderer::Font, + font: Renderer::Font, placeholder: Option<&str>, selected: Option<&T>, handle: &Handle, @@ -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 { diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 9daddfbc..bd803910 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, - font: Renderer::Font, + font: Option, style: ::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) -> Self { + self.font = Some(font.into()); self } @@ -268,6 +268,7 @@ where { let label_layout = children.next().unwrap(); + let font = self.font.unwrap_or(renderer.default_font()); widget::text::draw( renderer, @@ -275,7 +276,7 @@ where label_layout, &self.label, self.text_size, - self.font.clone(), + 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..235a027e 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, style: ::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) -> 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)); @@ -156,13 +160,15 @@ where _cursor_position: Point, _viewport: &Rectangle, ) { + let font = self.font.unwrap_or_else(|| renderer.default_font()); + draw( renderer, style, layout, &self.content, self.size, - self.font.clone(), + font, theme.appearance(self.style), self.horizontal_alignment, self.vertical_alignment, @@ -242,7 +248,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 5e198b8f..e6b70db2 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, width: Length, padding: Padding, size: Option, @@ -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`]. @@ -179,6 +179,8 @@ where cursor_position: Point, value: Option<&Value>, ) { + let font = self.font.unwrap_or(renderer.default_font()); + draw( renderer, theme, @@ -188,7 +190,7 @@ where value.unwrap_or(&self.value), &self.placeholder, self.size, - &self.font, + font, self.is_secure, &self.style, ) @@ -258,7 +260,7 @@ where shell, &mut self.value, self.size, - &self.font, + self.font.unwrap_or(renderer.default_font()), self.is_secure, self.on_change.as_ref(), self.on_paste.as_deref(), @@ -277,6 +279,8 @@ where cursor_position: Point, _viewport: &Rectangle, ) { + let font = self.font.unwrap_or(renderer.default_font()); + draw( renderer, theme, @@ -286,7 +290,7 @@ where &self.value, &self.placeholder, self.size, - &self.font, + font, self.is_secure, &self.style, ) @@ -410,7 +414,7 @@ pub fn update<'a, Message, Renderer>( shell: &mut Shell<'_, Message>, value: &mut Value, size: Option, - font: &Renderer::Font, + font: Renderer::Font, is_secure: bool, on_change: &dyn Fn(String) -> Message, on_paste: Option<&dyn Fn(String) -> Message>, @@ -459,7 +463,7 @@ where find_cursor_position( renderer, text_layout.bounds(), - font.clone(), + font, size, &value, state, @@ -487,7 +491,7 @@ where let position = find_cursor_position( renderer, text_layout.bounds(), - font.clone(), + font, size, value, state, @@ -536,7 +540,7 @@ where let position = find_cursor_position( renderer, text_layout.bounds(), - font.clone(), + font, size, &value, state, @@ -816,7 +820,7 @@ pub fn draw( value: &Value, placeholder: &str, size: Option, - font: &Renderer::Font, + font: Renderer::Font, is_secure: bool, style: &::Style, ) where @@ -862,7 +866,7 @@ pub fn draw( value, size, position, - font.clone(), + font, ); let is_cursor_visible = ((focus.now - focus.updated_at) @@ -903,7 +907,7 @@ pub fn draw( value, size, left, - font.clone(), + font, ); let (right_position, right_offset) = @@ -913,7 +917,7 @@ pub fn draw( value, size, right, - font.clone(), + font, ); let width = right_position - left_position; @@ -948,7 +952,7 @@ pub fn draw( let text_width = renderer.measure_width( if text.is_empty() { placeholder } else { &text }, size, - font.clone(), + font, ); let render = |renderer: &mut Renderer| { @@ -963,7 +967,7 @@ pub fn draw( } else { theme.value_color(style) }, - font: font.clone(), + font: font, bounds: Rectangle { y: text_bounds.center_y(), width: f32::INFINITY, @@ -1195,8 +1199,7 @@ where { 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); renderer .hit_test( diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs index a434af65..495406db 100644 --- a/native/src/widget/toggler.rs +++ b/native/src/widget/toggler.rs @@ -42,7 +42,7 @@ where text_size: Option, text_alignment: alignment::Horizontal, spacing: f32, - font: Renderer::Font, + font: Option, style: ::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) -> 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 @@ -236,6 +236,7 @@ where if let Some(label) = &self.label { let label_layout = children.next().unwrap(); + let font = self.font.unwrap_or_else(|| renderer.default_font()); crate::widget::text::draw( renderer, @@ -243,7 +244,7 @@ where label_layout, label, self.text_size, - self.font.clone(), + font, Default::default(), self.text_alignment, alignment::Vertical::Center, diff --git a/src/application.rs b/src/application.rs index 1db5c93f..9a1c1855 100644 --- a/src/application.rs +++ b/src/application.rs @@ -197,7 +197,6 @@ pub trait Application: Sized { let renderer_settings = crate::renderer::Settings { default_font: settings.default_font, default_text_size: settings.default_text_size, - text_multithreading: settings.text_multithreading, antialiasing: if settings.antialiasing { Some(crate::renderer::settings::Antialiasing::MSAAx4) } else { diff --git a/src/settings.rs b/src/settings.rs index 266ad404..ce07b0dd 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,5 +1,6 @@ //! Configure your application. use crate::window; +use crate::Font; /// The settings of an application. #[derive(Debug, Clone)] @@ -20,23 +21,16 @@ pub struct Settings { /// [`Application`]: crate::Application pub flags: Flags, - /// The bytes of the font that will be used by default. + /// The default [`Font`] to be used. /// - /// If `None` is provided, a default system font will be chosen. - // TODO: Add `name` for web compatibility - pub default_font: Option<&'static [u8]>, + /// By default, it uses [`Font::SansSerif`]. + pub default_font: Font, /// The text size that will be used by default. /// /// The default value is `16.0`. pub default_text_size: f32, - /// If enabled, spread text workload in multiple threads when multiple cores - /// are available. - /// - /// By default, it is disabled. - pub text_multithreading: bool, - /// If set to true, the renderer will try to perform antialiasing for some /// primitives. /// @@ -79,7 +73,6 @@ impl Settings { window: default_settings.window, default_font: default_settings.default_font, default_text_size: default_settings.default_text_size, - text_multithreading: default_settings.text_multithreading, antialiasing: default_settings.antialiasing, exit_on_close_request: default_settings.exit_on_close_request, try_opengles_first: default_settings.try_opengles_first, @@ -96,9 +89,8 @@ where id: None, window: Default::default(), flags: Default::default(), - default_font: Default::default(), + default_font: Font::SansSerif, default_text_size: 16.0, - text_multithreading: false, antialiasing: false, exit_on_close_request: true, try_opengles_first: false, diff --git a/graphics/fonts/Icons.ttf b/wgpu/fonts/Iced-Icons.ttf similarity index 62% rename from graphics/fonts/Icons.ttf rename to wgpu/fonts/Iced-Icons.ttf index 5e455b6988de00cc4a4e928aec96a27f555669a3..7112f08621071c423bf130f2906de1f878b6acbe 100644 GIT binary patch delta 1197 zcmah|T}YEr7=F%owpp8~

F*FR&)aY%MLb9}3n&!+uOw5m{sVoTl41<}8C?cTrtc z-&F-&1cFqA;EhBVL3CS01Xj=w5omPbg@Ik!bG{wz=cbMKywCe{p7Xx%Ip26_K2(AL zP{YLo#N$0(x9=YM4%AN5TYn(7KaLRUXiw2L4K25Sp+S~f+@coo0Xvb(b^k<8sffFDWpJ)e%>{JqsILrOaL1i{Mn#Us?WW1lY znM-D^`H`2mcxD5OIGVSIi?idgBP?K)@wR-S&B}k>*YpIaQWaf>ng(UZ?(w-Z)w_OR zy_}&3@1A~3DE&#^ze*+Kn6uVX-%idkcZ-TG{k*Qni#0l8z(+jHa5L7qNkXo2dPGmD z%uTv3z}QK$8Pyu3mU>MPqesyTnj`z&J>|Q*lWI0)lS7kqNw#hCTgK#d(!4j|paQQome?pl8hhXuDUH1di1O4`Uw$#J{eCnV0gVHwHO{CRcvi9wRhjH{4S^u; z>41SMJkwaB6Yn+lAjt8SH}g(JPGcYaH#PPnAtp5rV3V=kk-k9zr`OxcMmvy#g)~eT z*~qE8>_}N@vm<5ah`SliV1zSBqCnHij0`0S;!w#&R~MLJks``R5TS0@bpH~UBP|Fs zQ%NbpWh=StTrqAJGL{)_j+pH{dg*)`E#YW58i_LPzqKY4GUYQFk0JckI0K9p`wSdz-k1DjJF|82`PQb=`KXQ8!e&IE1F+-vmpll}gDDD~YbA5ZSP@H}(ZOp6JrzNRIt5Y}4+;^%_ItatA-?5%-|x@&zBli^-EY}!$wL6p zu?iLT@c6`4<6-kXDt{T_8{^%*1IFk+AV$e2BPr9~SoyR=zR6gN+|3!@&jk-qxk2BU zvty|Tk2j{t-vF8&GqX1JYVvhvUo5#YHyqsQ2h<+&t$5VT&o-<#v{Bfja4t@zGN?`f zo>uavcq+H-*NET=ajHsM5fiPrLq0|BOPR|yUTZJNsliB_sp$6e`Udh2-dJV8Db{#dC7|qLuc}Z0%9)k2 zeQ5)Q#Os*KcgI$mx~u4ccTyVkc8O%j{(E#~fO>I1IP?05{2=GOzK|~+0bdS&y`0f6 z9Y9ly3%_ptl-GiCR(F+Wq`qPoX>gr7R+#6^`a*%T>~wgj(ors!DvE}DHCd&i&aGDR zJWw676uUIrU0sWB|C{wuD>at)+gDzON(5c3QXg`$hdAWo3TOzs*h_uJ#eTFS=3))` z0G`Nq@Eqet^LXWAfoh?zNOFiOZKPE-i#Tw3tkAs%I zl1aqkIiq#3&FJlM?$Y*2?+i@b*Eo9-d Self { - let text_pipeline = text::Pipeline::new( - device, - queue, - format, - settings.default_font, - settings.text_multithreading, - ); - + let text_pipeline = text::Pipeline::new(device, queue, format); let quad_pipeline = quad::Pipeline::new(device, format); let triangle_pipeline = triangle::Pipeline::new(device, format, settings.antialiasing); @@ -61,6 +55,7 @@ impl Backend { #[cfg(any(feature = "image", feature = "svg"))] image_pipeline, + default_font: settings.default_font, default_text_size: settings.default_text_size, } } @@ -199,9 +194,13 @@ impl iced_graphics::Backend for Backend { } impl backend::Text for Backend { - const ICON_FONT: Font = Font::Default; // TODO - const CHECKMARK_ICON: char = '✓'; - const ARROW_DOWN_ICON: char = '▼'; + const ICON_FONT: Font = Font::Name("Iced-Icons"); + const CHECKMARK_ICON: char = '\u{e800}'; + const ARROW_DOWN_ICON: char = '\u{f00c}'; + + fn default_font(&self) -> Font { + self.default_font + } fn default_size(&self) -> f32 { self.default_text_size diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 1a293681..6d6d3fd6 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -47,7 +47,9 @@ mod quad; mod text; mod triangle; -pub use iced_graphics::{Antialiasing, Color, Error, Primitive, Viewport}; +pub use iced_graphics::{ + Antialiasing, Color, Error, Font, Primitive, Viewport, +}; pub use iced_native::Theme; pub use wgpu; diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs index 5ef79499..bd9cf473 100644 --- a/wgpu/src/settings.rs +++ b/wgpu/src/settings.rs @@ -1,12 +1,12 @@ //! Configure a renderer. -use std::fmt; - pub use crate::Antialiasing; +use crate::Font; + /// The settings of a [`Backend`]. /// /// [`Backend`]: crate::Backend -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Settings { /// The present mode of the [`Backend`]. /// @@ -16,42 +16,20 @@ pub struct Settings { /// The internal graphics backend to use. pub internal_backend: wgpu::Backends, - /// The bytes of the font that will be used by default. - /// - /// If `None` is provided, a default system font will be chosen. - pub default_font: Option<&'static [u8]>, + /// The default [`Font`] to use. + pub default_font: Font, /// The default size of text. /// /// By default, it will be set to `16.0`. pub default_text_size: f32, - /// If enabled, spread text workload in multiple threads when multiple cores - /// are available. - /// - /// By default, it is disabled. - pub text_multithreading: bool, - /// The antialiasing strategy that will be used for triangle primitives. /// /// By default, it is `None`. pub antialiasing: Option, } -impl fmt::Debug for Settings { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Settings") - .field("present_mode", &self.present_mode) - .field("internal_backend", &self.internal_backend) - // Instead of printing the font bytes, we simply show a `bool` indicating if using a default font or not. - .field("default_font", &self.default_font.is_some()) - .field("default_text_size", &self.default_text_size) - .field("text_multithreading", &self.text_multithreading) - .field("antialiasing", &self.antialiasing) - .finish() - } -} - impl Settings { /// Creates new [`Settings`] using environment configuration. /// @@ -81,9 +59,8 @@ impl Default for Settings { Settings { present_mode: wgpu::PresentMode::AutoVsync, internal_backend: wgpu::Backends::all(), - default_font: None, - default_text_size: 20.0, - text_multithreading: false, + default_font: Font::SansSerif, + default_text_size: 16.0, antialiasing: None, } } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index fa7fd5df..083d9d2b 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -112,8 +112,6 @@ impl Pipeline { device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat, - _default_font: Option<&[u8]>, - _multithreading: bool, ) -> Self { Pipeline { renderers: Vec::new(), @@ -316,7 +314,11 @@ impl Pipeline { fn to_family(font: Font) -> glyphon::Family<'static> { match font { - Font::Default => glyphon::Family::SansSerif, - Font::External { name, .. } => glyphon::Family::Name(name), + Font::Name(name) => glyphon::Family::Name(name), + Font::SansSerif => glyphon::Family::SansSerif, + Font::Serif => glyphon::Family::Serif, + Font::Cursive => glyphon::Family::Cursive, + Font::Fantasy => glyphon::Family::Fantasy, + Font::Monospace => glyphon::Family::Monospace, } }