Themes

Having a standardized Theme system is necessary for an easy-to-use UI library. However, we don't use a single struct for styles, as this is wasteful and would not cover every use case. Instead, each widget should create a struct with style information, that derives the traits: Default + Send + Sync.

Usage

Lets go over how the Button widget handles its styling, as an example:

#[derive(Debug, Clone)]
pub struct ButtonStyle {
    pub normal: Color,
    pub disabled: Color,
    pub hover: Color,
    pub pressed: Color,
}

impl Default for ButtonStyle {
    fn default() -> Self {
        Self {
            normal: Color::White,
            disabled: Color::LightGray,
            hover: Color::LightGray,
            pressed: Color::DarkGray,
        }
    }
}

This houses all of the fields that the Button widget uses to determine how it will render. When it actually wants to utilize that style, we use the StyleExt extension trait.

use agui::widgets::state::theme::StyleExt;

#[functional_widget]
fn button(ctx: &BuildContext, style: Option<ButtonStyle>, child: WidgetRef) -> BuildResult {
    // `resolve` will perform the following steps to get the style:
    //   1. If the style is `Some`, return it
    //   2. Check for a widget that's providing a Theme, and get_or_default from that
    //   3. Check global state for a Theme, and get_or_default from that
    //   4. Use the Default style
    let style: ButtonStyle = style.resolve(ctx);

    BuildResult::None
}

Notice that the style field is an Option. The StyleExt trait also supports this type, making it simple to allow style overrides without additional checks.