diff --git a/Cargo.lock b/Cargo.lock index cc2a291c..2a49fc50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6603,6 +6603,7 @@ dependencies = [ "image", "log", "lru", + "num_enum", "ouroboros", "parking_lot", "regex", @@ -6613,6 +6614,7 @@ dependencies = [ "serde_json", "slotmap", "smallvec", + "strum", "taffy", "vulkano", "vulkano-shaders", diff --git a/dash-frontend/assets/gui/dashboard.xml b/dash-frontend/assets/gui/dashboard.xml index c1ac0ddb..c33e95d7 100644 --- a/dash-frontend/assets/gui/dashboard.xml +++ b/dash-frontend/assets/gui/dashboard.xml @@ -1,6 +1,4 @@ - - @@ -39,7 +37,7 @@
- +
- @@ -120,7 +118,7 @@ flex_direction="row" align_items="center" justify_content="space_between" - color="~color_bottom_panel" + color="background_variant" >
diff --git a/dash-frontend/assets/gui/t_dropdown_button.xml b/dash-frontend/assets/gui/t_dropdown_button.xml index c97fa855..7d7f5ed7 100644 --- a/dash-frontend/assets/gui/t_dropdown_button.xml +++ b/dash-frontend/assets/gui/t_dropdown_button.xml @@ -1,6 +1,4 @@ - -
- + diff --git a/dash-frontend/assets/gui/t_group_box.xml b/dash-frontend/assets/gui/t_group_box.xml index 8292d2c6..36524ad1 100644 --- a/dash-frontend/assets/gui/t_group_box.xml +++ b/dash-frontend/assets/gui/t_group_box.xml @@ -1,6 +1,4 @@ - - - \ No newline at end of file +
diff --git a/dash-frontend/assets/gui/t_menu_button.xml b/dash-frontend/assets/gui/t_menu_button.xml index 3029459b..a9c9dd66 100644 --- a/dash-frontend/assets/gui/t_menu_button.xml +++ b/dash-frontend/assets/gui/t_menu_button.xml @@ -1,7 +1,5 @@ - - - + - + diff --git a/wgui/src/color.rs b/wgui/src/color.rs new file mode 100644 index 00000000..09da5b26 --- /dev/null +++ b/wgui/src/color.rs @@ -0,0 +1,226 @@ +use crate::drawing; +use num_enum::TryFromPrimitive; +use strum::EnumCount; +// Primary: button color +// OnPrimary: text color placed on the Primary-colored button + +#[derive(Debug, Copy, Clone, TryFromPrimitive, EnumCount)] +#[repr(u8)] +pub enum WguiColorName { + Primary, + OnPrimary, + Secondary, + OnSecondary, + Tertiary, + OnTertiary, + Danger, + OnDanger, + Background, + OnBackground, + Outline, + BackgroundVariant, + OnBackgroundVariant, +} + +pub struct WguiColorPalette { + colors: Vec<(drawing::Color, &'static str)>, +} + +#[derive(Clone, Copy, Debug)] +pub struct WguiNamedColor { + name: WguiColorName, + rgb_multiplier: f32, + rgb_addition: f32, + alpha: f32, +} + +#[derive(Clone, Copy, Debug)] +pub enum WguiColor { + Raw(drawing::Color), + Named(WguiNamedColor), +} + +impl WguiColorPalette { + pub fn new() -> WguiColorPalette { + let mut colors = Vec::<(drawing::Color, &'static str)>::new(); + colors.resize(WguiColorName::COUNT, Default::default()); + + // default theme + colors[WguiColorName::Primary as usize] = (drawing::Color::from_hex("#21adff").unwrap(), "primary"); + colors[WguiColorName::OnPrimary as usize] = (drawing::Color::from_hex("#eaf7ff").unwrap(), "on_primary"); + colors[WguiColorName::Secondary as usize] = (drawing::Color::from_hex("#424b56").unwrap(), "secondary"); + colors[WguiColorName::OnSecondary as usize] = (drawing::Color::from_hex("#d2e6ff").unwrap(), "on_secondary"); + colors[WguiColorName::Tertiary as usize] = (drawing::Color::from_hex("#1aedcd").unwrap(), "tertiary"); + colors[WguiColorName::OnTertiary as usize] = (drawing::Color::from_hex("#d1fff8").unwrap(), "on_tertiary"); + colors[WguiColorName::Danger as usize] = (drawing::Color::from_hex("#ea0c76").unwrap(), "danger"); + colors[WguiColorName::OnDanger as usize] = (drawing::Color::from_hex("#ffebf5").unwrap(), "on_danger"); + colors[WguiColorName::Background as usize] = (drawing::Color::from_hex("#00121a").unwrap(), "background"); + colors[WguiColorName::OnBackground as usize] = (drawing::Color::from_hex("#e4f5f6").unwrap(), "on_background"); + colors[WguiColorName::Outline as usize] = (drawing::Color::from_hex("#204353").unwrap(), "outline"); + colors[WguiColorName::BackgroundVariant as usize] = + (drawing::Color::from_hex("#031e2a").unwrap(), "background_variant"); + colors[WguiColorName::OnBackgroundVariant as usize] = + (drawing::Color::from_hex("#e2fdff").unwrap(), "on_background_variant"); + + WguiColorPalette { colors } + } + + pub fn find(&self, in_name: &str) -> Option { + for (idx, (_, name)) in self.colors.iter().enumerate() { + if in_name == *name { + return Some( + WguiColorName::try_from(idx as u8) + .unwrap() /* this never fails */ + .into(), + ); + } + } + + None + } +} + +impl Default for WguiColorPalette { + fn default() -> Self { + Self::new() + } +} + +impl WguiColor { + pub fn resolve(&self, palette: &WguiColorPalette) -> drawing::Color { + match &self { + WguiColor::Raw(color) => *color, + WguiColor::Named(color) => color.resolve(palette), + } + } + + #[must_use] + pub const fn mult_rgb(&self, mult: f32) -> WguiColor { + match self { + WguiColor::Raw(color) => WguiColor::Raw(color.mult_rgb(mult)), + WguiColor::Named(color) => WguiColor::Named(WguiNamedColor { + name: color.name, + rgb_multiplier: color.rgb_multiplier * mult, + rgb_addition: color.rgb_addition, + alpha: color.alpha, + }), + } + } + + #[must_use] + pub const fn add_rgb(&self, addition: f32) -> WguiColor { + match self { + WguiColor::Raw(color) => WguiColor::Raw(color.add_rgb(addition)), + WguiColor::Named(color) => WguiColor::Named(WguiNamedColor { + name: color.name, + rgb_multiplier: color.rgb_multiplier, + rgb_addition: color.rgb_addition + addition, + alpha: color.alpha, + }), + } + } + + #[must_use] + pub const fn add_alpha(&self, alpha: f32) -> WguiColor { + match self { + WguiColor::Raw(color) => WguiColor::Raw(drawing::Color { + r: color.r, + g: color.g, + b: color.b, + a: color.a + alpha, + }), + WguiColor::Named(color) => WguiColor::Named(WguiNamedColor { + name: color.name, + rgb_multiplier: color.rgb_multiplier, + rgb_addition: color.rgb_addition, + alpha: color.alpha + alpha, + }), + } + } + + #[must_use] + pub const fn with_alpha(&self, alpha: f32) -> WguiColor { + match self { + WguiColor::Raw(color) => WguiColor::Raw(color.with_alpha(alpha)), + WguiColor::Named(color) => WguiColor::Named(WguiNamedColor { + name: color.name, + rgb_multiplier: color.rgb_multiplier, + rgb_addition: color.rgb_addition, + alpha, + }), + } + } + + // returns named colors if val is 0 or 1, raw otherwise + #[must_use] + pub fn lerp(&self, palette: &WguiColorPalette, other: &WguiColor, val: f32) -> WguiColor { + if val <= 0.0 { + *self + } else if val >= 1.0 { + *other + } else { + let c1 = self.resolve(palette); + let c2 = other.resolve(palette); + c1.lerp(&c2, val).into() + } + } +} + +impl WguiColorName { + pub const fn to_wgui_color(&self) -> WguiColor { + WguiColor::Named(WguiNamedColor { + name: *self, + alpha: 1.0, + rgb_multiplier: 1.0, + rgb_addition: 0.0, + }) + } +} + +impl From for WguiColor { + fn from(name: WguiColorName) -> Self { + name.to_wgui_color() + } +} + +impl From for WguiColor { + fn from(color: drawing::Color) -> Self { + WguiColor::Raw(color) + } +} + +impl Default for WguiColor { + fn default() -> Self { + Self::Raw(Default::default()) + } +} + +impl WguiNamedColor { + pub fn resolve(&self, palette: &WguiColorPalette) -> drawing::Color { + let idx = self.name as usize; + if idx >= palette.colors.len() { + // unlikely + debug_assert!(false); + return drawing::Color::new(1.0, 0.0, 1.0, 1.0); // Magenta + } + + let (mut color, _) = palette.colors[idx]; + if self.alpha != 1.0 { + color.a *= self.alpha; + } + + if self.rgb_multiplier != 1.0 { + color.r *= self.rgb_multiplier; + color.g *= self.rgb_multiplier; + color.b *= self.rgb_multiplier; + } + + if self.rgb_addition != 0.0 { + color.r += self.rgb_addition; + color.g += self.rgb_addition; + color.b += self.rgb_addition; + } + + color + } +} diff --git a/wgui/src/components/bar_graph.rs b/wgui/src/components/bar_graph.rs index 492527af..9e2e2e0e 100644 --- a/wgui/src/components/bar_graph.rs +++ b/wgui/src/components/bar_graph.rs @@ -134,10 +134,10 @@ pub fn construct( root.id, WidgetRectangle::create(WidgetRectangleParams { border: 2.0, - border_color: drawing::Color::new(1.0, 1.0, 1.0, 0.5), + border_color: drawing::Color::new(1.0, 1.0, 1.0, 0.5).into(), round: WLength::Units(3.0), gradient: GradientMode::Vertical, - color: drawing::Color::new(0.0, 0.0, 0.0, 0.6), + color: drawing::Color::new(0.0, 0.0, 0.0, 0.6).into(), ..Default::default() }), taffy::Style { diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs index 77654986..1f674113 100644 --- a/wgui/src/components/button.rs +++ b/wgui/src/components/button.rs @@ -1,11 +1,12 @@ use crate::{ animation::{Animation, AnimationEasing}, assets::AssetPath, + color::{WguiColor, WguiColorName}, components::{ self, Component, ComponentBase, ComponentTrait, RefreshData, tooltip::{ComponentTooltip, TooltipTrait}, }, - drawing::{self, Boundary, Color}, + drawing::{self, Boundary}, event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, i18n::Translation, layout::{WidgetID, WidgetPair}, @@ -33,11 +34,11 @@ use taffy::{AlignItems, JustifyContent, prelude::length}; pub struct Params<'a> { pub text: Option, // if unset, label will not be populated pub sprite_src: Option>, - pub color: Option, + pub color: Option, pub border: f32, - pub border_color: Option, - pub hover_border_color: Option, - pub hover_color: Option, + pub border_color: Option, + pub hover_border_color: Option, + pub hover_color: Option, pub round: WLength, pub style: taffy::Style, pub text_style: TextStyle, @@ -77,10 +78,10 @@ pub struct ButtonClickEvent { pub type ButtonClickCallback = Rc anyhow::Result<()>>; pub struct Colors { - pub color: drawing::Color, - pub border_color: drawing::Color, - pub hover_color: drawing::Color, - pub hover_border_color: drawing::Color, + pub color: WguiColor, + pub border_color: WguiColor, + pub hover_color: WguiColor, + pub hover_border_color: WguiColor, } struct State { @@ -136,12 +137,8 @@ impl ComponentTrait for ComponentButton { } } -fn get_color2(color: &drawing::Color, gradient_intensity: f32) -> drawing::Color { - color.lerp(&Color::new(0.0, 0.0, 0.0, color.a), gradient_intensity) -} - -fn get_hover_color(color: &drawing::Color) -> drawing::Color { - Color::new(color.r + 0.25, color.g + 0.25, color.g + 0.25, color.a + 0.15) +fn get_color2(color: &WguiColor, gradient_intensity: f32) -> WguiColor { + color.mult_rgb(1.0 - gradient_intensity) } impl ComponentButton { @@ -161,18 +158,17 @@ impl ComponentButton { label.set_text(common, text); } - pub fn set_color(&self, common: &mut CallbackDataCommon, color: Color) { + pub fn set_color(&self, common: &mut CallbackDataCommon, color: WguiColor) { let gradient_intensity = common.state.theme.gradient_intensity; let Some(mut rect) = common.state.widgets.get_as::(self.data.id_rect) else { return; }; + rect.params.color = color; + rect.params.color2 = get_color2(&color, gradient_intensity); let mut state = self.state.borrow_mut(); state.colors.color = color; - state.colors.hover_color = get_hover_color(&color); - rect.params.color = color; - rect.params.color2 = get_color2(&color, gradient_intensity); } pub fn get_time_since_last_pressed(&self) -> Duration { @@ -220,10 +216,15 @@ impl ComponentButton { let state = state.borrow(); let colors = &state.colors; - let bgcolor = colors.color.lerp(&colors.hover_color, mult * 0.5); - rect.params.color = bgcolor; - rect.params.color2 = get_color2(&bgcolor, gradient_intensity); - rect.params.border_color = colors.border_color.lerp(&colors.hover_border_color, mult); + + { + let globals = common.globals(); + let palette = &globals.palette; + let bgcolor = colors.color.lerp(palette, &colors.hover_color, mult * 0.5); + rect.params.color = bgcolor; + rect.params.color2 = get_color2(&bgcolor, gradient_intensity); + rect.params.border_color = colors.border_color.lerp(palette, &colors.hover_border_color, mult); + } common.alterables.mark_redraw(); }), ); @@ -245,13 +246,18 @@ fn anim_hover( ) { let mult = pos * if pressed { 1.5 } else { 1.0 }; + let globals = common.globals(); + let (init_border_color, init_color) = if sticky_down { - (colors.hover_border_color, colors.color.lerp(&colors.hover_color, 0.5)) + ( + colors.hover_border_color, + colors.color.lerp(&globals.palette, &colors.hover_color, 0.5), + ) } else { (colors.border_color, colors.color) }; - let bgcolor = init_color.lerp(&colors.hover_color, mult); + let bgcolor = init_color.lerp(&globals.palette, &colors.hover_color, mult); let gradient_intensity = common.state.theme.gradient_intensity; @@ -263,7 +269,7 @@ fn anim_hover( rect.params.color = bgcolor; rect.params.color2 = get_color2(&bgcolor, gradient_intensity); - rect.params.border_color = init_border_color.lerp(&colors.hover_border_color, mult); + rect.params.border_color = init_border_color.lerp(&globals.palette, &colors.hover_border_color, mult); } fn anim_hover_create(state: Rc>, widget_id: WidgetID, fade_in: bool, anim_mult: f32) -> Animation { @@ -446,25 +452,26 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul style.overflow.x = taffy::Overflow::Hidden; style.overflow.y = taffy::Overflow::Hidden; + let globals = ess.layout.state.globals.get(); + // update colors to default ones if they are not specified - let color = params.color.unwrap_or(theme.button_color); + let color = params.color.unwrap_or_else(|| WguiColorName::BackgroundVariant.into()); let border_color = params .border_color - .unwrap_or_else(|| Color::new(color.r, color.g, color.b, color.a + 0.25)); + .unwrap_or_else(|| WguiColor::from(WguiColorName::Outline)); - let hover_color = params.hover_color.unwrap_or_else(|| get_hover_color(&color)); + let hover_color = params + .hover_color + .unwrap_or_else(|| color.add_rgb(0.25).add_alpha(0.15)); let hover_border_color = params .hover_border_color - .unwrap_or_else(|| Color::new(color.r + 0.5, color.g + 0.5, color.g + 0.5, color.a + 0.5)); + .unwrap_or_else(|| border_color.add_rgb(0.5).add_alpha(0.5)); let gradient_intensity = theme.gradient_intensity; - let light_text = { - let mult = if theme.dark_mode { color.a } else { 1.0 - color.a }; - (color.r + color.g + color.b) * mult < 1.5 - }; + drop(globals); let (root, _) = ess.layout.add_child( ess.parent, @@ -515,11 +522,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul content, style: TextStyle { weight: Some(FontWeight::Bold), - color: Some(if light_text { - Color::new(1.0, 1.0, 1.0, 1.0) - } else { - Color::new(0.0, 0.0, 0.0, 1.0) - }), ..params.text_style }, }, diff --git a/wgui/src/components/checkbox.rs b/wgui/src/components/checkbox.rs index cc11a86d..24f29c0c 100644 --- a/wgui/src/components/checkbox.rs +++ b/wgui/src/components/checkbox.rs @@ -9,12 +9,13 @@ use taffy::{ use crate::{ animation::{Animation, AnimationEasing}, + color::{WguiColor, WguiColorName}, components::{ Component, ComponentBase, ComponentTrait, RefreshData, radio_group::ComponentRadioGroup, tooltip::{self, ComponentTooltip, TooltipTrait}, }, - drawing::Color, + drawing, event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, i18n::Translation, layout::{self, WidgetID, WidgetPair}, @@ -31,7 +32,7 @@ use crate::{ pub struct Params { pub text: Translation, pub style: taffy::Style, - pub color_checked: Option, + pub color_checked: Option, pub box_size: f32, pub checked: bool, pub radio_group: Option>, @@ -87,7 +88,7 @@ struct Data { value: Option>, // arbitrary value assigned to the element radio_group: Option>, - color_checked: Color, + color_checked: WguiColor, } pub struct ComponentCheckbox { @@ -96,7 +97,7 @@ pub struct ComponentCheckbox { state: Rc>, } -const COLOR_UNCHECKED: Color = Color::new(0.0, 0.0, 0.0, 0.0); +const COLOR_UNCHECKED: drawing::Color = drawing::Color::new(0.0, 0.0, 0.0, 0.0); impl ComponentTrait for ComponentCheckbox { fn base(&self) -> &ComponentBase { @@ -114,7 +115,11 @@ impl ComponentTrait for ComponentCheckbox { fn set_box_checked(widgets: &layout::WidgetMap, data: &Data, checked: bool) { widgets.call(data.id_inner_box, |rect: &mut WidgetRectangle| { - rect.params.color = if checked { data.color_checked } else { COLOR_UNCHECKED } + rect.params.color = if checked { + data.color_checked + } else { + COLOR_UNCHECKED.into() + } }); } @@ -159,13 +164,13 @@ impl ComponentCheckbox { } fn anim_hover(rect: &mut WidgetRectangle, pos: f32, pressed: bool) { - let brightness = pos * if pressed { 0.6 } else { 0.4 }; + let mut brightness = pos * if pressed { 0.6 } else { 0.4 }; rect.params.border = 2.0; - rect.params.color.a = brightness; - rect.params.border_color.a = rect.params.color.a; + rect.params.color = rect.params.color.with_alpha(brightness); if pressed { - rect.params.border_color.a += 0.4; + brightness += 0.4; } + rect.params.border_color = rect.params.border_color.with_alpha(brightness); } fn anim_hover_in(state: Rc>, widget_id: WidgetID, anim_mult: f32) -> Animation { @@ -329,7 +334,6 @@ fn register_event_mouse_release( pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let mut style = params.style; - let theme = &ess.layout.state.theme; // force-override style style.flex_wrap = taffy::FlexWrap::NoWrap; @@ -358,13 +362,12 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul (WLength::Units(5.0), WLength::Units(8.0)) }; - let color_checked = params.color_checked.unwrap_or(theme.accent_color); + let color_checked = params.color_checked.unwrap_or(WguiColorName::Primary.into()); let (root, _) = ess.layout.add_child( ess.parent, WidgetRectangle::create(WidgetRectangleParams { - color: Color::new(1.0, 1.0, 1.0, 0.0), - border_color: Color::new(1.0, 1.0, 1.0, 0.0), + color: WguiColor::from(WguiColorName::OnPrimary).with_alpha(0.0), round: round_5, ..Default::default() }), @@ -382,9 +385,9 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul id_container, WidgetRectangle::create(WidgetRectangleParams { border: 2.0, - border_color: Color::new(1.0, 1.0, 1.0, 1.0), + border_color: WguiColorName::OnPrimary.into(), round: round_8, - color: Color::new(1.0, 1.0, 1.0, 0.0), + color: WguiColor::from(WguiColorName::OnPrimary).with_alpha(0.0), ..Default::default() }), taffy::Style { @@ -400,7 +403,11 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul outer_box.id, WidgetRectangle::create(WidgetRectangleParams { round: round_5, - color: if params.checked { color_checked } else { COLOR_UNCHECKED }, + color: if params.checked { + color_checked + } else { + COLOR_UNCHECKED.into() + }, ..Default::default() }), taffy::Style { diff --git a/wgui/src/components/color_selector.rs b/wgui/src/components/color_selector.rs index a7ef1b4d..5885d04e 100644 --- a/wgui/src/components/color_selector.rs +++ b/wgui/src/components/color_selector.rs @@ -96,7 +96,10 @@ impl ComponentTrait for ComponentColorSelector { Translation::from_raw_text_string(state.color.to_hex_rgb()), ); - self.data.button.set_color(&mut data.layout.common(), state.color); + self + .data + .button + .set_color(&mut data.layout.common(), state.color.into()); } } @@ -210,7 +213,7 @@ impl ComponentColorSelector { .widgets .get_as::(popup_state.id_rect_color) { - rect.set_color(common, new_color); + rect.set_color(common, new_color.into()); } set_color_internal(&mut state, common, new_color); }) @@ -240,10 +243,10 @@ pub fn construct( let (widget_button, button) = button::construct( ess, button::Params { - color: Some(params.color), + color: Some(params.color.into()), round: WLength::Percent(1.0), border: 2.0, - border_color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), + border_color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0).into()), style, ..Default::default() }, diff --git a/wgui/src/components/editbox.rs b/wgui/src/components/editbox.rs index daae860e..9cb296a9 100644 --- a/wgui/src/components/editbox.rs +++ b/wgui/src/components/editbox.rs @@ -8,8 +8,9 @@ use taffy::prelude::{auto, length, percent}; use crate::{ animation::{Animation, AnimationEasing}, + color::{WguiColor, WguiColorName}, components::{Component, ComponentBase, ComponentTrait, FocusChangeData, RefreshData}, - drawing::{self, Color}, + drawing::Color, event::{self, CallbackDataCommon, CallbackMetadata, EventListenerCollection, EventListenerKind, StyleSetRequest}, i18n::Translation, layout::{WidgetID, WidgetPair}, @@ -55,7 +56,7 @@ pub struct ComponentEditBox { fn anim_bottom_rect( common: &mut CallbackDataCommon, - accent_color: drawing::Color, + accent_color: WguiColor, id_rect: WidgetID, anim_mult: f32, focused: bool, @@ -69,10 +70,12 @@ fn anim_bottom_rect( let rect = data.obj.get_as_mut::().unwrap(); let pos_bidir = if focused { data.pos } else { 1.0 - data.pos }; - rect.set_color( - common, - accent_color.lerp(&drawing::Color::new(1.0, 1.0, 1.0, 1.0), pos_bidir), + let color_lerped = accent_color.lerp( + &common.globals().palette, + &WguiColorName::OnBackgroundVariant.into(), + pos_bidir, ); + rect.set_color(common, color_lerped); common.alterables.set_style( data.widget_id, @@ -100,9 +103,9 @@ fn anim_bottom_rect( fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State) -> Option<()> { let theme = &common.state.theme; - let editbox_color = theme.editbox_color; + let editbox_color = WguiColor::from(WguiColorName::BackgroundVariant); + let accent_color = WguiColor::from(WguiColorName::Primary); let anim_mult = theme.animation_mult; - let accent_color = theme.accent_color; let (rect_color, border_color) = if state.focused { (editbox_color.add_rgb(0.15), editbox_color.add_rgb(0.15 + 0.25)) @@ -271,7 +274,7 @@ pub fn construct( ess: &mut ConstructEssentials, mut params: Params, ) -> anyhow::Result<(WidgetPair, Rc)> { - let text_color = ess.layout.state.theme.text_color; + let text_color = WguiColor::from(WguiColorName::OnBackgroundVariant); if params.style.size.width.is_auto() { params.style.size.width = length(128.0); diff --git a/wgui/src/components/slider.rs b/wgui/src/components/slider.rs index 69e338d5..303a0647 100644 --- a/wgui/src/components/slider.rs +++ b/wgui/src/components/slider.rs @@ -5,11 +5,11 @@ use taffy::prelude::{length, percent}; use crate::{ animation::{Animation, AnimationEasing}, + color::{WguiColor, WguiColorName, WguiColorPalette}, components::{ Component, ComponentBase, ComponentTrait, RefreshData, tooltip::{self, ComponentTooltip, TooltipTrait}, }, - drawing::{self}, event::{ self, CallbackDataCommon, CallbackMetadata, DeviceBitmask, EventAlterables, EventListenerCollection, EventListenerKind, StyleSetRequest, @@ -346,12 +346,12 @@ impl State { } } -const BODY_COLOR: drawing::Color = drawing::Color::new(0.6, 0.65, 0.7, 0.1); -const BODY_BORDER_COLOR: drawing::Color = drawing::Color::new(0.4, 0.45, 0.5, 0.6); -const HANDLE_BORDER_COLOR: drawing::Color = drawing::Color::new(0.85, 0.85, 0.85, 1.0); -const HANDLE_BORDER_COLOR_HOVERED: drawing::Color = drawing::Color::new(0.0, 0.0, 0.0, 1.0); -const HANDLE_COLOR: drawing::Color = drawing::Color::new(1.0, 1.0, 1.0, 1.0); -const HANDLE_COLOR_HOVERED: drawing::Color = drawing::Color::new(0.9, 0.9, 0.9, 1.0); +const BODY_COLOR: WguiColor = WguiColorName::BackgroundVariant.to_wgui_color(); +const BODY_BORDER_COLOR: WguiColor = WguiColorName::Outline.to_wgui_color(); +const HANDLE_COLOR: WguiColorName = WguiColorName::Secondary; +const HANDLE_COLOR_HOVERED: WguiColor = WguiColorName::Secondary.to_wgui_color().add_rgb(0.1); +const HANDLE_BORDER_COLOR: WguiColor = WguiColorName::Primary.to_wgui_color(); +const HANDLE_BORDER_COLOR_HOVERED: WguiColor = WguiColorName::Primary.to_wgui_color().mult_rgb(1.25); const SLIDER_HOVER_SCALE: f32 = 0.25; fn get_anim_transform(pos: f32, widget_size: Vec2) -> Mat4 { @@ -361,9 +361,9 @@ fn get_anim_transform(pos: f32, widget_size: Vec2) -> Mat4 { ) } -fn anim_rect(rect: &mut WidgetRectangle, pos: f32) { - rect.params.color = drawing::Color::lerp(&HANDLE_COLOR, &HANDLE_COLOR_HOVERED, pos); - rect.params.border_color = drawing::Color::lerp(&HANDLE_BORDER_COLOR, &HANDLE_BORDER_COLOR_HOVERED, pos); +fn anim_rect(rect: &mut WidgetRectangle, palette: &WguiColorPalette, pos: f32) { + rect.params.color = WguiColor::lerp(&HANDLE_COLOR.into(), palette, &HANDLE_COLOR_HOVERED, pos); + rect.params.border_color = WguiColor::lerp(&HANDLE_BORDER_COLOR, palette, &HANDLE_BORDER_COLOR_HOVERED, pos); } fn on_enter_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID, anim_mult: f32) { @@ -374,7 +374,7 @@ fn on_enter_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID, an Box::new(move |common, data| { let rect = data.obj.get_as_mut::().unwrap(); data.data.transform = get_anim_transform(data.pos, data.widget_boundary.size); - anim_rect(rect, data.pos); + anim_rect(rect, &common.globals().palette, data.pos); common.alterables.mark_redraw(); }), )); @@ -388,7 +388,7 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID, an Box::new(move |common, data| { let rect = data.obj.get_as_mut::().unwrap(); data.data.transform = get_anim_transform(1.0 - data.pos, data.widget_boundary.size); - anim_rect(rect, 1.0 - data.pos); + anim_rect(rect, &common.globals().palette, 1.0 - data.pos); common.alterables.mark_redraw(); }), )); @@ -606,7 +606,7 @@ fn mount_slider_handle( let (slider_handle_rect, _) = ess.layout.add_child( slider_handle.id, WidgetRectangle::create(WidgetRectangleParams { - color: HANDLE_COLOR, + color: HANDLE_COLOR.into(), border_color: HANDLE_BORDER_COLOR, border: 2.0, round: WLength::Percent(1.0), @@ -628,7 +628,7 @@ fn mount_slider_handle( WidgetLabelParams { content: Translation::default(), style: TextStyle { - color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), // always black + color: Some(WguiColorName::OnPrimary.into()), weight: Some(FontWeight::Bold), align: Some(HorizontalAlign::Center), ..Default::default() diff --git a/wgui/src/components/tabs.rs b/wgui/src/components/tabs.rs index 1143ec81..f9b2fd43 100644 --- a/wgui/src/components/tabs.rs +++ b/wgui/src/components/tabs.rs @@ -1,5 +1,6 @@ use crate::{ assets::AssetPath, + color::WguiColorName, components::{ Component, ComponentBase, ComponentTrait, RefreshData, button::{self, ComponentButton}, @@ -66,16 +67,11 @@ impl ComponentTrait for ComponentTabs { impl State { fn select_entry(&mut self, common: &mut CallbackDataCommon, name: &Rc) { - let (color_accent, color_button) = { - let theme = &common.state.theme; - (theme.accent_color, theme.button_color) - }; - for entry in &self.mounted_entries { if *entry.name == **name { - entry.button.set_color(common, color_accent); + entry.button.set_color(common, WguiColorName::Primary.into()); } else { - entry.button.set_color(common, color_button); + entry.button.set_color(common, WguiColorName::BackgroundVariant.into()); } } self.selected_entry_name = name.clone(); diff --git a/wgui/src/components/tooltip.rs b/wgui/src/components/tooltip.rs index 9af734e0..0152c8ca 100644 --- a/wgui/src/components/tooltip.rs +++ b/wgui/src/components/tooltip.rs @@ -4,8 +4,8 @@ use taffy::prelude::length; use crate::{ animation::{Animation, AnimationEasing}, + color::{WguiColor, WguiColorName}, components::{self, Component, ComponentBase, ComponentTrait, RefreshData}, - drawing::Color, event::CallbackDataCommon, i18n::Translation, layout::{self, LayoutTask, LayoutTasks, WidgetID, WidgetPair}, @@ -153,8 +153,8 @@ impl Drop for ComponentTooltip { } } -pub const TOOLTIP_COLOR: Color = Color::new(0.02, 0.02, 0.02, 0.95); -pub const TOOLTIP_BORDER_COLOR: Color = Color::new(0.4, 0.4, 0.4, 1.0); +pub const TOOLTIP_COLOR: WguiColorName = WguiColorName::BackgroundVariant; +pub const TOOLTIP_BORDER_COLOR: WguiColorName = WguiColorName::Outline; pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let absolute_boundary = { @@ -233,8 +233,8 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul let (rect, _) = ess.layout.add_child( div.id, WidgetRectangle::create(WidgetRectangleParams { - color: TOOLTIP_COLOR, - border_color: TOOLTIP_BORDER_COLOR, + color: TOOLTIP_COLOR.into(), + border_color: TOOLTIP_BORDER_COLOR.into(), border: 2.0, round: WLength::Units(24.0), ..Default::default() @@ -300,8 +300,8 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul Box::new(move |common, data| { let rect = data.obj.get_as_mut::().unwrap(); /* safe */ let alpha = data.pos; - rect.params.color.a = alpha; - rect.params.border_color.a = alpha; + rect.params.color = rect.params.color.with_alpha(alpha); + rect.params.border_color = rect.params.border_color.with_alpha(alpha); let position_shift = state.borrow().position_shift; @@ -313,7 +313,11 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul )); if let Some(mut label) = common.state.widgets.get_as::(label.id) { - label.set_color(common, Color::new(1.0, 1.0, 1.0, alpha), true); + label.set_color( + common, + WguiColor::from(WguiColorName::OnBackground).with_alpha(alpha), + true, + ); } common.alterables.mark_redraw(); diff --git a/wgui/src/components/video.rs b/wgui/src/components/video.rs index 9d709114..c629e56b 100644 --- a/wgui/src/components/video.rs +++ b/wgui/src/components/video.rs @@ -4,8 +4,8 @@ use taffy::prelude::percent; use crate::{ animation::Animation, assets::AssetPath, + color::WguiColorName, components::{Component, ComponentBase, ComponentTrait, RefreshData}, - drawing::Color, event::EventAlterables, globals::WguiGlobals, layout::{Layout, WidgetID, WidgetPair}, @@ -227,7 +227,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul let (root, _) = ess.layout.add_child( ess.parent, WidgetRectangle::create(WidgetRectangleParams { - color: Color::new(0.1, 0.1, 0.1, 1.0), + color: WguiColorName::Background.into(), ..Default::default() }), style, diff --git a/wgui/src/drawing.rs b/wgui/src/drawing.rs index c0c59ea1..aa47156d 100644 --- a/wgui/src/drawing.rs +++ b/wgui/src/drawing.rs @@ -119,7 +119,7 @@ impl Color { } #[must_use] - pub fn add_rgb(&self, n: f32) -> Self { + pub const fn add_rgb(&self, n: f32) -> Self { Self { r: self.r + n, g: self.g + n, @@ -129,7 +129,7 @@ impl Color { } #[must_use] - pub fn mult_rgb(&self, n: f32) -> Self { + pub const fn mult_rgb(&self, n: f32) -> Self { Self { r: self.r * n, g: self.g * n, @@ -139,7 +139,7 @@ impl Color { } #[must_use] - pub fn lerp(&self, other: &Self, n: f32) -> Self { + pub const fn lerp(&self, other: &Self, n: f32) -> Self { Self { r: self.r * (1.0 - n) + other.r * n, g: self.g * (1.0 - n) + other.g * n, @@ -191,6 +191,46 @@ impl Color { pub const fn as_arr(&self) -> [f32; 4] { [self.r, self.b, self.g, self.a] } + + // expects strings like "#424242" or "#424242FF" + pub fn from_hex(html_hex: &str) -> Option { + let Some(ch) = html_hex.chars().next() else { + return None; + }; + + if ch != '#' { + return None; + } + + if html_hex.len() == 7 { + if let (Ok(r), Ok(g), Ok(b)) = ( + u8::from_str_radix(&html_hex[1..3], 16), + u8::from_str_radix(&html_hex[3..5], 16), + u8::from_str_radix(&html_hex[5..7], 16), + ) { + return Some(drawing::Color::new( + f32::from(r) / 255., + f32::from(g) / 255., + f32::from(b) / 255., + 1., + )); + } + } else if html_hex.len() == 9 + && let (Ok(r), Ok(g), Ok(b), Ok(a)) = ( + u8::from_str_radix(&html_hex[1..3], 16), + u8::from_str_radix(&html_hex[3..5], 16), + u8::from_str_radix(&html_hex[5..7], 16), + u8::from_str_radix(&html_hex[7..9], 16), + ) { + return Some(drawing::Color::new( + f32::from(r) / 255., + f32::from(g) / 255., + f32::from(b) / 255., + f32::from(a) / 255., + )); + } + None + } } impl Default for Color { diff --git a/wgui/src/globals.rs b/wgui/src/globals.rs index e1a54333..9337aebc 100644 --- a/wgui/src/globals.rs +++ b/wgui/src/globals.rs @@ -12,6 +12,7 @@ use regex::Regex; use crate::{ assets::{AssetPath, AssetProvider, LangProvider}, assets_internal, + color::WguiColorPalette, font_config::{WguiFontConfig, WguiFontSystem}, i18n::I18n, renderer_vk::text::custom_glyph::CustomGlyphCache, @@ -24,6 +25,7 @@ pub struct Globals { pub i18n_builtin: I18n, pub font_system: WguiFontSystem, pub custom_glyph_cache: CustomGlyphCache, + pub palette: WguiColorPalette, } #[derive(Clone)] @@ -46,6 +48,7 @@ impl WguiGlobals { font_system: WguiFontSystem::new(font_config, i18n_builtin.get_locale()), i18n_builtin, custom_glyph_cache: CustomGlyphCache::new(), + palette: Default::default(), })))) } diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs index 22756a03..9ad11274 100644 --- a/wgui/src/layout.rs +++ b/wgui/src/layout.rs @@ -930,7 +930,7 @@ impl Layout { layout.location.y, layout.content_size.width, layout.content_size.height, - state.obj.debug_print() + state.obj.debug_print(&self.state.globals.get()) ); buf.append(&mut line.into_bytes()); diff --git a/wgui/src/lib.rs b/wgui/src/lib.rs index 7be1645e..5ebaf0a3 100644 --- a/wgui/src/lib.rs +++ b/wgui/src/lib.rs @@ -26,6 +26,7 @@ pub mod animation; pub mod any; pub mod assets; mod assets_internal; +pub mod color; pub mod components; pub mod drawing; pub mod event; diff --git a/wgui/src/parser/component_button.rs b/wgui/src/parser/component_button.rs index 4e640c1c..60d53672 100644 --- a/wgui/src/parser/component_button.rs +++ b/wgui/src/parser/component_button.rs @@ -1,7 +1,7 @@ use crate::{ assets::AssetPath, + color::WguiColor, components::{Component, button}, - drawing::Color, i18n::Translation, layout::WidgetID, parser::{ @@ -21,11 +21,11 @@ pub fn parse_component_button<'a>( attribs: &[AttribPair], tag_name: &str, ) -> anyhow::Result { - let mut color: Option = None; + let mut color: Option = None; let mut border = 2.0; - let mut border_color: Option = None; - let mut hover_color: Option = None; - let mut hover_border_color: Option = None; + let mut border_color: Option = None; + let mut hover_color: Option = None; + let mut hover_border_color: Option = None; let mut round = WLength::Units(4.0); let mut tooltip = TooltipAttribs::default(); let mut sticky: bool = false; diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs index 78ab9f22..a50a60aa 100644 --- a/wgui/src/parser/mod.rs +++ b/wgui/src/parser/mod.rs @@ -21,7 +21,6 @@ mod widget_sprite; use crate::{ assets::{AssetPath, AssetPathOwned, normalize_path}, components::{Component, ComponentWeak}, - drawing::{self}, globals::WguiGlobals, i18n::Translation, layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap, WidgetPair}, @@ -529,31 +528,6 @@ impl ParserContext<'_> { } } - fn populate_theme_variables(&mut self) { - let theme = self.layout.state.theme.clone(); - - macro_rules! insert_color_vars { - ($self:expr, $name:literal, $field:expr, $alpha:expr) => { - $self.insert_var(concat!("color_", $name), &$field.to_hex()); - $self.insert_var( - concat!("color_", $name, "_translucent"), - &$field.with_alpha($alpha).to_hex(), - ); - $self.insert_var(concat!("color_", $name, "_50"), &$field.mult_rgb(0.50).to_hex()); - $self.insert_var(concat!("color_", $name, "_40"), &$field.mult_rgb(0.40).to_hex()); - $self.insert_var(concat!("color_", $name, "_30"), &$field.mult_rgb(0.30).to_hex()); - $self.insert_var(concat!("color_", $name, "_20"), &$field.mult_rgb(0.20).to_hex()); - $self.insert_var(concat!("color_", $name, "_10"), &$field.mult_rgb(0.10).to_hex()); - }; - } - - insert_color_vars!(self, "text", theme.text_color, theme.translucent_alpha); - insert_color_vars!(self, "accent", theme.accent_color, theme.translucent_alpha); - insert_color_vars!(self, "danger", theme.danger_color, theme.translucent_alpha); - insert_color_vars!(self, "faded", theme.faded_color, theme.translucent_alpha); - insert_color_vars!(self, "bg", theme.bg_color, theme.translucent_alpha); - } - fn print_invalid_attrib(&self, tag_name: &str, key: &str, value: &str) { log::warn!( "{}: <{tag_name}> value for \"{key}\" is invalid: \"{value}\"", @@ -644,38 +618,6 @@ fn is_percent(value: &str) -> bool { value.ends_with('%') } -// Parses a color from a HTML hex string -pub fn parse_color_hex(html_hex: &str) -> Option { - if html_hex.len() == 7 { - if let (Ok(r), Ok(g), Ok(b)) = ( - u8::from_str_radix(&html_hex[1..3], 16), - u8::from_str_radix(&html_hex[3..5], 16), - u8::from_str_radix(&html_hex[5..7], 16), - ) { - return Some(drawing::Color::new( - f32::from(r) / 255., - f32::from(g) / 255., - f32::from(b) / 255., - 1., - )); - } - } else if html_hex.len() == 9 - && let (Ok(r), Ok(g), Ok(b), Ok(a)) = ( - u8::from_str_radix(&html_hex[1..3], 16), - u8::from_str_radix(&html_hex[3..5], 16), - u8::from_str_radix(&html_hex[5..7], 16), - u8::from_str_radix(&html_hex[7..9], 16), - ) { - return Some(drawing::Color::new( - f32::from(r) / 255., - f32::from(g) / 255., - f32::from(b) / 255., - f32::from(a) / 255., - )); - } - None -} - fn get_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> Option> { node.children().find(|&child| child.tag_name().name() == name) } @@ -864,7 +806,7 @@ fn process_attrib(template_parameters: &TemplateParams, ctx: &ParserContext, key Some(name) => AttribPair::new(key, name), None => { log::warn!("{}: undefined variable \"{value}\"", ctx.doc_params.path.get_str()); - AttribPair::new(key, "undefined") + AttribPair::new(key, format!("undefined_{}", value)) } } } else { @@ -1298,7 +1240,6 @@ pub fn parse_from_assets( ) -> anyhow::Result { let parser_data = ParserData::default(); let mut ctx = create_default_context(doc_params, layout, &parser_data); - ctx.populate_theme_variables(); ctx.populate_extra_variables(&doc_params.extra.extra_vars); let (file, node_layout) = get_doc_from_asset_path(&ctx, doc_params.path)?; diff --git a/wgui/src/parser/style.rs b/wgui/src/parser/style.rs index afbed247..7586c4c8 100644 --- a/wgui/src/parser/style.rs +++ b/wgui/src/parser/style.rs @@ -4,8 +4,9 @@ use taffy::{ }; use crate::{ + color::WguiColor, drawing, - parser::{AttribPair, ParserContext, is_percent, parse_color_hex, parse_f32}, + parser::{AttribPair, ParserContext, is_percent, parse_f32}, renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle}, widget::util::WLength, }; @@ -31,12 +32,19 @@ pub fn parse_round( } } -pub fn parse_color(ctx: &ParserContext<'_>, tag_name: &str, key: &str, value: &str, color: &mut drawing::Color) { - if let Some(res_color) = parse_color_hex(value) { - *color = res_color; - } else { - ctx.print_invalid_attrib(tag_name, key, value); +pub fn parse_color(ctx: &ParserContext<'_>, tag_name: &str, key: &str, value: &str, out_color: &mut WguiColor) -> bool { + if let Some(color) = drawing::Color::from_hex(value) { + *out_color = color.into(); + return true; } + + if let Some(color) = ctx.layout.state.globals.get().palette.find(value) { + *out_color = color; + return true; + } + + ctx.print_invalid_attrib(tag_name, key, value); + false } pub fn parse_color_opt( @@ -44,12 +52,11 @@ pub fn parse_color_opt( tag_name: &str, key: &str, value: &str, - color: &mut Option, + out_color: &mut Option, ) { - if let Some(res_color) = parse_color_hex(value) { - *color = Some(res_color); - } else { - ctx.print_invalid_attrib(tag_name, key, value); + let mut color = WguiColor::default(); + if parse_color(ctx, tag_name, key, value, &mut color) { + *out_color = Some(color); } } @@ -60,9 +67,7 @@ pub fn parse_text_style(ctx: &ParserContext<'_>, attribs: &[AttribPair], tag_nam let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref()); match key { "color" => { - if let Some(color) = parse_color_hex(value) { - style.color = Some(color); - } + parse_color_opt(ctx, tag_name, key, value, &mut style.color); } "align" => match value { "left" => style.align = Some(HorizontalAlign::Left), @@ -90,7 +95,7 @@ pub fn parse_text_style(ctx: &ParserContext<'_>, attribs: &[AttribPair], tag_nam } } "shadow" => { - if let Some(color) = parse_color_hex(value) { + if let Some(color) = drawing::Color::from_hex(value) { style.shadow.get_or_insert_default().color = color; } } diff --git a/wgui/src/parser/widget_sprite.rs b/wgui/src/parser/widget_sprite.rs index 15ab6846..e59767d4 100644 --- a/wgui/src/parser/widget_sprite.rs +++ b/wgui/src/parser/widget_sprite.rs @@ -2,14 +2,12 @@ use crate::{ layout::WidgetID, parser::{ AttribPair, ParserContext, ParserFile, get_asset_path_from_kv, parse_children, parse_widget_universal, - style::parse_style, + style::{parse_color_opt, parse_style}, }, renderer_vk::text::custom_glyph::CustomGlyphData, widget::sprite::{WidgetSprite, WidgetSpriteParams}, }; -use super::parse_color_hex; - pub fn parse_widget_sprite<'a>( file: &'a ParserFile, ctx: &mut ParserContext, @@ -39,11 +37,7 @@ pub fn parse_widget_sprite<'a>( } } "color" => { - if let Some(color) = parse_color_hex(value) { - params.color = Some(color); - } else { - ctx.print_invalid_attrib(tag_name, key, value); - } + parse_color_opt(ctx, tag_name, key, value, &mut params.color); } _ => {} } diff --git a/wgui/src/renderer_vk/text/mod.rs b/wgui/src/renderer_vk/text/mod.rs index 991f2244..c059471a 100644 --- a/wgui/src/renderer_vk/text/mod.rs +++ b/wgui/src/renderer_vk/text/mod.rs @@ -11,7 +11,10 @@ use etagere::AllocId; use glam::Mat4; use parking_lot::Mutex; -use crate::drawing::{self}; +use crate::{ + color::{WguiColor, WguiColorPalette}, + drawing::{self}, +}; pub static SWASH_CACHE: LazyLock> = LazyLock::new(|| Mutex::new(SwashCache::new())); @@ -45,7 +48,7 @@ impl Default for TextShadow { pub struct TextStyle { pub size: Option, pub line_height: Option, - pub color: Option, + pub color: Option, pub style: Option, pub weight: Option, pub align: Option, @@ -53,12 +56,12 @@ pub struct TextStyle { pub shadow: Option, } -impl From<&TextStyle> for Attrs<'_> { - fn from(style: &TextStyle) -> Self { +impl TextStyle { + pub fn to_attrs(&self, palette: &WguiColorPalette) -> Attrs<'_> { Attrs::new() - .color(style.color.unwrap_or_default().into()) - .style(style.style.unwrap_or_default().into()) - .weight(style.weight.unwrap_or_default().into()) + .color(self.color.unwrap_or_default().resolve(palette).into()) + .style(self.style.unwrap_or_default().into()) + .weight(self.weight.unwrap_or_default().into()) } } diff --git a/wgui/src/theme.rs b/wgui/src/theme.rs index 6d9c530a..a5ec82e1 100644 --- a/wgui/src/theme.rs +++ b/wgui/src/theme.rs @@ -1,16 +1,5 @@ -use crate::drawing; - #[derive(Clone)] pub struct WguiTheme { - pub dark_mode: bool, - pub text_color: drawing::Color, - pub button_color: drawing::Color, - pub accent_color: drawing::Color, - pub danger_color: drawing::Color, - pub faded_color: drawing::Color, - pub bg_color: drawing::Color, - pub editbox_color: drawing::Color, - pub translucent_alpha: f32, pub animation_mult: f32, pub rounding_mult: f32, pub gradient_intensity: f32, // currently used for buttons @@ -19,15 +8,6 @@ pub struct WguiTheme { impl Default for WguiTheme { fn default() -> Self { Self { - dark_mode: true, - text_color: drawing::Color::new(1.0, 1.0, 1.0, 1.0), - button_color: drawing::Color::new(1.0, 1.0, 1.0, 0.02), - accent_color: drawing::Color::new(0.13, 0.68, 1.0, 1.0), - danger_color: drawing::Color::new(0.9, 0.0, 0.0, 1.0), - faded_color: drawing::Color::new(0.67, 0.74, 0.80, 1.0), - bg_color: drawing::Color::new(0.0, 0.07, 0.1, 0.75), - editbox_color: drawing::Color::new(0.15, 0.25, 0.35, 0.95), - translucent_alpha: 0.5, animation_mult: 1.0, rounding_mult: 1.0, gradient_intensity: 0.3, diff --git a/wgui/src/widget/custom_draw.rs b/wgui/src/widget/custom_draw.rs index e262bca4..45d1a527 100644 --- a/wgui/src/widget/custom_draw.rs +++ b/wgui/src/widget/custom_draw.rs @@ -2,6 +2,7 @@ use slotmap::Key; use crate::{ drawing::{self}, + globals::Globals, layout::WidgetID, stack, widget::WidgetStateFlags, @@ -59,7 +60,7 @@ impl WidgetObj for WidgetCustomDraw { super::WidgetType::Rectangle } - fn debug_print(&self) -> String { + fn debug_print(&self, _globals: &Globals) -> String { String::default() } } diff --git a/wgui/src/widget/div.rs b/wgui/src/widget/div.rs index 6dc5ffb9..0da1546c 100644 --- a/wgui/src/widget/div.rs +++ b/wgui/src/widget/div.rs @@ -1,6 +1,6 @@ use slotmap::Key; -use crate::{layout::WidgetID, widget::WidgetStateFlags}; +use crate::{globals::Globals, layout::WidgetID, widget::WidgetStateFlags}; use super::{WidgetObj, WidgetState}; @@ -31,7 +31,7 @@ impl WidgetObj for WidgetDiv { super::WidgetType::Div } - fn debug_print(&self) -> String { + fn debug_print(&self, _globals: &Globals) -> String { String::default() } } diff --git a/wgui/src/widget/image.rs b/wgui/src/widget/image.rs index 7f6525d6..85d6c781 100644 --- a/wgui/src/widget/image.rs +++ b/wgui/src/widget/image.rs @@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use slotmap::Key; use crate::{ + color::WguiColor, drawing::{self, ImagePrimitive, PrimitiveExtent}, event::EventAlterables, globals::Globals, @@ -20,7 +21,7 @@ pub struct WidgetImageParams { pub glyph_data: Option, pub border: f32, - pub border_color: drawing::Color, + pub border_color: WguiColor, pub round: WLength, } @@ -84,7 +85,7 @@ impl WidgetObj for WidgetImage { content_key: self.content_key, skip_cache: self.dirty, border: self.params.border, - border_color: self.params.border_color, + border_color: self.params.border_color.resolve(&state.globals.palette), round_units, }, )); @@ -112,7 +113,7 @@ impl WidgetObj for WidgetImage { super::WidgetType::Sprite } - fn debug_print(&self) -> String { + fn debug_print(&self, _globals: &Globals) -> String { String::default() } } diff --git a/wgui/src/widget/label.rs b/wgui/src/widget/label.rs index 9b0d68b9..3cbd8c6e 100644 --- a/wgui/src/widget/label.rs +++ b/wgui/src/widget/label.rs @@ -5,13 +5,13 @@ use slotmap::Key; use taffy::AvailableSpace; use crate::{ + color::{WguiColor, WguiColorName, WguiColorPalette}, drawing::{self, PrimitiveExtent}, event::CallbackDataCommon, globals::Globals, i18n::Translation, layout::{LayoutState, WidgetID}, renderer_vk::text::TextStyle, - theme::WguiTheme, widget::WidgetStateFlags, }; @@ -32,16 +32,16 @@ pub struct WidgetLabel { impl WidgetLabel { pub fn create(state: &mut LayoutState, params: WidgetLabelParams) -> WidgetState { - WidgetLabel::create_ex(&mut state.globals.get(), &state.theme, params) + WidgetLabel::create_ex(&mut state.globals.get(), params) } - pub fn create_ex(globals: &mut Globals, theme: &WguiTheme, mut params: WidgetLabelParams) -> WidgetState { + pub fn create_ex(globals: &mut Globals, mut params: WidgetLabelParams) -> WidgetState { if params.style.color.is_none() { - params.style.color = Some(theme.text_color); + params.style.color = Some(WguiColorName::OnPrimary.into()); } let metrics = Metrics::from(¶ms.style); - let attrs = Attrs::from(¶ms.style); + let attrs = params.style.to_attrs(&globals.palette); let wrap = Wrap::from(¶ms.style); let mut buffer = Buffer::new_empty(metrics); @@ -86,7 +86,7 @@ impl WidgetLabel { } self.params.content = translation; - let attrs = Attrs::from(&self.params.style); + let attrs = self.params.style.to_attrs(&globals.palette); let text = self.params.content.generate(&mut globals.i18n_builtin); @@ -101,8 +101,8 @@ impl WidgetLabel { true } - fn update_attrs(&mut self) { - let attrs = Attrs::from(&self.params.style); + fn update_attrs(&mut self, palette: &WguiColorPalette) { + let attrs = self.params.style.to_attrs(palette); for line in &mut self.buffer.borrow_mut().lines { line.set_attrs_list(AttrsList::new(&attrs)); } @@ -117,10 +117,10 @@ impl WidgetLabel { } } - pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: drawing::Color, apply_to_existing_text: bool) { + pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: WguiColor, apply_to_existing_text: bool) { self.params.style.color = Some(color); if apply_to_existing_text { - self.update_attrs(); + self.update_attrs(&common.globals().palette); common.mark_widget_dirty(self.id); } } @@ -183,9 +183,9 @@ impl WidgetObj for WidgetLabel { super::WidgetType::Label } - fn debug_print(&self) -> String { + fn debug_print(&self, globals: &Globals) -> String { let color = if let Some(color) = self.params.style.color { - format!("[color: {}]", color.debug_ansi_block()) + format!("[color: {}]", color.resolve(&globals.palette).debug_ansi_block()) } else { String::default() }; diff --git a/wgui/src/widget/mod.rs b/wgui/src/widget/mod.rs index 93d01979..f03241cf 100644 --- a/wgui/src/widget/mod.rs +++ b/wgui/src/widget/mod.rs @@ -187,7 +187,7 @@ pub trait WidgetObj: AnyTrait { fn get_id(&self) -> WidgetID; fn set_id(&mut self, id: WidgetID); // always set at insertion fn get_type(&self) -> WidgetType; - fn debug_print(&self) -> String; + fn debug_print(&self, _globals: &Globals) -> String; fn draw(&mut self, state: &mut DrawState, params: &DrawParams); diff --git a/wgui/src/widget/rectangle.rs b/wgui/src/widget/rectangle.rs index b5a14a26..3c2e5be6 100644 --- a/wgui/src/widget/rectangle.rs +++ b/wgui/src/widget/rectangle.rs @@ -1,8 +1,10 @@ use slotmap::Key; use crate::{ + color::WguiColor, drawing::{self, GradientMode, PrimitiveExtent}, event::CallbackDataCommon, + globals::Globals, layout::WidgetID, widget::{WidgetStateFlags, util::WLength}, }; @@ -11,12 +13,12 @@ use super::{WidgetObj, WidgetState}; #[derive(Debug, Default)] pub struct WidgetRectangleParams { - pub color: drawing::Color, - pub color2: drawing::Color, + pub color: WguiColor, + pub color2: WguiColor, pub gradient: GradientMode, pub border: f32, - pub border_color: drawing::Color, + pub border_color: WguiColor, pub round: WLength, } @@ -36,7 +38,8 @@ impl WidgetRectangle { }), ) } - pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: drawing::Color) { + + pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: WguiColor) { self.params.color = color; common.mark_widget_dirty(self.id); } @@ -51,17 +54,21 @@ impl WidgetObj for WidgetRectangle { WLength::Percent(percent) => (f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8, }; + let color = self.params.color.resolve(&state.globals.palette); + let color2 = self.params.color2.resolve(&state.globals.palette); + let border_color = self.params.border_color.resolve(&state.globals.palette); + state.primitives.push(drawing::RenderPrimitive::Rectangle( PrimitiveExtent { boundary, transform: state.transform_stack.get().transform, }, drawing::Rectangle { - color: self.params.color, - color2: self.params.color2, + color, + color2, + border_color, gradient: self.params.gradient, border: self.params.border, - border_color: self.params.border_color, round_units, }, )); @@ -79,11 +86,11 @@ impl WidgetObj for WidgetRectangle { super::WidgetType::Rectangle } - fn debug_print(&self) -> String { + fn debug_print(&self, globals: &Globals) -> String { format!( "[color: {}][color2: {}][gradient: {:?}]", - self.params.color.debug_ansi_block(), - self.params.color2.debug_ansi_block(), + self.params.color.resolve(&globals.palette).debug_ansi_block(), + self.params.color2.resolve(&globals.palette).debug_ansi_block(), self.params.gradient, ) } diff --git a/wgui/src/widget/sprite.rs b/wgui/src/widget/sprite.rs index f9d3366f..126f3e07 100644 --- a/wgui/src/widget/sprite.rs +++ b/wgui/src/widget/sprite.rs @@ -4,6 +4,7 @@ use cosmic_text::{Attrs, Buffer, Color, Shaping, Weight}; use slotmap::Key; use crate::{ + color::WguiColor, drawing::{self, PrimitiveExtent}, event::{CallbackDataCommon, EventAlterables}, globals::Globals, @@ -20,7 +21,7 @@ use super::{WidgetObj, WidgetState}; #[derive(Debug, Default)] pub struct WidgetSpriteParams { pub glyph_data: Option, - pub color: Option, + pub color: Option, } #[derive(Debug, Default)] @@ -40,12 +41,12 @@ impl WidgetSprite { ) } - pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: drawing::Color) { + pub fn set_color(&mut self, common: &mut CallbackDataCommon, color: WguiColor) { self.params.color = Some(color); common.mark_widget_dirty(self.id); } - pub const fn get_color(&self) -> Option { + pub const fn get_color(&self) -> Option { self.params.color } @@ -74,12 +75,9 @@ impl WidgetObj for WidgetSprite { top: 0.0, width: boundary.size.x, height: boundary.size.y, - color: Some( - self - .params - .color - .map_or(cosmic_text::Color::rgb(255, 255, 255), Into::into), - ), + color: Some(self.params.color.map_or(cosmic_text::Color::rgb(255, 255, 255), |c| { + c.resolve(&state.globals.palette).into() + })), snap_to_physical_pixel: true, }; @@ -135,7 +133,7 @@ impl WidgetObj for WidgetSprite { super::WidgetType::Sprite } - fn debug_print(&self) -> String { + fn debug_print(&self, _globals: &Globals) -> String { String::default() } } diff --git a/wgui/src/windowing/window.rs b/wgui/src/windowing/window.rs index 1dc084e5..456ccf04 100644 --- a/wgui/src/windowing/window.rs +++ b/wgui/src/windowing/window.rs @@ -189,7 +189,7 @@ impl WguiWindow { AnimationEasing::OutQuad, Box::new(|common, data| { let rect = data.obj.get_as_mut::().unwrap() /* should always succeed */; - rect.params.color = drawing::Color::new(0.0, 0.0, 0.0, data.pos * 0.3); + rect.params.color = drawing::Color::new(0.0, 0.0, 0.0, data.pos * 0.3).into(); common.alterables.mark_redraw(); }), ));