diff --git a/examples/tic-tac-toe.rs b/examples/tic-tac-toe.rs index 7a8e2c1..d560279 100644 --- a/examples/tic-tac-toe.rs +++ b/examples/tic-tac-toe.rs @@ -131,7 +131,6 @@ impl GameState { } fn game_end(winner: Option, app: &Dynamic) -> impl MakeWidget { - // TODO we need typography styles let app = app.clone(); let label = if let Some(winner) = winner { format!("{winner:?} wins!") @@ -140,6 +139,7 @@ fn game_end(winner: Option, app: &Dynamic) -> impl MakeWidget }; label + .h1() .and( "Play Again" .into_button() diff --git a/examples/typography.rs b/examples/typography.rs new file mode 100644 index 0000000..8916701 --- /dev/null +++ b/examples/typography.rs @@ -0,0 +1,18 @@ +use gooey::widget::MakeWidget; +use gooey::Run; + +fn main() -> gooey::Result { + "Heading 1" + .h1() + .and("Heading 2".h2()) + .and("Heading 3".h3()) + .and("Heading 4".h4()) + .and("Heading 5".h5()) + .and("Heading 6".h6()) + .and("Regular Text") + .and("Small Text".small()) + .and("X-Small Text".x_small()) + .into_rows() + .centered() + .run() +} diff --git a/src/styles.rs b/src/styles.rs index afdc277..2c4cd6b 100644 --- a/src/styles.rs +++ b/src/styles.rs @@ -30,7 +30,7 @@ pub mod components; /// A collection of style components organized by their name. #[derive(Clone, Debug, Default)] -pub struct Styles(Arc>>); +pub struct Styles(Arc); impl Styles { /// Returns an empty collection. @@ -43,12 +43,16 @@ impl Styles { /// without reallocating. #[must_use] pub fn with_capacity(capacity: usize) -> Self { - Self(Arc::new(AHashMap::with_capacity(capacity))) + Self(Arc::new(StyleData { + components: AHashMap::with_capacity(capacity), + })) } /// Inserts a [`Component`] with a given name. pub fn insert_named(&mut self, name: ComponentName, component: impl IntoComponentValue) { - Arc::make_mut(&mut self.0).insert(name, component.into_component_value()); + Arc::make_mut(&mut self.0) + .components + .insert(name, component.into_component_value()); } /// Inserts a [`Component`] using then name provided. @@ -57,6 +61,16 @@ impl Styles { self.insert_named(name, component); } + /// Inserts a [`Component`] using then name provided, resolving the value + /// through `dynamic`. + pub fn insert_dynamic( + &mut self, + name: &impl NamedComponent, + dynamic: impl Into, + ) { + self.insert(name, Component::Dynamic(dynamic.into())); + } + /// Adds a [`Component`] for the name provided and returns self. #[must_use] pub fn with( @@ -71,14 +85,64 @@ impl Styles { self } + /// Adds a [`Component`] using then name provided, resolving the value + /// through `dynamic`. This function returns self. + #[must_use] + pub fn with_dynamic( + mut self, + name: &C, + dynamic: impl Into, + ) -> Self { + self.insert_dynamic(name, dynamic); + self + } + /// Returns the associated component for the given name, if found. #[must_use] - pub fn get_named(&self, component: &Named) -> Option<&Value> + pub fn get_with_fallback( + &self, + component: &impl NamedComponent, + fallback: &Fallback, + context: &WidgetContext<'_, '_>, + ) -> Fallback::ComponentType where - Named: NamedComponent + ?Sized, + Fallback: ComponentDefinition + ?Sized, { - let name = component.name(); - self.0.get(&name) + self.0 + .components + .get(&component.name()) + .or_else(|| self.0.components.get(&fallback.name())) + .and_then(|component| Self::resolve_component(component, context)) + .unwrap_or_else(|| fallback.default_value(context)) + } + + fn resolve_component( + component: &Value, + context: &WidgetContext<'_, '_>, + ) -> Option + where + T: ComponentType, + { + let mut resolved = component.get(); + loop { + match T::try_from_component(resolved) { + Ok(value) => { + if value.requires_invalidation() { + component.invalidate_when_changed(context); + } else { + component.redraw_when_changed(context); + } + break Some(value); + } + Err(Component::Dynamic(dynamic)) => { + let Some(new_component) = dynamic.resolve(context) else { + break None; + }; + resolved = new_component; + } + Err(_) => break None, + } + } } /// Returns the component associated with the given name, or if not found, @@ -92,22 +156,10 @@ impl Styles { where Named: ComponentDefinition + ?Sized, { - let name = component.name(); self.0 - .get(&name) - .and_then(|component| { - match ::try_from_component(component.get()) { - Ok(value) => { - if value.requires_invalidation() { - component.invalidate_when_changed(context); - } else { - component.redraw_when_changed(context); - } - Some(value) - } - Err(_) => None, - } - }) + .components + .get(&component.name()) + .and_then(|component| Self::resolve_component(component, context)) .unwrap_or_else(|| component.default_value(context)) } @@ -120,6 +172,11 @@ impl Styles { } } +#[derive(Debug, Default, Clone)] +struct StyleData { + components: AHashMap>, +} + /// A value that can be converted into a `Value`. pub trait IntoComponentValue { /// Returns `self` stored in a component value. @@ -173,6 +230,7 @@ impl IntoIterator for Styles { fn into_iter(self) -> Self::IntoIter { Arc::try_unwrap(self.0) .unwrap_or_else(|err| err.as_ref().clone()) + .components .into_iter() } } @@ -229,6 +287,9 @@ pub enum Component { /// A custom component type. Custom(CustomComponent), + + /// This component should use the associated value in the named class. + Dynamic(DynamicComponent), } impl Component { @@ -241,6 +302,23 @@ impl Component { { Self::Custom(CustomComponent::new(component)) } + + /// Returns a new [`DynamicComponent`] which allows resolving a component at + /// runtime. + #[must_use] + pub fn dynamic(resolve: Func) -> Self + where + Func: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option + + RefUnwindSafe + + Send + + Sync + + 'static, + T: ComponentType, + { + Self::Dynamic(DynamicComponent::new(move |context| { + resolve(context).map(T::into_component) + })) + } } impl From for Component { @@ -854,7 +932,7 @@ impl From<&'static Lazy> for ComponentName { } /// A type that represents a named style component. -pub trait NamedComponent { +pub trait NamedComponent: Sized { /// Returns the name of the style component. fn name(&self) -> Cow<'_, ComponentName>; } @@ -2253,3 +2331,81 @@ impl TryFrom for FontFamilyList { } } } + +/// A [`Component`] that resolves its value at runtime. +#[derive(Clone)] +pub struct DynamicComponent(Arc); + +impl Debug for DynamicComponent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("DynamicComponent").finish() + } +} + +impl PartialEq for DynamicComponent { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} + +/// A type that resolves to a [`Component`] at runtime. +pub trait DynamicComponentResolver: RefUnwindSafe + Send + Sync + 'static { + /// Returns the effective component, if one should be applied. + fn resolve_component(&self, context: &WidgetContext<'_, '_>) -> Option; +} + +struct DynamicFunctionWrapper(F); + +impl DynamicComponentResolver for DynamicFunctionWrapper +where + T: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option + + RefUnwindSafe + + Send + + Sync + + 'static, +{ + fn resolve_component(&self, context: &WidgetContext<'_, '_>) -> Option { + self.0(context) + } +} + +impl DynamicComponentResolver for T +where + T: ComponentDefinition + Clone + RefUnwindSafe + Send + Sync + 'static, +{ + fn resolve_component(&self, context: &WidgetContext<'_, '_>) -> Option { + Some(context.get(self).into_component()) + } +} + +impl From for DynamicComponent +where + T: DynamicComponentResolver, +{ + fn from(resolve: T) -> Self { + Self(Arc::new(resolve)) + } +} + +impl DynamicComponent { + /// Returns a new dynamic component that invokes `resolve` each time it is + /// used by widgets. + #[must_use] + pub fn new(resolve: Func) -> Self + where + Func: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option + + RefUnwindSafe + + Send + + Sync + + 'static, + { + Self::from(DynamicFunctionWrapper(resolve)) + } + + /// Invokes the resolver function, optionally returning a resolved + /// component. + #[must_use] + pub fn resolve(&self, context: &WidgetContext<'_, '_>) -> Option { + self.0.resolve_component(context) + } +} diff --git a/src/styles/components.rs b/src/styles/components.rs index d2ec563..aa028bf 100644 --- a/src/styles/components.rs +++ b/src/styles/components.rs @@ -92,9 +92,52 @@ macro_rules! define_components { define_components! { Global { /// The [`Dimension`] to use as the size to render text. - TextSize(Dimension, "text_size", Dimension::Lp(Lp::points(12))) + TextSize(Dimension, "text_size", @BaseTextSize) /// The [`Dimension`] to use to space multiple lines of text. - LineHeight(Dimension,"line_height",Dimension::Lp(Lp::points(16))) + LineHeight(Dimension,"line_height", @BaseLineHeight) + + /// The base [`Dimension`] to use as the normal text size. Unless + /// overridden, all other sizes for built-in widgets will be based on + /// this dimension. + BaseTextSize(Dimension, "base_text_size", Dimension::Lp(Lp::points(12))) + /// The base [`Dimension`] to use to space multiple lines of text. + /// Unless overridden, all other sizes for built-in widgets will be + /// based on this dimension. + BaseLineHeight(Dimension,"base_line_height", Dimension::Lp(Lp::points(16))) + /// The largest text size on a series of 8 steps. + TextSize8(Dimension, "text_size_8", |context| context.get(&BaseTextSize) * 2.5) + /// The second-largest text size on a series of 8 steps. + TextSize7(Dimension, "text_size_7", |context| context.get(&BaseTextSize) * 2.25) + /// The third-largest text size on a series of 8 steps. + TextSize6(Dimension, "text_size_6", |context| context.get(&BaseTextSize) * 2.0) + /// The fourth-largest text size on a series of 8 steps. + TextSize5(Dimension, "text_size_5", |context| context.get(&BaseTextSize) * 1.5) + /// The fifth-largest text size on a series of 8 steps. + TextSize4(Dimension, "text_size_4", |context| context.get(&BaseTextSize) * 1.25) + /// The base text size on a series of 8 steps. + TextSize3(Dimension, "text_size_3", @BaseTextSize) + /// The second-smallest text size on a series of 8 steps. + TextSize2(Dimension, "text_size_2", |context| context.get(&BaseTextSize) * 0.75) + /// The smallest text size on a series of 8 steps. + TextSize1(Dimension, "text_size_1", |context| context.get(&BaseTextSize) * 0.5) + + /// The largest line height on a series of 8 steps. + LineHeight8(Dimension, "line_height_8", |context| context.get(&BaseLineHeight) * 2.5) + /// The second-largest line height on a series of 8 steps. + LineHeight7(Dimension, "line_height_7", |context| context.get(&BaseLineHeight) * 2.25) + /// The third-largest line height on a series of 8 steps. + LineHeight6(Dimension, "line_height_6", |context| context.get(&BaseLineHeight) * 2.0) + /// The fourth-largest line height on a series of 8 steps. + LineHeight5(Dimension, "line_height_5", |context| context.get(&BaseLineHeight) * 1.5) + /// The fifth-largest line height on a series of 8 steps. + LineHeight4(Dimension, "line_height_4", |context| context.get(&BaseLineHeight) * 1.25) + /// The base line height on a series of 8 steps. + LineHeight3(Dimension, "line_height_4", @BaseLineHeight) + /// The second-smallest line height on a series of 8 steps. + LineHeight2(Dimension, "line_height_2", |context| context.get(&BaseLineHeight) * 0.75) + /// The smallest line height on a series of 8 steps. + LineHeight1(Dimension, "line_height_1", |context| context.get(&BaseLineHeight) * 0.675) + /// The [`Color`] of the surface for the user interface to draw upon. SurfaceColor(Color, "surface_color", .surface.color) /// The [`Color`] to use when rendering text. @@ -147,5 +190,50 @@ define_components! { FontWeight(Weight, "font_weight", Weight::NORMAL) /// The font style to apply to text rendering. FontStyle(Style, "font_style", Style::Normal) + + /// The default [`Weight`] to apply to headings. + HeadingWeight(Weight, "heading_weight", Weight::BOLD) + /// The [`Weight`] to apply to h1 headings. + Heading1Weight(Weight, "heading_weight_1", @HeadingWeight) + /// The [`Weight`] to apply to h2 headings. + Heading2Weight(Weight, "heading_weight_2", @HeadingWeight) + /// The [`Weight`] to apply to h3 headings. + Heading3Weight(Weight, "heading_weight_3", @HeadingWeight) + /// The [`Weight`] to apply to h4 headings. + Heading4Weight(Weight, "heading_weight_4", @HeadingWeight) + /// The [`Weight`] to apply to h5 headings. + Heading5Weight(Weight, "heading_weight_5", @HeadingWeight) + /// The [`Weight`] to apply to h6 headings. + Heading6Weight(Weight, "heading_weight_6", @HeadingWeight) + + /// The default [`Style`] to apply to headings. + HeadingStyle(Style, "heading_style", Style::Normal) + /// The [`Style`] to apply to h1 headings. + Heading1Style(Style, "heading_style_1", @HeadingStyle) + /// The [`Style`] to apply to h2 headings. + Heading2Style(Style, "heading_style_2", @HeadingStyle) + /// The [`Style`] to apply to h3 headings. + Heading3Style(Style, "heading_style_3", @HeadingStyle) + /// The [`Style`] to apply to h4 headings. + Heading4Style(Style, "heading_style_4", @HeadingStyle) + /// The [`Style`] to apply to h5 headings. + Heading5Style(Style, "heading_style_5", @HeadingStyle) + /// The [`Style`] to apply to h6 headings. + Heading6Style(Style, "heading_style_6", @HeadingStyle) + + /// The default [`FontFamilyList`] to apply to headings. + HeadingFontFamily(FontFamilyList, "heading_font_family", FontFamilyList::from(FamilyOwned::SansSerif)) + /// The [`FontFamilyList`] to apply to h1 headings. + Heading1FontFamily(FontFamilyList, "heading_font_family_1", @HeadingFontFamily) + /// The [`FontFamilyList`] to apply to h2 headings. + Heading2FontFamily(FontFamilyList, "heading_font_family_2", @HeadingFontFamily) + /// The [`FontFamilyList`] to apply to h3 headings. + Heading3FontFamily(FontFamilyList, "heading_font_family_3", @HeadingFontFamily) + /// The [`FontFamilyList`] to apply to h4 headings. + Heading4FontFamily(FontFamilyList, "heading_font_family_4", @HeadingFontFamily) + /// The [`FontFamilyList`] to apply to h5 headings. + Heading5FontFamily(FontFamilyList, "heading_font_family_5", @HeadingFontFamily) + /// The [`FontFamilyList`] to apply to h6 headings. + Heading6FontFamily(FontFamilyList, "heading_font_family_6", @HeadingFontFamily) } } diff --git a/src/widget.rs b/src/widget.rs index 81292f1..da6019f 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -19,9 +19,18 @@ use kludgine::Color; use crate::context::sealed::WindowHandle; use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext}; +use crate::styles::components::{ + FontFamily, FontStyle, FontWeight, Heading1FontFamily, Heading1Style, Heading1Weight, + Heading2FontFamily, Heading2Style, Heading2Weight, Heading3FontFamily, Heading3Style, + Heading3Weight, Heading4FontFamily, Heading4Style, Heading4Weight, Heading5FontFamily, + Heading5Style, Heading5Weight, Heading6FontFamily, Heading6Style, Heading6Weight, LineHeight, + LineHeight1, LineHeight2, LineHeight3, LineHeight4, LineHeight5, LineHeight6, LineHeight7, + LineHeight8, TextSize, TextSize1, TextSize2, TextSize3, TextSize4, TextSize5, TextSize6, + TextSize7, TextSize8, +}; use crate::styles::{ - ComponentDefinition, ContainerLevel, Dimension, DimensionRange, Edges, IntoComponentValue, - Styles, ThemePair, VisualOrder, + ComponentDefinition, ContainerLevel, Dimension, DimensionRange, DynamicComponent, Edges, + IntoComponentValue, Styles, ThemePair, VisualOrder, }; use crate::tree::Tree; use crate::utils::IgnorePoison; @@ -675,6 +684,123 @@ pub trait MakeWidget: Sized { Style::new(Styles::new().with(name, component), self) } + /// Associates a style component with `self`, resolving its value using + /// `dynamic` at runtime. + fn with_dynamic( + self, + name: &C, + dynamic: impl Into, + ) -> Style + where + Value: IntoComponentValue, + { + Style::new(Styles::new().with_dynamic(name, dynamic), self) + } + + /// Styles `self` with the largest of 6 heading styles. + fn h1(self) -> Style { + self.xxxx_large() + .with_dynamic(&FontStyle, Heading1Style) + .with_dynamic(&FontFamily, Heading1FontFamily) + .with_dynamic(&FontWeight, Heading1Weight) + } + + /// Styles `self` with the second largest of 6 heading styles. + fn h2(self) -> Style { + self.xxx_large() + .with_dynamic(&FontStyle, Heading2Style) + .with_dynamic(&FontFamily, Heading2FontFamily) + .with_dynamic(&FontWeight, Heading2Weight) + } + + /// Styles `self` with the third largest of 6 heading styles. + fn h3(self) -> Style { + self.xx_large() + .with_dynamic(&FontStyle, Heading3Style) + .with_dynamic(&FontFamily, Heading3FontFamily) + .with_dynamic(&FontWeight, Heading3Weight) + } + + /// Styles `self` with the third smallest of 6 heading styles. + fn h4(self) -> Style { + self.x_large() + .with_dynamic(&FontStyle, Heading4Style) + .with_dynamic(&FontFamily, Heading4FontFamily) + .with_dynamic(&FontWeight, Heading4Weight) + } + + /// Styles `self` with the second smallest of 6 heading styles. + fn h5(self) -> Style { + self.large() + .with_dynamic(&FontStyle, Heading5Style) + .with_dynamic(&FontFamily, Heading5FontFamily) + .with_dynamic(&FontWeight, Heading5Weight) + } + + /// Styles `self` with the smallest of 6 heading styles. + fn h6(self) -> Style { + self.default_size() + .with_dynamic(&FontStyle, Heading6Style) + .with_dynamic(&FontFamily, Heading6FontFamily) + .with_dynamic(&FontWeight, Heading6Weight) + } + + /// Styles `self` with the largest text size. + #[must_use] + fn xxxx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize8) + .with_dynamic(&LineHeight, LineHeight8) + } + + /// Styles `self` with the second largest text size. + #[must_use] + fn xxx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize7) + .with_dynamic(&LineHeight, LineHeight7) + } + + /// Styles `self` with the third largest text size. + #[must_use] + fn xx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize6) + .with_dynamic(&LineHeight, LineHeight6) + } + + /// Styles `self` with the fourth largest text size. + #[must_use] + fn x_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize5) + .with_dynamic(&LineHeight, LineHeight5) + } + + /// Styles `self` with the fifth largest text size. + #[must_use] + fn large(self) -> Style { + self.with_dynamic(&TextSize, TextSize4) + .with_dynamic(&LineHeight, LineHeight4) + } + + /// Styles `self` with the third smallest text size. + #[must_use] + fn default_size(self) -> Style { + self.with_dynamic(&TextSize, TextSize3) + .with_dynamic(&LineHeight, LineHeight3) + } + + /// Styles `self` with the second smallest text size. + #[must_use] + fn small(self) -> Style { + self.with_dynamic(&TextSize, TextSize2) + .with_dynamic(&LineHeight, LineHeight2) + } + + /// Styles `self` with the smallest text size. + #[must_use] + fn x_small(self) -> Style { + self.with_dynamic(&TextSize, TextSize1) + .with_dynamic(&LineHeight, LineHeight1) + } + /// Sets the widget that should be focused next. /// /// Gooey automatically determines reverse tab order by using this same diff --git a/src/widgets/label.rs b/src/widgets/label.rs index 8c37b9b..7d3ddc4 100644 --- a/src/widgets/label.rs +++ b/src/widgets/label.rs @@ -98,4 +98,10 @@ macro_rules! impl_make_widget { }; } -impl_make_widget!(&'_ str, String, Value, Dynamic); +impl_make_widget!( + &'_ str, + String, + Value, + Dynamic, + Dynamic<&'static str> +); diff --git a/src/widgets/style.rs b/src/widgets/style.rs index d1c714a..b4c3047 100644 --- a/src/widgets/style.rs +++ b/src/widgets/style.rs @@ -1,5 +1,14 @@ use crate::context::EventContext; -use crate::styles::Styles; +use crate::styles::components::{ + FontFamily, FontStyle, FontWeight, Heading1FontFamily, Heading1Style, Heading1Weight, + Heading2FontFamily, Heading2Style, Heading2Weight, Heading3FontFamily, Heading3Style, + Heading3Weight, Heading4FontFamily, Heading4Style, Heading4Weight, Heading5FontFamily, + Heading5Style, Heading5Weight, Heading6FontFamily, Heading6Style, Heading6Weight, LineHeight, + LineHeight1, LineHeight2, LineHeight3, LineHeight4, LineHeight5, LineHeight6, LineHeight7, + LineHeight8, TextSize, TextSize1, TextSize2, TextSize3, TextSize4, TextSize5, TextSize6, + TextSize7, TextSize8, +}; +use crate::styles::{ComponentDefinition, DynamicComponent, IntoComponentValue, Styles}; use crate::value::{IntoValue, Value}; use crate::widget::{MakeWidget, WidgetRef, WrapperWidget}; @@ -19,6 +28,156 @@ impl Style { child: WidgetRef::new(child), } } + + fn map_styles_mut(&mut self, map: impl FnOnce(&mut Styles) -> R) -> R { + match &mut self.styles { + Value::Constant(styles) => map(styles), + Value::Dynamic(dynamic) => dynamic.map_mut(map), + } + } + + /// Associates a style component with `self`. + #[must_use] + pub fn with( + mut self, + name: &C, + component: impl IntoValue, + ) -> Style + where + Value: IntoComponentValue, + { + self.map_styles_mut(|styles| { + styles.insert(name, component.into_value()); + }); + self + } + + /// Associates a style component with `self`, resolving its value using + /// `dynamic` at runtime. + #[must_use] + pub fn with_dynamic( + mut self, + name: &C, + dynamic: impl Into, + ) -> Style + where + Value: IntoComponentValue, + { + self.map_styles_mut(|styles| { + styles.insert_dynamic(name, dynamic); + }); + self + } + + /// Styles `self` with the largest of 6 heading styles. + #[must_use] + pub fn h1(self) -> Style { + self.xxxx_large() + .with_dynamic(&FontStyle, Heading1Style) + .with_dynamic(&FontFamily, Heading1FontFamily) + .with_dynamic(&FontWeight, Heading1Weight) + } + + /// Styles `self` with the second largest of 6 heading styles. + #[must_use] + pub fn h2(self) -> Style { + self.xxx_large() + .with_dynamic(&FontStyle, Heading2Style) + .with_dynamic(&FontFamily, Heading2FontFamily) + .with_dynamic(&FontWeight, Heading2Weight) + } + + /// Styles `self` with the third largest of 6 heading styles. + #[must_use] + pub fn h3(self) -> Style { + self.xx_large() + .with_dynamic(&FontStyle, Heading3Style) + .with_dynamic(&FontFamily, Heading3FontFamily) + .with_dynamic(&FontWeight, Heading3Weight) + } + + /// Styles `self` with the third smallest of 6 heading styles. + #[must_use] + pub fn h4(self) -> Style { + self.x_large() + .with_dynamic(&FontStyle, Heading4Style) + .with_dynamic(&FontFamily, Heading4FontFamily) + .with_dynamic(&FontWeight, Heading4Weight) + } + + /// Styles `self` with the second smallest of 6 heading styles. + #[must_use] + pub fn h5(self) -> Style { + self.large() + .with_dynamic(&FontStyle, Heading5Style) + .with_dynamic(&FontFamily, Heading5FontFamily) + .with_dynamic(&FontWeight, Heading5Weight) + } + + /// Styles `self` with the smallest of 6 heading styles. + #[must_use] + pub fn h6(self) -> Style { + self.default_size() + .with_dynamic(&FontStyle, Heading6Style) + .with_dynamic(&FontFamily, Heading6FontFamily) + .with_dynamic(&FontWeight, Heading6Weight) + } + + /// Styles `self` with the largest text size. + #[must_use] + pub fn xxxx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize8) + .with_dynamic(&LineHeight, LineHeight8) + } + + /// Styles `self` with the second largest text size. + #[must_use] + pub fn xxx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize7) + .with_dynamic(&LineHeight, LineHeight7) + } + + /// Styles `self` with the third largest text size. + #[must_use] + pub fn xx_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize6) + .with_dynamic(&LineHeight, LineHeight6) + } + + /// Styles `self` with the fourth largest text size. + #[must_use] + pub fn x_large(self) -> Style { + self.with_dynamic(&TextSize, TextSize5) + .with_dynamic(&LineHeight, LineHeight5) + } + + /// Styles `self` with the fifth largest text size. + #[must_use] + pub fn large(self) -> Style { + self.with_dynamic(&TextSize, TextSize4) + .with_dynamic(&LineHeight, LineHeight4) + } + + /// Styles `self` with the third smallest text size. + #[must_use] + pub fn default_size(self) -> Style { + self.with_dynamic(&TextSize, TextSize3) + .with_dynamic(&LineHeight, LineHeight3) + } + + /// Styles `self` with the second smallest text size. + #[must_use] + pub fn small(self) -> Style { + self.with_dynamic(&TextSize, TextSize2) + .with_dynamic(&LineHeight, LineHeight2) + } + + /// Styles `self` with the smallest text size. + #[must_use] + pub fn x_small(self) -> Style { + self.with_dynamic(&TextSize, TextSize1) + .with_dynamic(&LineHeight, LineHeight1) + } } impl WrapperWidget for Style {