cushy/src/styles/components.rs
Jonathan Johnson 353db9dc39
Added Opacity component
Closes #87
2023-12-13 14:02:39 -08:00

242 lines
13 KiB
Rust

//! All style components supported by the built-in widgets.
use kludgine::cosmic_text::{FamilyOwned, Style, Weight};
use kludgine::figures::units::Lp;
use kludgine::shapes::CornerRadii;
use kludgine::Color;
use crate::animation::easings::{EaseInOutQuadradic, EaseInQuadradic, EaseOutQuadradic};
use crate::animation::{EasingFunction, ZeroToOne};
use crate::styles::{Dimension, FocusableWidgets, FontFamilyList, VisualOrder};
/// Defines a set of style components for Gooey.
///
/// These macros implement [`NamedComponent`](crate::styles::NamedComponent) and
/// [`ComponentDefinition`](crate::styles::ComponentDefinition) for each entry
/// defined. The syntax is:
///
/// ```rust
/// use gooey::define_components;
/// use gooey::styles::Dimension;
/// use gooey::styles::components::{SurfaceColor, TextColor};
/// use gooey::kludgine::Color;
/// use gooey::kludgine::figures::Zero;
///
/// define_components! {
/// GroupName {
/// /// This is the documentation for example component. It has a default value of `Dimension::ZERO`.
/// ExampleComponent(Dimension, "example_component", Dimension::ZERO)
/// /// This component whose default value is a color from the current theme.
/// ThemedComponent(Color, "themed_component", .primary.color)
/// /// This component is a color whose default value is the currently defined `TextColor`.
/// DependentComponent(Color, "dependent_component", @TextColor)
/// /// This component defaults to picking a contrasting color between `TextColor` and `SurfaceColor`
/// ContrastingColor(Color, "contrasting_color", contrasting!(ThemedComponent, TextColor, SurfaceColor))
/// /// This component shows how to use a closure for nearly infinite flexibility in computing the default value.
/// ClosureDefaultComponent(Color, "closure_component", |context| context.get(&TextColor))
/// }
/// }
/// ```
#[macro_export]
macro_rules! define_components {
($($widget:ident { $($(#$doc:tt)* $component:ident($type:ty, $name:expr, $($default:tt)*))* })*) => {$($(
$(#$doc)*
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct $component;
const _: () = {
use $crate::styles::{ComponentDefinition, ComponentName, NamedComponent};
use $crate::context::WidgetContext;
use $crate::Lazy;
use ::std::borrow::Cow;
impl NamedComponent for $component {
fn name(&self) -> Cow<'_, ComponentName> {
static NAME: Lazy<ComponentName> = Lazy::new(|| ComponentName::new(stringify!($widget), $name));
Cow::Borrowed(&*NAME)
}
}
impl ComponentDefinition for $component {
type ComponentType = $type;
define_components!($type, $($default)*);
}
};
)*)*};
($type:ty, . $($path:tt)*) => {
define_components!($type, |context| context.theme().$($path)*);
};
($type:ty, |$context:ident| $($expr:tt)*) => {
fn default_value(&self, $context: &WidgetContext<'_, '_>) -> $type {
$($expr)*
}
};
($type:ty, @$path:path) => {
define_components!($type, |context| context.get(&$path));
};
($type:ty, contrasting!($bg:ident, $($fg:ident),+ $(,)?)) => {
define_components!($type, |context| {
use $crate::styles::ColorExt;
context.get(&$bg).most_contrasting(&[
$(context.get(&$fg)),+
])
});
};
($type:ty, $($expr:tt)*) => {
define_components!($type, |_context| $($expr)*);
};
}
define_components! {
Global {
/// The [`Dimension`] to use as the size to render text.
TextSize(Dimension, "text_size", @BaseTextSize)
/// The [`Dimension`] to use to space multiple lines of text.
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.
TextColor(Color, "text_color", .surface.on_color)
/// The [`Color`] to use when rendering text in a more subdued tone.
TextColorVariant(Color, "text_color_variant", .surface.on_color_variant)
/// A [`Color`] to be used as a highlight color.
HighlightColor(Color,"highlight_color",.primary.color.with_alpha(128))
/// Intrinsic, uniform padding for a widget.
///
/// This component is opt-in and does not automatically work for all widgets.
IntrinsicPadding(Dimension, "padding", Dimension::Lp(Lp::points(6)))
/// The [`EasingFunction`] to apply to animations that have no inherent
/// directionality.
Easing(EasingFunction, "Easing", EasingFunction::from(EaseInOutQuadradic))
/// The [`EasingFunction`] to apply to animations that transition a value from
/// "nothing" to "something". For example, if an widget is animating a color's
/// alpha channel towards opaqueness, it would query for this style component.
/// Otherwise, it would use [`EasingOut`].
EasingIn(EasingFunction, "easing_out", EasingFunction::from(EaseInQuadradic))
/// The [`EasingFunction`] to apply to animations that transition a value from
/// "something" to "nothing". For example, if an widget is animating a color's
/// alpha channel towards transparency, it would query for this style component.
/// Otherwise, it would use [`EasingIn`].
EasingOut(EasingFunction, "easing_out", EasingFunction::from(EaseOutQuadradic))
/// The [`VisualOrder`] strategy to use when laying out content.
LayoutOrder(VisualOrder, "visual_order", VisualOrder::left_to_right())
/// The set of controls to allow focusing via tab key and initial focus
/// selection.
AutoFocusableControls(FocusableWidgets, "focus", FocusableWidgets::default())
/// A [`Color`] to be used as the background color of a widget.
WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE)
/// A [`Color`] to be used to accent a widget.
WidgetAccentColor(Color, "widget_accent_color", .primary.color)
/// A [`Color`] to be used to accent a disabled widget.
DisabledWidgetAccentColor(Color, "disabled_widget_accent_color", .primary.color_dim)
/// A [`Color`] to be used as an outline color.
OutlineColor(Color, "outline_color", .surface.outline)
/// A [`Color`] to be used as an outline color.
DisabledOutlineColor(Color, "disabled_outline_color", .surface.outline_variant)
/// A [`Color`] to be used as a background color for widgets that render an
/// opaque background.
OpaqueWidgetColor(Color, "opaque_color", .surface.opaque_widget)
/// A set of radius descriptions for how much roundness to apply to the
/// shapes of widgets.
CornerRadius(CornerRadii<Dimension>, "corner_radius", CornerRadii::from(Dimension::Lp(Lp::points(10))))
/// The font family to render text using.
FontFamily(FontFamilyList, "font_family", FontFamilyList::from(FamilyOwned::SansSerif))
/// The font (boldness) weight to apply to text rendering.
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)
/// The opaqueness of drawing calls
Opacity(ZeroToOne, "opacity", ZeroToOne::ONE)
}
}