wgui: separate globals and themes

This commit is contained in:
Aleksander 2026-03-05 19:28:42 +01:00
parent a83af3d833
commit cb899235b4
33 changed files with 257 additions and 317 deletions

View File

@ -12,6 +12,7 @@ use wgui::{
parser::{Fetchable, ParseDocumentParams, ParserState},
renderer_vk::text::custom_glyph::CustomGlyphData,
task::Tasks,
theme::WguiTheme,
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
};
@ -86,6 +87,7 @@ pub struct InitParams<'a, T> {
pub interface: BoxDashInterface<T>,
pub lang_provider: &'a WayVRLangProvider,
pub has_monado: bool,
pub theme: Rc<WguiTheme>,
}
#[derive(Clone)]
@ -106,12 +108,11 @@ pub enum FrontendTask {
RecenterPlayspace,
PushToast(Translation),
PlaySound(SoundType),
UpdateWguiDefaultsFromConfig,
HideDashboard,
}
impl<T: 'static> Frontend<T> {
pub fn new(mut params: InitParams<T>, data: &mut T) -> anyhow::Result<Frontend<T>> {
pub fn new(params: InitParams<T>) -> anyhow::Result<Frontend<T>> {
let mut assets = Box::new(assets::Asset {});
let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?;
@ -121,7 +122,6 @@ impl<T: 'static> Frontend<T> {
let globals = WguiGlobals::new(
assets,
params.lang_provider,
wgui::globals::Defaults::default(),
&WguiFontConfig {
binaries: vec![&font_binary_regular, &font_binary_bold, &font_binary_light],
family_name_sans_serif: "Quicksand",
@ -131,15 +131,16 @@ impl<T: 'static> Frontend<T> {
PathBuf::new(), //FIXME: pass from somewhere else
)?;
Frontend::update_defaults_from_config(&globals, &mut params.interface, data);
let (layout, state) = wgui::parser::new_layout_from_assets(
&ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/dashboard.xml"),
extra: Default::default(),
},
&LayoutParams { resize_to_parent: true },
LayoutParams {
resize_to_parent: true,
theme: params.theme,
},
)?;
let id_popup_manager = state.get_widget_id("popup_manager")?;
@ -185,7 +186,6 @@ impl<T: 'static> Frontend<T> {
// init some things first
frontend.tasks.push(FrontendTask::RefreshBackground);
frontend.tasks.push(FrontendTask::RefreshClock);
frontend.tasks.push(FrontendTask::UpdateWguiDefaultsFromConfig);
Frontend::register_widgets(&mut frontend)?;
@ -196,16 +196,6 @@ impl<T: 'static> Frontend<T> {
self.sounds_to_play.push(sound_type);
}
fn update_defaults_from_config(globals: &WguiGlobals, interface: &mut BoxDashInterface<T>, data: &mut T) {
let config = interface.general_config(data);
let mut globals = globals.get();
let defaults = &mut globals.defaults;
defaults.animation_mult = 1.0 / config.ui_animation_speed;
defaults.gradient_intensity = config.ui_gradient_intensity;
}
fn play_sound(&mut self, audio_system: &mut audio::AudioSystem, sound_type: SoundType) -> anyhow::Result<()> {
let mut assets = self.globals.assets_builtin();
@ -273,7 +263,7 @@ impl<T: 'static> Frontend<T> {
{
// always 30 times per second
while self.timestep.on_tick() {
self.toast_manager.tick(&self.globals, &mut self.layout)?;
self.toast_manager.tick(&mut self.layout)?;
}
}
@ -374,9 +364,6 @@ impl<T: 'static> Frontend<T> {
FrontendTask::PushToast(content) => self.toast_manager.push(content),
FrontendTask::PlaySound(sound_type) => self.queue_play_sound(sound_type),
FrontendTask::HideDashboard => self.action_hide_dashboard(params.data),
FrontendTask::UpdateWguiDefaultsFromConfig => {
Frontend::update_defaults_from_config(&self.globals, &mut self.interface, params.data)
}
};
Ok(())
}

View File

