mirror of
https://github.com/danbulant/cushy
synced 2026-06-17 13:31:07 +00:00
Added font size + heading helpers
This commit is contained in:
parent
3f2aace55e
commit
8e19a89bca
7 changed files with 583 additions and 30 deletions
|
|
@ -131,7 +131,6 @@ impl GameState {
|
|||
}
|
||||
|
||||
fn game_end(winner: Option<Player>, app: &Dynamic<AppState>) -> 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<Player>, app: &Dynamic<AppState>) -> impl MakeWidget
|
|||
};
|
||||
|
||||
label
|
||||
.h1()
|
||||
.and(
|
||||
"Play Again"
|
||||
.into_button()
|
||||
|
|
|
|||
18
examples/typography.rs
Normal file
18
examples/typography.rs
Normal file
|
|
@ -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()
|
||||
}
|
||||
202
src/styles.rs
202
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<AHashMap<ComponentName, Value<Component>>>);
|
||||
pub struct Styles(Arc<StyleData>);
|
||||
|
||||
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<DynamicComponent>,
|
||||
) {
|
||||
self.insert(name, Component::Dynamic(dynamic.into()));
|
||||
}
|
||||
|
||||
/// Adds a [`Component`] for the name provided and returns self.
|
||||
#[must_use]
|
||||
pub fn with<C: ComponentDefinition>(
|
||||
|
|
@ -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<C: ComponentDefinition>(
|
||||
mut self,
|
||||
name: &C,
|
||||
dynamic: impl Into<DynamicComponent>,
|
||||
) -> Self {
|
||||
self.insert_dynamic(name, dynamic);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the associated component for the given name, if found.
|
||||
#[must_use]
|
||||
pub fn get_named<Named>(&self, component: &Named) -> Option<&Value<Component>>
|
||||
pub fn get_with_fallback<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<T>(
|
||||
component: &Value<Component>,
|
||||
context: &WidgetContext<'_, '_>,
|
||||
) -> Option<T>
|
||||
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 <Named::ComponentType>::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<ComponentName, Value<Component>>,
|
||||
}
|
||||
|
||||
/// A value that can be converted into a `Value<Component>`.
|
||||
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<T, Func>(resolve: Func) -> Self
|
||||
where
|
||||
Func: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option<T>
|
||||
+ RefUnwindSafe
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
T: ComponentType,
|
||||
{
|
||||
Self::Dynamic(DynamicComponent::new(move |context| {
|
||||
resolve(context).map(T::into_component)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FamilyOwned> for Component {
|
||||
|
|
@ -854,7 +932,7 @@ impl From<&'static Lazy<ComponentName>> 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<Component> for FontFamilyList {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Component`] that resolves its value at runtime.
|
||||
#[derive(Clone)]
|
||||
pub struct DynamicComponent(Arc<dyn DynamicComponentResolver>);
|
||||
|
||||
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<Component>;
|
||||
}
|
||||
|
||||
struct DynamicFunctionWrapper<F>(F);
|
||||
|
||||
impl<T> DynamicComponentResolver for DynamicFunctionWrapper<T>
|
||||
where
|
||||
T: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option<Component>
|
||||
+ RefUnwindSafe
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
{
|
||||
fn resolve_component(&self, context: &WidgetContext<'_, '_>) -> Option<Component> {
|
||||
self.0(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DynamicComponentResolver for T
|
||||
where
|
||||
T: ComponentDefinition + Clone + RefUnwindSafe + Send + Sync + 'static,
|
||||
{
|
||||
fn resolve_component(&self, context: &WidgetContext<'_, '_>) -> Option<Component> {
|
||||
Some(context.get(self).into_component())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> 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<Func>(resolve: Func) -> Self
|
||||
where
|
||||
Func: for<'a, 'context, 'widget> Fn(&'a WidgetContext<'context, 'widget>) -> Option<Component>
|
||||
+ 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<Component> {
|
||||
self.0.resolve_component(context)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
130
src/widget.rs
130
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<C: ComponentDefinition>(
|
||||
self,
|
||||
name: &C,
|
||||
dynamic: impl Into<DynamicComponent>,
|
||||
) -> Style
|
||||
where
|
||||
Value<C::ComponentType>: 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
|
||||
|
|
|
|||
|
|
@ -98,4 +98,10 @@ macro_rules! impl_make_widget {
|
|||
};
|
||||
}
|
||||
|
||||
impl_make_widget!(&'_ str, String, Value<String>, Dynamic<String>);
|
||||
impl_make_widget!(
|
||||
&'_ str,
|
||||
String,
|
||||
Value<String>,
|
||||
Dynamic<String>,
|
||||
Dynamic<&'static str>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<R>(&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<C: ComponentDefinition>(
|
||||
mut self,
|
||||
name: &C,
|
||||
component: impl IntoValue<C::ComponentType>,
|
||||
) -> Style
|
||||
where
|
||||
Value<C::ComponentType>: 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<C: ComponentDefinition>(
|
||||
mut self,
|
||||
name: &C,
|
||||
dynamic: impl Into<DynamicComponent>,
|
||||
) -> Style
|
||||
where
|
||||
Value<C::ComponentType>: 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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue