From 480401d65d30ed9126e8948d822f77f0a7015965 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 27 Jul 2023 18:23:23 -0600 Subject: [PATCH] WIP --- Cargo.lock | 4 +- crates/gpui/Cargo.toml | 1 - crates/gpui/playground/ui/Cargo.toml | 3 + .../elements => playground/ui/src}/node.rs | 291 +++++++++++------- .../gpui/playground/ui/src/playground_ui.rs | 36 ++- crates/gpui/playground/ui/src/tokens.rs | 20 +- crates/gpui/src/app.rs | 4 +- crates/gpui/src/app/window.rs | 24 +- crates/gpui/src/color.rs | 2 +- crates/gpui/src/elements.rs | 14 +- crates/gpui/src/elements/text.rs | 52 ---- crates/gpui/src/fonts.rs | 41 +-- 12 files changed, 242 insertions(+), 250 deletions(-) rename crates/gpui/{src/elements => playground/ui/src}/node.rs (88%) diff --git a/Cargo.lock b/Cargo.lock index 2bd912446e..80ce418aa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3085,7 +3085,6 @@ dependencies = [ "metal", "num_cpus", "objc", - "optional_struct", "ordered-float", "parking", "parking_lot 0.11.2", @@ -5175,7 +5174,10 @@ dependencies = [ name = "playground_ui" version = "0.1.0" dependencies = [ + "derive_more", "gpui", + "log", + "optional_struct", ] [[package]] diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 8920f27862..8721327c33 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -31,7 +31,6 @@ itertools = "0.10" lazy_static.workspace = true log.workspace = true num_cpus = "1.13" -optional_struct = "0.3.1" ordered-float.workspace = true parking = "2.0.0" parking_lot.workspace = true diff --git a/crates/gpui/playground/ui/Cargo.toml b/crates/gpui/playground/ui/Cargo.toml index c57dc508f1..1ff8b7f50a 100644 --- a/crates/gpui/playground/ui/Cargo.toml +++ b/crates/gpui/playground/ui/Cargo.toml @@ -9,4 +9,7 @@ path = "src/playground_ui.rs" crate-type = ["dylib"] [dependencies] +derive_more = "0.99.17" gpui = { path = "../.." } +log.workspace = true +optional_struct = "0.3.1" diff --git a/crates/gpui/src/elements/node.rs b/crates/gpui/playground/ui/src/node.rs similarity index 88% rename from crates/gpui/src/elements/node.rs rename to crates/gpui/playground/ui/src/node.rs index e0cfafbdcb..41d5de13bd 100644 --- a/crates/gpui/src/elements/node.rs +++ b/crates/gpui/playground/ui/src/node.rs @@ -1,5 +1,6 @@ -use super::layout_highlighted_chunks; -use crate::{ +use derive_more::Add; +use gpui::elements::layout_highlighted_chunks; +use gpui::{ color::Color, fonts::HighlightStyle, geometry::{ @@ -11,9 +12,8 @@ use crate::{ serde_json::Value, text_layout::{Line, ShapedBoundary}, AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder, - SizeConstraint, Vector2FExt, View, ViewContext, + SizeConstraint, View, ViewContext, }; -use derive_more::Add; use length::{Length, Rems}; use log::warn; use optional_struct::*; @@ -28,6 +28,7 @@ use std::{ pub struct Node { style: NodeStyle, children: Vec>, + id: Option>, } pub fn node(child: impl Element) -> Node { @@ -44,7 +45,7 @@ pub fn row() -> Node { axis: Axis3d::X, ..Default::default() }, - children: Default::default(), + ..Default::default() } } @@ -54,7 +55,7 @@ pub fn stack() -> Node { axis: Axis3d::Z, ..Default::default() }, - children: Default::default(), + ..Default::default() } } @@ -63,11 +64,17 @@ impl Default for Node { Self { style: Default::default(), children: Default::default(), + id: None, } } } impl Node { + pub fn id(mut self, id: impl Into>) -> Self { + self.id = Some(id.into()); + self + } + pub fn child(mut self, child: impl Element) -> Self { self.children.push(child.into_any()); self @@ -148,26 +155,65 @@ impl Node { view: &mut V, cx: &mut LayoutContext, ) -> Vector2F { - layout.margins = self.style.margins.fixed_pixels(rem_pixels); - layout.padding = self.style.padding.fixed_pixels(rem_pixels); + eprintln!( + "{}: max_size = {:?}", + self.id.as_deref().unwrap_or(""), + max_size + ); - let padded_max = - max_size - layout.margins.size() - self.style.borders.width - layout.padding.size(); - let mut remaining_length = padded_max.get(axis); + let mut remaining_flex: f32 = 0.; + layout.margins = self.style.margins.fixed_pixels(rem_pixels); + remaining_flex += self.style.margins.flex().get(axis); + layout.padding = self.style.padding.fixed_pixels(rem_pixels); + remaining_flex += self.style.padding.flex().get(axis); + + let mut padded_max = + max_size - layout.margins.size() - self.style.borders.size() - layout.padding.size(); + + match self.style.size.width { + Length::Hug => {} + Length::Fixed(width) => { + padded_max.set_x(width.to_pixels(rem_pixels)); + } + Length::Auto { min, max, .. } => padded_max.set_x( + padded_max + .x() + .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)), + ), + }; + match self.style.size.height { + Length::Hug => {} + Length::Fixed(height) => padded_max.set_y(height.to_pixels(rem_pixels)), + Length::Auto { min, max, .. } => padded_max.set_y( + padded_max + .y() + .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)), + ), + }; + + let mut remaining_length = + padded_max.get(axis) - self.style.size.get(axis).fixed_pixels(rem_pixels); + dbg!(padded_max, remaining_length); // Pass 1: Total up flex units and layout inflexible children. // // Consume the remaining length as we layout inflexible children, so that any // remaining length can be distributed among flexible children in the next pass. - let mut remaining_flex: f32 = 0.; let mut cross_axis_max: f32 = 0.; let cross_axis = axis.rotate(); // Fixed children are unconstrained along the primary axis, and constrained to // the padded max size along the cross axis. - let mut child_constraint = + let child_constraint = SizeConstraint::loose(Vector2F::infinity().set(cross_axis, padded_max.get(cross_axis))); + eprintln!( + "{}: child_max = {:?}, remaining_length: {}", + self.id.as_deref().unwrap_or(""), + child_constraint.max, + remaining_length + ); + for child in &mut self.children { if let Some(child_flex) = child .metadata::() @@ -181,14 +227,26 @@ impl Node { } } + eprintln!( + "{}: child_max = {:?}, remaining_length: {}", + self.id.as_deref().unwrap_or(""), + child_constraint.max, + remaining_length + ); + // Pass 2: Allocate the remaining space among flexible lengths along the primary axis. if remaining_flex > 0. { + dbg!(self.id.as_deref(), remaining_length, remaining_flex); + // Add flex pixels from margin and padding. *layout.margins.start_mut(axis) += self.style.margins.start(axis).flex_pixels( rem_pixels, &mut remaining_flex, &mut remaining_length, ); + + dbg!(self.id.as_deref(), layout.margins.start(axis)); + *layout.padding.start_mut(axis) += self.style.padding.start(axis).flex_pixels( rem_pixels, &mut remaining_flex, @@ -224,16 +282,6 @@ impl Node { ); } - let mut size = max_size; - - match self.style.size.get(axis) { - Length::Hug => { - size.set(axis, max_size.get(axis) - remaining_length); - } - Length::Fixed(_) => {} - Length::Auto { flex, min, max } => todo!(), - }; - let width = match self.style.size.width { Length::Hug => match axis { Axis2d::X => max_size.get(axis) - remaining_length, @@ -245,7 +293,7 @@ impl Node { } }, Length::Fixed(width) => width.to_pixels(rem_pixels), - Length::Auto { flex, min, max } => max_size + Length::Auto { min, max, .. } => max_size .x() .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)), }; @@ -261,16 +309,19 @@ impl Node { } }, Length::Fixed(height) => height.to_pixels(rem_pixels), - Length::Auto { flex, min, max } => max_size + Length::Auto { min, max, .. } => max_size .y() .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)), }; - let length = max_size.get(axis) - remaining_length; - match axis { - Axis2d::X => vec2f(length, cross_axis_max), - Axis2d::Y => vec2f(cross_axis_max, length), - } + eprintln!( + "{}: size = {} {}", + self.id.as_deref().unwrap_or(""), + width, + height + ); + + vec2f(width, height) } fn paint_children_xy( @@ -287,99 +338,45 @@ impl Node { let mut child_origin = bounds.origin(); // Align all children together along the primary axis - let mut align_horizontally = false; - let mut align_vertically = false; - match axis { - Axis2d::X => align_horizontally = true, - Axis2d::Y => align_vertically = true, - } - align_child( - &mut child_origin, - parent_size, - layout.content_size, - self.style.align.0, - align_horizontally, - align_vertically, - ); + // let mut align_horizontally = false; + // let mut align_vertically = false; + // match axis { + // Axis2d::X => align_horizontally = true, + // Axis2d::Y => align_vertically = true, + // } + // align_child( + // &mut child_origin, + // parent_size, + // layout.content_size, + // self.style.align.0, + // align_horizontally, + // align_vertically, + // ); for child in &mut self.children { // Align each child along the cross axis - align_horizontally = !align_horizontally; - align_vertically = !align_vertically; - align_child( - &mut child_origin, - parent_size, - child.size(), - self.style.align.0, - align_horizontally, - align_vertically, + // align_horizontally = !align_horizontally; + // align_vertically = !align_vertically; + // align_child( + // &mut child_origin, + // parent_size, + // child.size(), + // self.style.align.0, + // align_horizontally, + // align_vertically, + // ); + // + eprintln!( + "{}: child origin {:?}", + self.id.as_deref().unwrap_or(""), + child_origin ); - child.paint(scene, child_origin, visible_bounds, view, cx); // Advance along the primary axis by the size of this child - match axis { - Axis2d::X => child_origin.set_x(child_origin.x() + child.size().x()), - Axis2d::Y => child_origin.set_y(child_origin.y() + child.size().y()), - } + child_origin.set(axis, child_origin.get(axis) + child.size().get(axis)); } } - - // fn layout_stacked_children( - // &mut self, - // constraint: SizeConstraint, - // view: &mut V, - // cx: &mut LayoutContext, - // ) -> Vector2F { - // let mut size = Vector2F::zero(); - - // for child in &mut self.children { - // let child_size = child.layout(constraint, view, cx); - // size.set_x(size.x().max(child_size.x())); - // size.set_y(size.y().max(child_size.y())); - // } - - // size - // } - - // fn inset_size(&self, rem_size: f32) -> Vector2F { - // todo!() - // // self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size) - // } - - // - // fn margin_fixed_size(&self, rem_size: f32) -> Vector2F { - // self.style.margins.fixed().to_pixels(rem_size) - // } - - // fn padding_size(&self, rem_size: f32) -> Vector2F { - // // We need to account for auto padding - // todo!() - // // vec2f( - // // (self.style.padding.left + self.style.padding.right).to_pixels(rem_size), - // // (self.style.padding.top + self.style.padding.bottom).to_pixels(rem_size), - // // ) - // } - - // fn border_size(&self) -> Vector2F { - // let mut x = 0.0; - // if self.style.borders.left { - // x += self.style.borders.width; - // } - // if self.style.borders.right { - // x += self.style.borders.width; - // } - - // let mut y = 0.0; - // if self.style.borders.top { - // y += self.style.borders.width; - // } - // if self.style.borders.bottom { - // y += self.style.borders.width; - // } - - // vec2f(x, y) - // } } impl Element for Node { @@ -412,7 +409,8 @@ impl Element for Node { view: &mut V, cx: &mut PaintContext, ) -> Self::PaintState { - let rem_pixels = cx.rem_pixels(); + dbg!(&layout); + let margined_bounds = RectF::from_points( bounds.origin() + vec2f(layout.margins.left, layout.margins.top), bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom), @@ -442,6 +440,12 @@ impl Element for Node { let Fill::Color(fill_color) = self.style.fill; let is_fill_visible = !fill_color.is_fully_transparent(); if is_fill_visible || self.style.borders.is_visible() { + eprintln!( + "{}: paint background: {:?}", + self.id.as_deref().unwrap_or(""), + margined_bounds + ); + scene.push_quad(Quad { bounds: margined_bounds, background: is_fill_visible.then_some(fill_color), @@ -688,8 +692,7 @@ impl Size { } } -// Sides? -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] struct Edges { top: T, bottom: T, @@ -1083,7 +1086,7 @@ pub fn text(text: impl Into>) -> Node { }) } -#[derive(Default)] +#[derive(Default, Debug)] pub struct NodeLayout { content_size: Vector2F, margins: Edges, @@ -1194,6 +1197,8 @@ impl Element for Text { _: &mut V, cx: &mut PaintContext, ) -> Self::PaintState { + dbg!(bounds); + let mut origin = bounds.origin(); let empty = Vec::new(); let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {}; @@ -1375,3 +1380,53 @@ where (None, None) => None, } } + +trait Vector2FExt { + fn infinity() -> Self; + fn get(self, axis: Axis2d) -> f32; + fn set(&mut self, axis: Axis2d, value: f32) -> Self; +} + +impl Vector2FExt for Vector2F { + fn infinity() -> Self { + vec2f(f32::INFINITY, f32::INFINITY) + } + + fn get(self, axis: Axis2d) -> f32 { + match axis { + Axis2d::X => self.x(), + Axis2d::Y => self.y(), + } + } + + // TODO: It's a bit weird to mutate and return. + fn set(&mut self, axis: Axis2d, value: f32) -> Self { + match axis { + Axis2d::X => self.set_x(value), + Axis2d::Y => self.set_y(value), + } + *self + } +} + +trait ElementExt { + fn margin_left(self, margin_left: impl Into) -> Node + where + Self: Element + Sized, + { + node(self).margin_left(margin_left) + } +} + +impl ElementExt for E +where + V: View, + E: Element, +{ + fn margin_left(self, margin_left: impl Into) -> Node + where + Self: Sized, + { + node(self).margin_left(margin_left) + } +} diff --git a/crates/gpui/playground/ui/src/playground_ui.rs b/crates/gpui/playground/ui/src/playground_ui.rs index 6bce415335..8b10fd358f 100644 --- a/crates/gpui/playground/ui/src/playground_ui.rs +++ b/crates/gpui/playground/ui/src/playground_ui.rs @@ -1,10 +1,12 @@ -use gpui::{ - elements::node::{column, length::auto, row, text}, - AnyElement, Element, LayoutContext, View, ViewContext, +use gpui::{color::Color, AnyElement, Element, LayoutContext, View, ViewContext}; +use node::{ + length::{auto, rems}, + *, }; use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc}; use tokens::{margin::m4, text::lg}; +mod node; mod tokens; #[derive(Element, Clone, Default)] @@ -13,13 +15,32 @@ pub struct Playground(PhantomData); impl Playground { pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext) -> AnyElement { column() + .id("red column") .width(auto()) + .height(auto()) + .fill(Color::red()) .child( - dialog("This is a dialog", "You would see a description here.") - .button("Button 1", 1, Self::action_1) - .button("Button 2", 2, Self::action_2), + row() + .id("green row") + .width(auto()) + .height(rems(20.)) + .margin_left(auto()) + .fill(Color::green()), // .child( + // row() + // .id("blue child") + // .height(auto()) + // .width(rems(20.)) + // .fill(Color::blue()) + // .margin_left(auto()), + // ), ) .into_any() + + // .child( + // dialog("This is a dialog", "You would see a description here.") + // .button("Button 1", 1, Self::action_1) + // .button("Button 2", 2, Self::action_2), + // ) } fn action_1(_: &mut V, data: &usize, _: &mut ViewContext) { @@ -118,7 +139,8 @@ where F: ClickHandler, { fn render(&mut self, _: &mut V, _: &mut LayoutContext) -> AnyElement { - todo!() + // TODO! Handle click etc + row().child(text(self.label.clone())).into_any() } } diff --git a/crates/gpui/playground/ui/src/tokens.rs b/crates/gpui/playground/ui/src/tokens.rs index 83d9209489..d429c6bb5a 100644 --- a/crates/gpui/playground/ui/src/tokens.rs +++ b/crates/gpui/playground/ui/src/tokens.rs @@ -1,13 +1,7 @@ -pub mod color { - use gpui::color::Color; - - pub fn background(elevation: f32) -> Color { - todo!() - } -} +pub mod color {} pub mod text { - use gpui::elements::node::length::{rems, Rems}; + use crate::node::length::{rems, Rems}; pub fn xs() -> Rems { rems(0.75) @@ -37,21 +31,21 @@ pub mod text { rems(1.875) } - pub fn x4l() -> Rems { + pub fn xxxxl() -> Rems { rems(2.25) } - pub fn x5l() -> Rems { + pub fn xxxxxl() -> Rems { rems(3.0) } - pub fn x6l() -> Rems { + pub fn xxxxxxl() -> Rems { rems(4.0) } } pub mod padding { - use gpui::elements::node::length::{rems, Rems}; + use crate::node::length::{rems, Rems}; pub fn p1() -> Rems { rems(0.25) @@ -107,7 +101,7 @@ pub mod padding { } pub mod margin { - use gpui::elements::node::length::{rems, Rems}; + use crate::node::length::{rems, Rems}; pub fn m1() -> Rems { rems(0.25) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 14419e504f..64b6139c2b 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3440,7 +3440,7 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> { self.text_style_stack .last() .cloned() - .unwrap_or(Default::default()) + .unwrap_or(Arc::new(TextStyle::default(&self.font_cache))) } pub fn with_text_style(&mut self, style: S, f: F) -> T @@ -3506,7 +3506,7 @@ impl<'a, 'b, 'c, V: View> PaintContext<'a, 'b, 'c, V> { self.text_style_stack .last() .cloned() - .unwrap_or(Default::default()) + .unwrap_or(Arc::new(TextStyle::default(&self.font_cache))) } pub fn with_text_style(&mut self, style: S, f: F) -> T diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 5dd3e97e19..4cc39f9bd3 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1,5 +1,5 @@ use crate::{ - elements::{node::Axis2d, AnyRootElement}, + elements::AnyRootElement, geometry::rect::RectF, json::ToJson, keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult}, @@ -1248,38 +1248,16 @@ impl Column for Axis { } pub trait Vector2FExt { - fn infinity() -> Self; fn along(self, axis: Axis) -> f32; - fn get(self, axis: Axis2d) -> f32; - fn set(&mut self, axis: Axis2d, value: f32) -> Self; } impl Vector2FExt for Vector2F { - fn infinity() -> Self { - Self::new(f32::INFINITY, f32::INFINITY) - } - fn along(self, axis: Axis) -> f32 { match axis { Axis::Horizontal => self.x(), Axis::Vertical => self.y(), } } - - fn get(self, axis: Axis2d) -> f32 { - match axis { - Axis2d::X => self.x(), - Axis2d::Y => self.y(), - } - } - - fn set(&mut self, axis: Axis2d, value: f32) -> Self { - match axis { - Axis2d::X => self.set_x(value), - Axis2d::Y => self.set_y(value), - } - *self - } } pub trait RectFExt { diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs index bc7cae6643..2e77460200 100644 --- a/crates/gpui/src/color.rs +++ b/crates/gpui/src/color.rs @@ -18,7 +18,7 @@ use serde_json::json; pub struct Color(#[schemars(with = "String")] ColorU); pub fn color(rgba: u32) -> Color { - color(rgba) + Color::from_u32(rgba) } pub fn rgb(r: f32, g: f32, b: f32) -> Color { diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 34dffd9803..5bed935319 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -12,7 +12,6 @@ mod keystroke_label; mod label; mod list; mod mouse_event_handler; -pub mod node; mod overlay; mod resizable; mod stack; @@ -28,11 +27,7 @@ pub use self::{ }; pub use crate::window::ChildView; -use self::{ - clipped::Clipped, - expanded::Expanded, - node::{length::Length, node, Node}, -}; +use self::{clipped::Clipped, expanded::Expanded}; use crate::{ geometry::{ rect::RectF, @@ -204,13 +199,6 @@ pub trait Element: 'static { { MouseEventHandler::for_child(self.into_any(), region_id) } - - fn margin_left(self, margin_left: impl Into) -> Node - where - Self: Sized, - { - node(self).margin_left(margin_left) - } } trait AnyElementState { diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 9e6f8b259a..62722ccb18 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -400,58 +400,6 @@ pub fn layout_highlighted_chunks<'a>( layouts } -// Need to figure out how fonts flow through the tree to implement this. -impl Element for Cow<'static, str> { - type LayoutState = (); - - type PaintState = (); - - fn layout( - &mut self, - constraint: SizeConstraint, - view: &mut V, - cx: &mut LayoutContext, - ) -> (Vector2F, Self::LayoutState) { - todo!() - } - - fn paint( - &mut self, - scene: &mut SceneBuilder, - bounds: RectF, - visible_bounds: RectF, - layout: &mut Self::LayoutState, - view: &mut V, - cx: &mut PaintContext, - ) -> Self::PaintState { - todo!() - } - - fn rect_for_text_range( - &self, - range_utf16: Range, - bounds: RectF, - visible_bounds: RectF, - layout: &Self::LayoutState, - paint: &Self::PaintState, - view: &V, - cx: &ViewContext, - ) -> Option { - todo!() - } - - fn debug( - &self, - bounds: RectF, - layout: &Self::LayoutState, - paint: &Self::PaintState, - view: &V, - cx: &ViewContext, - ) -> crate::serde_json::Value { - todo!() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index d9a42a84c6..11a1e70962 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -223,6 +223,27 @@ impl TextStyle { }) } + pub fn default(font_cache: &FontCache) -> Self { + let font_family_id = font_cache.known_existing_family(); + let font_id = font_cache + .select_font(font_family_id, &Default::default()) + .expect("did not have any font in system-provided family"); + let font_family_name = font_cache + .family_name(font_family_id) + .expect("we loaded this family from the font cache, so this should work"); + + Self { + color: Color::default(), + font_family_name, + font_family_id, + font_id, + font_size: 14., + font_properties: Default::default(), + underline: Default::default(), + soft_wrap: true, + } + } + pub fn with_font_size(mut self, font_size: f32) -> Self { self.font_size = font_size; self @@ -350,25 +371,7 @@ impl Default for TextStyle { let font_cache = font_cache .as_ref() .expect("TextStyle::default can only be called within a call to with_font_cache"); - - let font_family_id = font_cache.known_existing_family(); - let font_id = font_cache - .select_font(font_family_id, &Default::default()) - .expect("did not have any font in system-provided family"); - let font_family_name = font_cache - .family_name(font_family_id) - .expect("we loaded this family from the font cache, so this should work"); - - Self { - color: Color::default(), - font_family_name, - font_family_id, - font_id, - font_size: 14., - font_properties: Default::default(), - underline: Default::default(), - soft_wrap: true, - } + Self::default(font_cache) }) } }