@ -163,7 +163,7 @@ impl<T> Tab<T> for TabSettings<T> {
}
Task::SettingUpdated(setting) => match setting {
SettingType::UiAnimationSpeed | SettingType::UiGradientIntensity | SettingType::UiRoundMultiplier => {
frontend.tasks.push(FrontendTask::UpdateWguiDefaultsFromConfig);
// todo: currently, wayvr restart is required to apply these changes (WguiTheme is Rc)
}
_ => { /* do nothing */ }
},
@ -426,16 +426,17 @@ impl SettingType {
}
fn requires_restart(self) -> bool {
match self {
matches!(
self,
Self::UiAnimationSpeed
| Self::UiRoundMultiplier
| Self::UprightScreenFix
| Self::DoubleCursorFix
| Self::ScreenRenderDown
| Self::Language
| Self::CaptureMethod => true,
_ => false,
}
| Self::UiRoundMultiplier
| Self::UiGradientIntensity
| Self::UprightScreenFix
| Self::DoubleCursorFix
| Self::ScreenRenderDown
| Self::Language
| Self::CaptureMethod
)
}
fn get_frontend_task(self) -> Option<FrontendTask> {
@ -466,7 +467,7 @@ fn horiz_cell(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<WidgetID>
fn mount_requires_restart(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<()> {
let content = Translation::from_translation_key("APP_SETTINGS.REQUIRES_RESTART");
let label = WidgetLabel::create(
&mut layout.state.globals.get(),
&mut layout.state,
WidgetLabelParams {
content,
style: TextStyle {

View File

@ -5,7 +5,6 @@ use wgui::{
animation::{Animation, AnimationEasing},
components::tooltip::{TOOLTIP_BORDER_COLOR, TOOLTIP_COLOR},
drawing::Color,
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, LayoutTask, LayoutTasks, WidgetID},
renderer_vk::{
@ -61,15 +60,7 @@ impl ToastManager {
}
}
fn mount_toast(
&self,
globals: &WguiGlobals,
layout: &mut Layout,
state: &mut State,
content: Translation,
) -> anyhow::Result<()> {
let mut globals = globals.get();
fn mount_toast(&self, layout: &mut Layout, state: &mut State, content: Translation) -> anyhow::Result<()> {
let (root, _) = layout.add_topmost_child(
WidgetDiv::create(),
taffy::Style {
@ -110,27 +101,24 @@ impl ToastManager {
},
)?;
let (label, _) = layout.add_child(
rect.id,
WidgetLabel::create(
&mut globals,
WidgetLabelParams {
content,
style: TextStyle {
weight: Some(FontWeight::Bold),
align: Some(HorizontalAlign::Center),
wrap: true,
..Default::default()
},
let label = WidgetLabel::create(
&mut layout.state,
WidgetLabelParams {
content,
style: TextStyle {
weight: Some(FontWeight::Bold),
align: Some(HorizontalAlign::Center),
wrap: true,
..Default::default()
},
),
taffy::Style { ..Default::default() },
)?;
},
);
let (label, _) = layout.add_child(rect.id, label, taffy::Style { ..Default::default() })?;
// show-up animation
layout.animations.add(Animation::new(
rect.id,
(TOAST_DURATION_TICKS as f32 * globals.defaults.animation_mult) as u32,
(TOAST_DURATION_TICKS as f32 * layout.state.theme.animation_mult) as u32,
AnimationEasing::Linear,
Box::new(move |common, data| {
let pos_showup = AnimationEasing::OutQuint.interpolate((data.pos * 4.0).min(1.0));
@ -161,7 +149,7 @@ impl ToastManager {
Ok(())
}
pub fn tick(&mut self, globals: &WguiGlobals, layout: &mut Layout) -> anyhow::Result<()> {
pub fn tick(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
let mut state = self.state.borrow_mut();
if state.timeout > 0 {
state.timeout -= 1;
@ -176,7 +164,7 @@ impl ToastManager {
state.timeout = TOAST_DURATION_TICKS;
// mount next
if let Some(content) = state.queue.pop_front() {
self.mount_toast(globals, layout, &mut state, content)?;
self.mount_toast(layout, &mut state, content)?;
}
}

View File

@ -8,7 +8,7 @@ use wgui::{
#[allow(dead_code)]
pub fn create_label(layout: &mut Layout, parent: WidgetID, content: Translation) -> anyhow::Result<()> {
let label = WidgetLabel::create(
&mut layout.state.globals.get(),
&mut layout.state,
WidgetLabelParams {
content,
style: TextStyle {

View File

@ -110,8 +110,7 @@ struct MultiSelectorParams<'a> {
}
fn mount_multi_selector(params: MultiSelectorParams) -> anyhow::Result<()> {
let globals = params.ess.layout.state.globals.clone();
let accent_color = globals.defaults().accent_color;
let accent_color = params.ess.layout.state.theme.accent_color;
for cell in params.cells {
let highlighted = cell.key == params.def_cell;
@ -654,8 +653,6 @@ impl View {
}
fn update_button_highlights(&self, layout: &mut Layout) -> anyhow::Result<()> {
let defaults = self.globals.defaults();
let mut c = layout.start_common();
let mut common = c.common();
@ -667,14 +664,12 @@ impl View {
};
let mut perform = |btn_num: u8, btn: &Rc<ComponentButton>| {
btn.set_color(
&mut common,
if num == btn_num {
defaults.accent_color
} else {
defaults.button_color
},
);
let color = if num == btn_num {
common.state.theme.accent_color
} else {
common.state.theme.button_color
};
btn.set_color(&mut common, color);
};
perform(0, &self.btn_sinks);

View File

@ -98,15 +98,9 @@ impl View {
Ok(())
}
fn mount_placeholder_text(
&self,
globals: &WguiGlobals,
layout: &mut Layout,
parent: WidgetID,
text: &str,
) -> anyhow::Result<()> {
fn mount_placeholder_text(&self, layout: &mut Layout, parent: WidgetID, text: &str) -> anyhow::Result<()> {
let label = WidgetLabel::create(
&mut globals.get(),
&mut layout.state,
WidgetLabelParams {
content: Translation::from_raw_text(text),
style: TextStyle {
@ -153,7 +147,7 @@ impl View {
// mount placeholder
let img = view_common.get_placeholder_image()?.clone();
self.mount_image(layout, &img)?;
self.mount_placeholder_text(&view_common.globals, layout, self.id_image_parent, &self.app_name)?;
self.mount_placeholder_text(layout, self.id_image_parent, &self.app_name)?;
} else {
// mount image
let path = format!("app:{:?}", self.app_id);

View File

@ -256,17 +256,14 @@ impl View {
)?;
if let Some(text) = text.take() {
layout.add_child(
self.id_list_parent,
WidgetLabel::create(
&mut self.globals.get(),
WidgetLabelParams {
content: text,
..Default::default()
},
),
Default::default(),
)?;
let label = WidgetLabel::create(
&mut layout.state,
WidgetLabelParams {
content: text,
..Default::default()
},
);
layout.add_child(self.id_list_parent, label, Default::default())?;
}
Ok(())

View File

@ -34,7 +34,6 @@ impl TestbedAny {
let globals = WguiGlobals::new(
assets,
&lang_provider,
wgui::globals::Defaults::default(),
&WguiFontConfig::default(),
PathBuf::new(), // cwd
)?;
@ -45,7 +44,7 @@ impl TestbedAny {
path,
extra: Default::default(),
},
&LayoutParams::default(),
LayoutParams::default(),
)?;
Ok(Self { layout, state })
}

View File

@ -1,6 +1,8 @@
use std::rc::Rc;
use crate::testbed::{Testbed, TestbedUpdateParams};
use dash_frontend::frontend::{self, FrontendUpdateParams};
use wgui::layout::Layout;
use wgui::{layout::Layout, theme::WguiTheme};
use wlx_common::{dash_interface_emulated::DashInterfaceEmulated, locale::WayVRLangProvider};
pub struct TestbedDashboard {
@ -12,14 +14,12 @@ impl TestbedDashboard {
let interface = DashInterfaceEmulated::new();
let lang_provider = WayVRLangProvider::default();
let frontend = frontend::Frontend::new(
frontend::InitParams {
interface: Box::new(interface),
has_monado: true,
lang_provider: &lang_provider,
},
&mut (),
)?;
let frontend = frontend::Frontend::new(frontend::InitParams {
interface: Box::new(interface),
has_monado: true,
lang_provider: &lang_provider,
theme: Rc::new(WguiTheme::default()),
})?;
Ok(Self { frontend })
}
}

View File

@ -21,6 +21,7 @@ use wgui::{
parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams, ParserState},
taffy::{self, prelude::length},
task::Tasks,
theme::WguiTheme,
widget::{div::WidgetDiv, label::WidgetLabel, rectangle::WidgetRectangle},
windowing::{
context_menu::{self, TickResult},
@ -91,7 +92,6 @@ impl TestbedGeneric {
let globals = WguiGlobals::new(
assets,
&lang_provider,
wgui::globals::Defaults::default(),
&WguiFontConfig::default(),
PathBuf::new(), // cwd
)?;
@ -125,8 +125,9 @@ impl TestbedGeneric {
let (layout, parser_state) = wgui::parser::new_layout_from_assets(
&TestbedGeneric::doc_params(&globals, extra),
&LayoutParams {
LayoutParams {
resize_to_parent: true,
theme: Rc::new(WguiTheme::default()),
},
)?;

View File

@ -147,8 +147,9 @@ impl<S: 'static> GuiPanel<S> {
let (mut layout, mut parser_state) = wgui::parser::new_layout_from_assets(
&doc_params,
&LayoutParams {
LayoutParams {
resize_to_parent: params.resize_to_parent,
theme: app.wgui_theme.clone(),
},
)?;

View File

@ -77,14 +77,12 @@ impl DashFrontend {
let _ = interface.process_launch(app, false, p)?;
}
let frontend = frontend::Frontend::new(
frontend::InitParams {
interface: Box::new(interface),
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
},
app,
)?;
let frontend = frontend::Frontend::new(frontend::InitParams {
interface: Box::new(interface),
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
theme: app.wgui_theme.clone(),
})?;
frontend
.tasks

View File

@ -11,7 +11,7 @@ use wgui::{
widget::rectangle::WidgetRectangle,
};
use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel, state::AppState};
use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel};
#[derive(Default)]
pub(super) struct InteractLockHandler {
@ -53,21 +53,18 @@ impl InteractLockHandler {
button.set_sticky_state(common, !interactable);
}
let globals = common.state.globals.get();
if interactable {
set_anim_color(&mut rect, 0.0, self.color, globals.defaults.danger_color);
set_anim_color(&mut rect, 0.0, self.color, common.state.theme.danger_color);
} else {
set_anim_color(&mut rect, 0.2, self.color, globals.defaults.danger_color);
set_anim_color(&mut rect, 0.2, self.color, common.state.theme.danger_color);
}
}
pub fn toggle(
&mut self,
common: &mut CallbackDataCommon,
app: &mut AppState,
anim_mult: f32,
) -> Box<ModifyOverlayTask> {
let defaults = app.wgui_globals.defaults().clone();
let rect_color = self.color;
self.interactable = !self.interactable;
@ -86,7 +83,7 @@ impl InteractLockHandler {
rect,
0.2 - (data.pos * 0.2),
rect_color,
defaults.danger_color,
common.state.theme.danger_color,
);
common.alterables.mark_redraw();
}),
@ -98,7 +95,12 @@ impl InteractLockHandler {
AnimationEasing::OutBack,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
set_anim_color(rect, data.pos * 0.2, rect_color, defaults.danger_color);
set_anim_color(
rect,
data.pos * 0.2,
rect_color,
common.state.theme.danger_color,
);
common.alterables.mark_redraw();
}),
)

View File

@ -272,7 +272,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
mouse: SpriteTabHandler::default(),
};
let anim_mult = app.wgui_globals.defaults().animation_mult;
let anim_mult = app.wgui_theme.animation_mult;
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
let Ok(button) =
@ -302,7 +302,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
}
let sel = OverlaySelector::Id(*state.id.borrow());
let task = state.lock.toggle(common, app, anim_mult);
let task = state.lock.toggle(common, anim_mult);
app.tasks
.enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task)));
Ok(EventResult::Consumed)

View File

@ -53,11 +53,9 @@ pub(super) fn create_keyboard_panel(
let doc_params = new_doc_params(&mut panel);
let globals = app.wgui_globals.clone();
let (accent_color, anim_mult) = {
let def = globals.defaults();
(def.accent_color, def.animation_mult)
let theme = &app.wgui_theme;
(theme.accent_color, theme.animation_mult)
};
let root = panel

View File

@ -1,8 +1,10 @@
use glam::Affine3A;
use idmap::IdMap;
use smallvec::{SmallVec, smallvec};
use std::rc::Rc;
use std::sync::Arc;
use wgui::log::LogErr;
use wgui::theme::WguiTheme;
use wgui::{
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
renderer_vk::context::SharedContext as WSharedContext,
@ -48,6 +50,7 @@ pub struct AppState {
pub anchor_grabbed: bool,
pub wgui_globals: WguiGlobals,
pub wgui_theme: Rc<WguiTheme>,
pub dbus: DbusConnector,
@ -90,7 +93,7 @@ impl AppState {
let osc_sender = crate::subsystem::osc::OscSender::new(session.config.osc_out_port).ok();
let wgui_shared = WSharedContext::new(gfx.clone())?;
let theme = session.config.theme_path.clone();
let theme_path = session.config.theme_path.clone();
let mut audio_sample_player = audio::SamplePlayer::new();
audio_sample_player.register_sample(
@ -112,7 +115,7 @@ impl AppState {
let mut assets = Box::new(gui::asset::GuiAsset {});
audio_sample_player.register_wgui_samples(assets.as_mut())?;
let mut defaults = wgui::globals::Defaults::default();
let mut theme = WguiTheme::default();
{
#[allow(clippy::ref_option)]
@ -122,15 +125,15 @@ impl AppState {
}
}
apply_color(&mut defaults.text_color, &session.config.color_text);
apply_color(&mut defaults.accent_color, &session.config.color_accent);
apply_color(&mut defaults.danger_color, &session.config.color_danger);
apply_color(&mut defaults.faded_color, &session.config.color_faded);
apply_color(&mut defaults.bg_color, &session.config.color_background);
apply_color(&mut theme.text_color, &session.config.color_text);
apply_color(&mut theme.accent_color, &session.config.color_accent);
apply_color(&mut theme.danger_color, &session.config.color_danger);
apply_color(&mut theme.faded_color, &session.config.color_faded);
apply_color(&mut theme.bg_color, &session.config.color_background);
}
defaults.animation_mult = 1. / session.config.ui_animation_speed;
defaults.rounding_mult = session.config.ui_round_multiplier;
theme.animation_mult = 1. / session.config.ui_animation_speed;
theme.rounding_mult = session.config.ui_round_multiplier;
let dbus = DbusConnector::default();
@ -157,10 +160,10 @@ impl AppState {
wgui_globals: WguiGlobals::new(
assets,
&lang_provider,
defaults,
&WguiFontConfig::default(),
get_config_file_path(&theme),
get_config_file_path(&theme_path),
)?,
wgui_theme: Rc::new(theme),
dbus,
xr_backend,
ipc_server,

View File

@ -157,7 +157,7 @@ impl ComponentButton {
}
pub fn set_color(&self, common: &mut CallbackDataCommon, color: Color) {
let gradient_intensity = common.defaults().gradient_intensity;
let gradient_intensity = common.state.theme.gradient_intensity;
let Some(mut rect) = common.state.widgets.get_as::<WidgetRectangle>(self.data.id_rect) else {
return;
@ -194,8 +194,8 @@ impl ComponentButton {
}
let (anim_mult, gradient_intensity) = {
let defaults = common.state.globals.defaults();
(defaults.animation_mult, defaults.gradient_intensity)
let theme = &common.state.theme;
(theme.animation_mult, theme.gradient_intensity)
};
let anim_ticks = if sticky_down { 5. } else { 10. };
@ -247,7 +247,7 @@ fn anim_hover(
let bgcolor = init_color.lerp(&colors.hover_color, mult);
let gradient_intensity = common.globals().defaults.gradient_intensity;
let gradient_intensity = common.state.theme.gradient_intensity;
//let t = Mat4::from_scale(Vec3::splat(1.0 + pos * 0.5)) * Mat4::from_rotation_z(pos * 1.0);
@ -416,8 +416,8 @@ fn register_event_mouse_release(
}
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
let globals = ess.layout.state.globals.clone();
let mut style = params.style;
let theme = &ess.layout.state.theme;
// force-override style
style.align_items = Some(AlignItems::Center);
@ -431,7 +431,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let color = if let Some(color) = params.color {
color
} else {
globals.defaults().button_color
theme.button_color
};
let border_color = if let Some(border_color) = params.border_color {
@ -452,7 +452,12 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
Color::new(color.r + 0.5, color.g + 0.5, color.g + 0.5, color.a + 0.5)
};
let gradient_intensity = ess.layout.state.globals.defaults().gradient_intensity;
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
};
let (root, _) = ess.layout.add_child(
ess.parent,
@ -469,15 +474,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let id_rect = root.id;
let light_text = {
let mult = if globals.defaults().dark_mode {
color.a
} else {
1.0 - color.a
};
(color.r + color.g + color.b) * mult < 1.5
};
let default_margin = taffy::Rect {
top: length(4.0),
bottom: length(4.0),
@ -487,7 +483,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
if let Some(sprite_path) = params.sprite_src {
let sprite = WidgetSprite::create(WidgetSpriteParams {
glyph_data: Some(CustomGlyphData::from_assets(&globals, sprite_path)?),
glyph_data: Some(CustomGlyphData::from_assets(&ess.layout.state.globals, sprite_path)?),
..Default::default()
});
@ -506,23 +502,25 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
}
let id_label = if let Some(content) = params.text {
let widget_label = WidgetLabel::create(
&mut ess.layout.state,
WidgetLabelParams {
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
},
},
);
let (label, _node_label) = ess.layout.add_child(
id_rect,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
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
},
},
),
widget_label,
taffy::Style {
margin: default_margin,
..Default::default()
@ -558,7 +556,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
id: root.id,
lhandles: {
let listeners = &mut root.widget.state().event_listeners;
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
let anim_mult = ess.layout.state.theme.animation_mult;
vec![
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
register_event_mouse_leave(state.clone(), listeners, anim_mult),

View File

@ -343,8 +343,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
(WLength::Units(5.0), WLength::Units(8.0))
};
let globals = ess.layout.state.globals.clone();
let (root, _) = ess.layout.add_child(
ess.parent,
WidgetRectangle::create(WidgetRectangleParams {
@ -397,20 +395,17 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
},
)?;
let (label, _node_label) = ess.layout.add_child(
id_container,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
content: params.text,
style: TextStyle {
weight: Some(FontWeight::Bold),
..Default::default()
},
let widget_label = WidgetLabel::create(
&mut ess.layout.state,
WidgetLabelParams {
content: params.text,
style: TextStyle {
weight: Some(FontWeight::Bold),
..Default::default()
},
),
Default::default(),
)?;
},
);
let (label, _node_label) = ess.layout.add_child(id_container, widget_label, Default::default())?;
let data = Rc::new(Data {
id_container,
@ -433,7 +428,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
id: root.id,
lhandles: {
let listeners = &mut root.widget.state().event_listeners;
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
let anim_mult = ess.layout.state.theme.animation_mult;
vec![
register_event_mouse_enter(state.clone(), listeners, params.tooltip, anim_mult),
register_event_mouse_leave(state.clone(), listeners, anim_mult),

View File

@ -99,11 +99,10 @@ fn anim_bottom_rect(
}
fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State) -> Option<()> {
let defaults = common.defaults();
let editbox_color = defaults.editbox_color;
let anim_mult = defaults.animation_mult;
let accent_color = defaults.accent_color;
drop(defaults);
let theme = &common.state.theme;
let editbox_color = theme.editbox_color;
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))
@ -279,10 +278,7 @@ pub fn construct(
ess: &mut ConstructEssentials,
mut params: Params,
) -> anyhow::Result<(WidgetPair, Rc<ComponentEditBox>)> {
let globals = ess.layout.state.globals.clone();
let defaults = globals.defaults();
let text_color = defaults.text_color;
drop(defaults);
let text_color = ess.layout.state.theme.text_color;
if params.style.size.width.is_auto() {
params.style.size.width = length(128.0);
@ -345,22 +341,23 @@ pub fn construct(
},
)?;
let widget_label = WidgetLabel::create(
&mut ess.layout.state,
WidgetLabelParams {
content: Translation::from_raw_text(&params.initial_text),
style: TextStyle {
shadow: Some(TextShadow {
x: 1.0,
y: 1.0,
color: Color::new(0.0, 0.0, 0.0, 1.0),
}),
..Default::default()
},
},
);
let (label, _node_label) = ess.layout.add_child(
label_parent.id,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
content: Translation::from_raw_text(&params.initial_text),
style: TextStyle {
shadow: Some(TextShadow {
x: 1.0,
y: 1.0,
color: Color::new(0.0, 0.0, 0.0, 1.0),
}),
..Default::default()
},
},
),
widget_label,
taffy::Style {
position: taffy::Position::Relative,
..Default::default()

View File

@ -498,26 +498,20 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
active_tooltip: None,
};
let globals = ess.layout.state.globals.clone();
let slider_text: Option<(WidgetPair, taffy::NodeId)> = if params.show_value {
let pair = ess.layout.add_child(
slider_handle.id,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
content: Translation::default(),
style: TextStyle {
color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), // always black
weight: Some(FontWeight::Bold),
align: Some(HorizontalAlign::Center),
..Default::default()
},
let label = WidgetLabel::create(
&mut ess.layout.state,
WidgetLabelParams {
content: Translation::default(),
style: TextStyle {
color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), // always black
weight: Some(FontWeight::Bold),
align: Some(HorizontalAlign::Center),
..Default::default()
},
),
Default::default(),
)?;
Some(pair)
},
);
Some(ess.layout.add_child(slider_handle.id, label, Default::default())?)
} else {
None
};
@ -535,7 +529,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
id: root.id,
lhandles: {
let listeners = &mut root.widget.state().event_listeners;
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
let anim_mult = ess.layout.state.theme.animation_mult;
vec![
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
register_event_mouse_leave(data.clone(), state.clone(), listeners, anim_mult),

View File

@ -67,8 +67,8 @@ impl ComponentTrait for ComponentTabs {
impl State {
fn select_entry(&mut self, common: &mut CallbackDataCommon, name: &Rc<str>) {
let (color_accent, color_button) = {
let def = common.state.globals.defaults();
(def.accent_color, def.button_color)
let theme = &common.state.theme;
(theme.accent_color, theme.button_color)
};
for entry in &self.mounted_entries {

View File

@ -163,8 +163,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
),
};
let globals = ess.layout.state.globals.clone();
let (div, _) = ess.layout.add_child(
ess.parent,
WidgetDiv::create(),
@ -211,20 +209,17 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
},
)?;
let (label, _) = ess.layout.add_child(
rect.id,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
content: params.info.text,
style: TextStyle {
weight: Some(FontWeight::Bold),
..Default::default()
},
let label = WidgetLabel::create(
&mut ess.layout.state,
WidgetLabelParams {
content: params.info.text,
style: TextStyle {
weight: Some(FontWeight::Bold),
..Default::default()
},
),
Default::default(),
)?;
},
);
let (label, _) = ess.layout.add_child(rect.id, label, Default::default())?;
let data = Rc::new(Data { id_root: div.id });
@ -246,7 +241,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
TooltipSide::Bottom => Vec2::new(0.0, 1.0),
};
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
let anim_mult = ess.layout.state.theme.animation_mult;
ess.layout.animations.add(Animation::new(
rect.id,
(10.0 * anim_mult) as u32,

View File

@ -1,6 +1,6 @@
use std::{
any::{Any, TypeId},
cell::{Ref, RefMut},
cell::RefMut,
collections::HashSet,
rc::{Rc, Weak},
};
@ -181,10 +181,6 @@ impl CallbackDataCommon<'_> {
pub fn globals(&self) -> RefMut<'_, globals::Globals> {
self.state.globals.get()
}
pub fn defaults(&self) -> Ref<'_, globals::Defaults> {
self.state.globals.defaults()
}
}
pub struct CallbackData<'a> {

View File

@ -1,5 +1,5 @@
use std::{
cell::{Ref, RefCell, RefMut},
cell::{RefCell, RefMut},
io::Read,
path::PathBuf,
rc::Rc,
@ -11,53 +11,17 @@ use regex::Regex;
use crate::{
assets::{AssetPath, AssetProvider, LangProvider},
assets_internal, drawing,
assets_internal,
font_config::{WguiFontConfig, WguiFontSystem},
i18n::I18n,
renderer_vk::text::custom_glyph::CustomGlyphCache,
};
#[derive(Clone)]
pub struct Defaults {
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
}
impl Default for Defaults {
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,
}
}
}
pub struct Globals {
pub assets_internal: Box<dyn AssetProvider>,
pub assets_builtin: Box<dyn AssetProvider>,
pub asset_folder: PathBuf,
pub i18n_builtin: I18n,
pub defaults: Defaults,
pub font_system: WguiFontSystem,
pub custom_glyph_cache: CustomGlyphCache,
}
@ -69,7 +33,6 @@ impl WguiGlobals {
pub fn new(
mut assets_builtin: Box<dyn AssetProvider>,
lang_provider: &dyn LangProvider,
defaults: Defaults,
font_config: &WguiFontConfig,
asset_folder: PathBuf,
) -> anyhow::Result<Self> {
@ -79,7 +42,6 @@ impl WguiGlobals {
Ok(Self(Rc::new(RefCell::new(Globals {
assets_internal,
assets_builtin,
defaults,
asset_folder,
font_system: WguiFontSystem::new(font_config, i18n_builtin.get_locale()),
i18n_builtin,
@ -128,10 +90,6 @@ impl WguiGlobals {
RefMut::map(self.0.borrow_mut(), |x| &mut x.i18n_builtin)
}
pub fn defaults(&self) -> Ref<'_, Defaults> {
Ref::map(self.0.borrow(), |x| &x.defaults)
}
pub fn assets_internal(&self) -> RefMut<'_, Box<dyn AssetProvider>> {
RefMut::map(self.0.borrow_mut(), |x| &mut x.assets_internal)
}

View File

@ -15,6 +15,7 @@ use crate::{
globals::WguiGlobals,
sound::WguiSoundType,
task::Tasks,
theme::WguiTheme,
widget::{self, EventParams, EventResult, WidgetObj, WidgetState, WidgetStateFlags, div::WidgetDiv},
};
@ -118,6 +119,7 @@ impl WidgetMap {
pub struct LayoutState {
pub globals: WguiGlobals,
pub theme: Rc<WguiTheme>,
pub widgets: WidgetMap,
pub nodes: WidgetNodeMap,
pub tree: taffy::tree::TaffyTree<WidgetID>,
@ -185,6 +187,7 @@ pub struct Layout {
#[derive(Default)]
pub struct LayoutParams {
pub resize_to_parent: bool,
pub theme: Rc<WguiTheme>,
}
fn add_child_internal(
@ -526,12 +529,13 @@ impl Layout {
Ok(event_result)
}
pub fn new(globals: WguiGlobals, params: &LayoutParams) -> anyhow::Result<Self> {
pub fn new(globals: WguiGlobals, params: LayoutParams) -> anyhow::Result<Self> {
let mut state = LayoutState {
tree: TaffyTree::new(),
widgets: WidgetMap::new(),
nodes: WidgetNodeMap::default(),
globals,
theme: params.theme,
};
let size = if params.resize_to_parent {

View File

@ -40,6 +40,7 @@ pub mod renderer_vk;
pub mod sound;
pub mod stack;
pub mod task;
pub mod theme;
pub mod widget;
pub mod windowing;

View File

@ -57,7 +57,7 @@ pub fn parse_component_button<'a>(
key,
value,
&mut round,
ctx.doc_params.globals.defaults().rounding_mult,
ctx.layout.state.theme.rounding_mult,
);
}
"color" => {

View File

@ -462,7 +462,7 @@ impl ParserContext<'_> {
}
fn populate_theme_variables(&mut self) {
let def = self.doc_params.globals.defaults();
let theme = self.layout.state.theme.clone();
macro_rules! insert_color_vars {
($self:expr, $name:literal, $field:expr, $alpha:expr) => {
@ -479,11 +479,11 @@ impl ParserContext<'_> {
};
}
insert_color_vars!(self, "text", def.text_color, def.translucent_alpha);
insert_color_vars!(self, "accent", def.accent_color, def.translucent_alpha);
insert_color_vars!(self, "danger", def.danger_color, def.translucent_alpha);
insert_color_vars!(self, "faded", def.faded_color, def.translucent_alpha);
insert_color_vars!(self, "bg", def.bg_color, def.translucent_alpha);
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) {
@ -1232,7 +1232,7 @@ pub fn parse_from_assets(
pub fn new_layout_from_assets(
doc_params: &ParseDocumentParams,
layout_params: &LayoutParams,
layout_params: LayoutParams,
) -> anyhow::Result<(Layout, ParserState)> {
let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
let widget = layout.content_root_widget;

View File

@ -42,7 +42,7 @@ pub fn parse_widget_image<'a>(
key,
value,
&mut params.round,
ctx.doc_params.globals.defaults().rounding_mult,
ctx.layout.state.theme.rounding_mult,
);
}
"border" => {

View File

@ -45,11 +45,8 @@ pub fn parse_widget_label<'a>(
}
}
let globals = ctx.layout.state.globals.clone();
let (widget, _) = ctx
.layout
.add_child(parent_id, WidgetLabel::create(&mut globals.get(), params), style)?;
let label = WidgetLabel::create(&mut ctx.layout.state, params);
let (widget, _) = ctx.layout.add_child(parent_id, label, style)?;
parse_widget_universal(ctx, &widget, attribs, tag_name);
parse_children(file, ctx, node, widget.id)?;

View File

@ -47,7 +47,7 @@ pub fn parse_widget_rectangle<'a>(
key,
value,
&mut params.round,
ctx.doc_params.globals.defaults().rounding_mult,
ctx.layout.state.theme.rounding_mult,
);
}
"border" => {

36
wgui/src/theme.rs Normal file
View File

@ -0,0 +1,36 @@
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
}
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,
}
}
}

View File

@ -9,8 +9,9 @@ use crate::{
event::CallbackDataCommon,
globals::Globals,
i18n::Translation,
layout::WidgetID,
layout::{LayoutState, WidgetID},
renderer_vk::text::TextStyle,
theme::WguiTheme,
widget::WidgetStateFlags,
};
@ -31,9 +32,13 @@ pub struct WidgetLabel {
}
impl WidgetLabel {
pub fn create(globals: &mut Globals, mut params: WidgetLabelParams) -> WidgetState {
pub fn create(state: &mut LayoutState, params: WidgetLabelParams) -> WidgetState {
WidgetLabel::create_ex(&mut state.globals.get(), &state.theme, params)
}
pub fn create_ex(globals: &mut Globals, theme: &WguiTheme, mut params: WidgetLabelParams) -> WidgetState {
if params.style.color.is_none() {
params.style.color = Some(globals.defaults.text_color);
params.style.color = Some(theme.text_color);
}
let metrics = Metrics::from(&params.style);