FileOrBuiltIn asset paths, theming support

This commit is contained in:
galister
2025-12-11 01:09:49 +09:00
parent cb0831223a
commit 1724d39697
13 changed files with 90 additions and 63 deletions

View File

@@ -1,4 +1,4 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, path::PathBuf, rc::Rc};
use chrono::Timelike; use chrono::Timelike;
use glam::Vec2; use glam::Vec2;
@@ -18,8 +18,8 @@ use wlx_common::timestep::Timestep;
use crate::{ use crate::{
assets, settings, assets, settings,
tab::{ tab::{
Tab, TabParams, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, settings::TabSettings,
settings::TabSettings, Tab, TabParams, TabType,
}, },
task::Tasks, task::Tasks,
util::{ util::{
@@ -96,6 +96,7 @@ impl Frontend {
family_name_serif: "Quicksand", family_name_serif: "Quicksand",
family_name_monospace: "", family_name_monospace: "",
}, },
PathBuf::new(), //FIXME: pass from somewhere else
)?; )?;
let (layout, state) = wgui::parser::new_layout_from_assets( let (layout, state) = wgui::parser::new_layout_from_assets(

View File

@@ -1,3 +1,5 @@
use std::path::PathBuf;
use crate::{ use crate::{
assets, assets,
testbed::{Testbed, TestbedUpdateParams}, testbed::{Testbed, TestbedUpdateParams},
@@ -21,7 +23,7 @@ pub struct TestbedAny {
impl TestbedAny { impl TestbedAny {
pub fn new(name: &str) -> anyhow::Result<Self> { pub fn new(name: &str) -> anyhow::Result<Self> {
let path = if name.ends_with(".xml") { let path = if name.ends_with(".xml") {
AssetPath::Filesystem(name) AssetPath::FileOrBuiltIn(name)
} else { } else {
AssetPath::BuiltIn(&format!("gui/{name}.xml")) AssetPath::BuiltIn(&format!("gui/{name}.xml"))
}; };
@@ -30,6 +32,7 @@ impl TestbedAny {
Box::new(assets::Asset {}), Box::new(assets::Asset {}),
wgui::globals::Defaults::default(), wgui::globals::Defaults::default(),
&WguiFontConfig::default(), &WguiFontConfig::default(),
PathBuf::new(), // cwd
)?; )?;
let (layout, state) = wgui::parser::new_layout_from_assets( let (layout, state) = wgui::parser::new_layout_from_assets(

View File

@@ -1,4 +1,4 @@
use std::{cell::RefCell, collections::VecDeque, rc::Rc}; use std::{cell::RefCell, collections::VecDeque, path::PathBuf, rc::Rc};
use crate::{ use crate::{
assets, assets,
@@ -8,9 +8,9 @@ use glam::Vec2;
use wgui::{ use wgui::{
assets::AssetPath, assets::AssetPath,
components::{ components::{
Component,
button::{ButtonClickCallback, ComponentButton}, button::{ButtonClickCallback, ComponentButton},
checkbox::ComponentCheckbox, checkbox::ComponentCheckbox,
Component,
}, },
drawing::Color, drawing::Color,
event::StyleSetRequest, event::StyleSetRequest,
@@ -80,6 +80,7 @@ impl TestbedGeneric {
Box::new(assets::Asset {}), Box::new(assets::Asset {}),
wgui::globals::Defaults::default(), wgui::globals::Defaults::default(),
&WguiFontConfig::default(), &WguiFontConfig::default(),
PathBuf::new(), // cwd
)?; )?;
let extra = ParseDocumentExtra { let extra = ParseDocumentExtra {

View File

@@ -158,12 +158,12 @@ _2nd gradient color_
`src`: **string** `src`: **string**
_External (filesystem) image path. Falls back to Internal (assets) if not found._
`src_builtin`: **string**
_Internal (assets) image path_ _Internal (assets) image path_
`src_ext`: **string**
_External (filesystem) image path_
`src_internal`: **string** `src_internal`: **string**
_wgui internal image path. Do not use directly unless it's related to the core wgui assets._ _wgui internal image path. Do not use directly unless it's related to the core wgui assets._
@@ -210,7 +210,7 @@ _Tooltip text on hover, translated by key_
_make button act as a toggle (visual only)_ _make button act as a toggle (visual only)_
`sprite_src` | `sprite_src_ext` | `sprite_src_internal` `sprite_src` | `sprite_src_builtin` | `sprite_src_internal`
_Image path (see [sprite](#sprite-widget)) for src descriptions_ _Image path (see [sprite](#sprite-widget)) for src descriptions_

View File

@@ -5,16 +5,16 @@ use std::path::{Component, Path, PathBuf};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum AssetPath<'a> { pub enum AssetPath<'a> {
WguiInternal(&'a str), // tied to internal wgui AssetProvider. Used internally WguiInternal(&'a str), // tied to internal wgui AssetProvider. Used internally
BuiltIn(&'a str), // tied to user AssetProvider BuiltIn(&'a str), // tied to user AssetProvider
Filesystem(&'a str), // tied to filesystem path FileOrBuiltIn(&'a str), // attempts to load from a path relative to asset_folder, falls back to BuiltIn
} }
#[derive(Clone)] #[derive(Clone)]
pub enum AssetPathOwned { pub enum AssetPathOwned {
WguiInternal(PathBuf), WguiInternal(PathBuf),
BuiltIn(PathBuf), BuiltIn(PathBuf),
Filesystem(PathBuf), FileOrBuiltIn(PathBuf),
} }
impl AssetPath<'_> { impl AssetPath<'_> {
@@ -22,7 +22,7 @@ impl AssetPath<'_> {
match &self { match &self {
AssetPath::WguiInternal(path) => path, AssetPath::WguiInternal(path) => path,
AssetPath::BuiltIn(path) => path, AssetPath::BuiltIn(path) => path,
AssetPath::Filesystem(path) => path, AssetPath::FileOrBuiltIn(path) => path,
} }
} }
@@ -30,7 +30,7 @@ impl AssetPath<'_> {
match self { match self {
AssetPath::WguiInternal(path) => AssetPathOwned::WguiInternal(PathBuf::from(path)), AssetPath::WguiInternal(path) => AssetPathOwned::WguiInternal(PathBuf::from(path)),
AssetPath::BuiltIn(path) => AssetPathOwned::BuiltIn(PathBuf::from(path)), AssetPath::BuiltIn(path) => AssetPathOwned::BuiltIn(PathBuf::from(path)),
AssetPath::Filesystem(path) => AssetPathOwned::Filesystem(PathBuf::from(path)), AssetPath::FileOrBuiltIn(path) => AssetPathOwned::FileOrBuiltIn(PathBuf::from(path)),
} }
} }
} }
@@ -40,7 +40,7 @@ impl AssetPathOwned {
match self { match self {
AssetPathOwned::WguiInternal(buf) => AssetPath::WguiInternal(buf.to_str().unwrap()), AssetPathOwned::WguiInternal(buf) => AssetPath::WguiInternal(buf.to_str().unwrap()),
AssetPathOwned::BuiltIn(buf) => AssetPath::BuiltIn(buf.to_str().unwrap()), AssetPathOwned::BuiltIn(buf) => AssetPath::BuiltIn(buf.to_str().unwrap()),
AssetPathOwned::Filesystem(buf) => AssetPath::Filesystem(buf.to_str().unwrap()), AssetPathOwned::FileOrBuiltIn(buf) => AssetPath::FileOrBuiltIn(buf.to_str().unwrap()),
} }
} }
@@ -48,7 +48,7 @@ impl AssetPathOwned {
match self { match self {
AssetPathOwned::WguiInternal(buf) => buf, AssetPathOwned::WguiInternal(buf) => buf,
AssetPathOwned::BuiltIn(buf) => buf, AssetPathOwned::BuiltIn(buf) => buf,
AssetPathOwned::Filesystem(buf) => buf, AssetPathOwned::FileOrBuiltIn(buf) => buf,
} }
} }
} }
@@ -64,7 +64,7 @@ impl AssetPathOwned {
match self { match self {
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path), AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path), AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path), AssetPathOwned::FileOrBuiltIn(_) => AssetPathOwned::FileOrBuiltIn(new_path),
} }
} }
} }

View File

@@ -1,9 +1,12 @@
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefCell, RefMut},
io::Read, io::Read,
path::PathBuf,
rc::Rc, rc::Rc,
}; };
use anyhow::Context;
use crate::{ use crate::{
assets::{AssetPath, AssetProvider}, assets::{AssetPath, AssetProvider},
assets_internal, drawing, assets_internal, drawing,
@@ -35,6 +38,7 @@ impl Default for Defaults {
pub struct Globals { pub struct Globals {
pub assets_internal: Box<dyn AssetProvider>, pub assets_internal: Box<dyn AssetProvider>,
pub assets_builtin: Box<dyn AssetProvider>, pub assets_builtin: Box<dyn AssetProvider>,
pub asset_folder: PathBuf,
pub i18n_builtin: I18n, pub i18n_builtin: I18n,
pub defaults: Defaults, pub defaults: Defaults,
pub font_system: WguiFontSystem, pub font_system: WguiFontSystem,
@@ -48,6 +52,7 @@ impl WguiGlobals {
mut assets_builtin: Box<dyn AssetProvider>, mut assets_builtin: Box<dyn AssetProvider>,
defaults: Defaults, defaults: Defaults,
font_config: &WguiFontConfig, font_config: &WguiFontConfig,
asset_folder: PathBuf,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
let i18n_builtin = I18n::new(&mut assets_builtin)?; let i18n_builtin = I18n::new(&mut assets_builtin)?;
let assets_internal = Box::new(assets_internal::AssetInternal {}); let assets_internal = Box::new(assets_internal::AssetInternal {});
@@ -57,6 +62,7 @@ impl WguiGlobals {
assets_builtin, assets_builtin,
i18n_builtin, i18n_builtin,
defaults, defaults,
asset_folder,
font_system: WguiFontSystem::new(font_config), font_system: WguiFontSystem::new(font_config),
})))) }))))
} }
@@ -65,26 +71,33 @@ impl WguiGlobals {
match asset_path { match asset_path {
AssetPath::WguiInternal(path) => self.assets_internal().load_from_path(path), AssetPath::WguiInternal(path) => self.assets_internal().load_from_path(path),
AssetPath::BuiltIn(path) => self.assets_builtin().load_from_path(path), AssetPath::BuiltIn(path) => self.assets_builtin().load_from_path(path),
AssetPath::Filesystem(path) => { AssetPath::FileOrBuiltIn(path) => self
let mut file = match std::fs::File::open(path) { .load_asset_from_fs(path)
Ok(f) => f, .inspect_err(|e| log::debug!("{e:?}"))
Err(e) => { .or_else(|_| self.assets_builtin().load_from_path(path)),
anyhow::bail!("Could not open asset from {path}: {e}");
}
};
/* 16 MiB safeguard */
if file.metadata()?.len() > 16 * 1024 * 1024 {
anyhow::bail!("Could not open asset from {path}: Over size limit (16MiB)");
}
let mut data = Vec::new();
if let Err(e) = file.read_to_end(&mut data) {
anyhow::bail!("Could not read asset from {path}: {e}");
}
Ok(data)
}
} }
} }
fn load_asset_from_fs(&self, path: &str) -> anyhow::Result<Vec<u8>> {
let path = self.0.borrow().asset_folder.join(path);
let mut file =
std::fs::File::open(path.as_path()).with_context(|| format!("Could not open asset from {}", path.display()))?;
/* 16 MiB safeguard */
let metadata = file
.metadata()
.with_context(|| format!("Could not get file metadata for {}", path.display()))?;
if metadata.len() > 16 * 1024 * 1024 {
anyhow::bail!("Could not open asset from {}: Over size limit (16MiB)", path.display());
}
let mut data = Vec::new();
file
.read_to_end(&mut data)
.with_context(|| format!("Could not read asset from {}", path.display()))?;
Ok(data)
}
pub fn get(&self) -> RefMut<'_, Globals> { pub fn get(&self) -> RefMut<'_, Globals> {
self.0.borrow_mut() self.0.borrow_mut()
} }

View File

@@ -1,13 +1,13 @@
use crate::{ use crate::{
assets::AssetPath, assets::AssetPath,
components::{Component, button, tooltip}, components::{button, tooltip, Component},
drawing::Color, drawing::Color,
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
AttribPair, ParserContext, ParserFile, parse_check_f32, parse_check_i32, parse_children, print_invalid_attrib, parse_check_f32, parse_check_i32, parse_children, print_invalid_attrib, process_component,
process_component,
style::{parse_color_opt, parse_round, parse_style, parse_text_style}, style::{parse_color_opt, parse_round, parse_style, parse_text_style},
AttribPair, ParserContext, ParserFile,
}, },
widget::util::WLength, widget::util::WLength,
}; };
@@ -62,10 +62,10 @@ pub fn parse_component_button<'a>(
"hover_border_color" => { "hover_border_color" => {
parse_color_opt(value, &mut hover_border_color); parse_color_opt(value, &mut hover_border_color);
} }
"sprite_src" | "sprite_src_ext" | "sprite_src_internal" => { "sprite_src" | "sprite_src_builtin" | "sprite_src_internal" => {
let asset_path = match key { let asset_path = match key {
"sprite_src" => AssetPath::BuiltIn(value), "sprite_src" => AssetPath::FileOrBuiltIn(value),
"sprite_src_ext" => AssetPath::Filesystem(value), "sprite_src_builtin" => AssetPath::BuiltIn(value),
"sprite_src_internal" => AssetPath::WguiInternal(value), "sprite_src_internal" => AssetPath::WguiInternal(value),
_ => unreachable!(), _ => unreachable!(),
}; };

View File

@@ -551,7 +551,7 @@ fn parse_tag_include(
for pair in attribs { for pair in attribs {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match pair.attrib.as_ref() { match pair.attrib.as_ref() {
"src" | "src_ext" | "src_internal" => { "src" | "src_builtin" | "src_internal" => {
path = Some({ path = Some({
let this = &file.path.clone(); let this = &file.path.clone();
let include: &str = &pair.value; let include: &str = &pair.value;
@@ -564,9 +564,9 @@ fn parse_tag_include(
"src" => match this { "src" => match this {
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path), AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path), AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path), AssetPathOwned::FileOrBuiltIn(_) => AssetPathOwned::FileOrBuiltIn(new_path),
}, },
"src_ext" => AssetPathOwned::Filesystem(new_path), "src_builtin" => AssetPathOwned::BuiltIn(new_path),
"src_internal" => AssetPathOwned::WguiInternal(new_path), "src_internal" => AssetPathOwned::WguiInternal(new_path),
_ => unreachable!(), _ => unreachable!(),
} }
@@ -583,7 +583,7 @@ fn parse_tag_include(
} }
let Some(path) = path else { let Some(path) = path else {
log::warn!("include tag with no source! specify either: src, src_ext, src_internal"); log::warn!("include tag with no source! specify either: src, src_builtin, src_internal");
return Ok(()); return Ok(());
}; };
let path_ref = path.as_ref(); let path_ref = path.as_ref();

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
assets::AssetPath, assets::AssetPath,
layout::WidgetID, layout::WidgetID,
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style}, parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData}, renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
widget::sprite::{WidgetSprite, WidgetSpriteParams}, widget::sprite::{WidgetSprite, WidgetSpriteParams},
}; };
@@ -22,10 +22,10 @@ pub fn parse_widget_sprite<'a>(
for pair in attribs { for pair in attribs {
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref()); let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
match key { match key {
"src" | "src_ext" | "src_internal" => { "src" | "src_builtin" | "src_internal" => {
let asset_path = match key { let asset_path = match key {
"src" => AssetPath::BuiltIn(value), "src" => AssetPath::FileOrBuiltIn(value),
"src_ext" => AssetPath::Filesystem(value), "src_builtin" => AssetPath::BuiltIn(value),
"src_internal" => AssetPath::WguiInternal(value), "src_internal" => AssetPath::WguiInternal(value),
_ => unreachable!(), _ => unreachable!(),
}; };

View File

@@ -1,7 +1,7 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use chrono::Offset; use chrono::Offset;
use glam::{Affine3A, Quat, Vec3, vec3}; use glam::{vec3, Affine3A, Quat, Vec3};
use idmap::IdMap; use idmap::IdMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -116,6 +116,10 @@ fn def_empty() -> Arc<str> {
"".into() "".into()
} }
fn def_theme_path() -> Arc<str> {
"theme".into()
}
fn def_toast_topics() -> IdMap<ToastTopic, ToastDisplayMethod> { fn def_toast_topics() -> IdMap<ToastTopic, ToastDisplayMethod> {
IdMap::new() IdMap::new()
} }
@@ -130,6 +134,9 @@ const fn def_max_height() -> u16 {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct GeneralConfig { pub struct GeneralConfig {
#[serde(default = "def_theme_path")]
pub theme_path: Arc<str>,
#[serde(default = "def_watch_pos")] #[serde(default = "def_watch_pos")]
pub watch_pos: Vec3, pub watch_pos: Vec3,

View File

@@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use button::setup_custom_button; use button::setup_custom_button;
use glam::{Affine2, Vec2, vec2}; use glam::{vec2, Affine2, Vec2};
use label::setup_custom_label; use label::setup_custom_label;
use wgui::{ use wgui::{
assets::AssetPath, assets::AssetPath,
@@ -15,7 +15,7 @@ use wgui::{
layout::{Layout, LayoutParams, WidgetID}, layout::{Layout, LayoutParams, WidgetID},
parser::{CustomAttribsInfoOwned, ParserState}, parser::{CustomAttribsInfoOwned, ParserState},
renderer_vk::context::Context as WguiContext, renderer_vk::context::Context as WguiContext,
widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle}, widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
}; };
use wlx_common::timestep::Timestep; use wlx_common::timestep::Timestep;
@@ -24,7 +24,7 @@ use crate::{
state::AppState, state::AppState,
subsystem::hid::WheelDelta, subsystem::hid::WheelDelta,
windowing::backend::{ windowing::backend::{
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform, ui_transform, FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
}, },
}; };
@@ -96,7 +96,7 @@ impl<S: 'static> GuiPanel<S> {
let doc_params = wgui::parser::ParseDocumentParams { let doc_params = wgui::parser::ParseDocumentParams {
globals: app.wgui_globals.clone(), globals: app.wgui_globals.clone(),
path: AssetPath::BuiltIn(path), path: AssetPath::FileOrBuiltIn(path),
extra: wgui::parser::ParseDocumentExtra { extra: wgui::parser::ParseDocumentExtra {
on_custom_attribs: Some(Box::new({ on_custom_attribs: Some(Box::new({
let custom_elems = custom_elems.clone(); let custom_elems = custom_elems.clone();

View File

@@ -1,6 +1,6 @@
use std::{collections::HashMap, rc::Rc}; use std::{collections::HashMap, rc::Rc};
use glam::{Affine3A, FloatExt, Mat4, Quat, Vec2, Vec3, vec2, vec3}; use glam::{vec2, vec3, Affine3A, FloatExt, Mat4, Quat, Vec2, Vec3};
use wgui::{ use wgui::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
assets::AssetPath, assets::AssetPath,
@@ -11,10 +11,10 @@ use wgui::{
renderer_vk::util, renderer_vk::util,
taffy::{self, prelude::length}, taffy::{self, prelude::length},
widget::{ widget::{
EventResult,
div::WidgetDiv, div::WidgetDiv,
rectangle::{WidgetRectangle, WidgetRectangleParams}, rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength, util::WLength,
EventResult,
}, },
}; };
use wlx_common::windowing::{OverlayWindowState, Positioning}; use wlx_common::windowing::{OverlayWindowState, Positioning};
@@ -22,14 +22,14 @@ use wlx_common::windowing::{OverlayWindowState, Positioning};
use crate::{ use crate::{
gui::panel::GuiPanel, gui::panel::GuiPanel,
state::AppState, state::AppState,
subsystem::hid::{ALT, CTRL, META, SHIFT, SUPER, XkbKeymap}, subsystem::hid::{XkbKeymap, ALT, CTRL, META, SHIFT, SUPER},
windowing::window::OverlayWindowConfig, windowing::window::OverlayWindowConfig,
}; };
use super::{ use super::{
KEYBOARD_NAME, KeyButtonData, KeyState, KeyboardBackend, KeyboardState, handle_press, handle_press, handle_release,
handle_release,
layout::{self, AltModifier, KeyCapType}, layout::{self, AltModifier, KeyCapType},
KeyButtonData, KeyState, KeyboardBackend, KeyboardState, KEYBOARD_NAME,
}; };
const BACKGROUND_PADDING: f32 = 16.0; const BACKGROUND_PADDING: f32 = 16.0;
@@ -83,7 +83,7 @@ pub fn create_keyboard(
let parse_doc_params = wgui::parser::ParseDocumentParams { let parse_doc_params = wgui::parser::ParseDocumentParams {
globals, globals,
path: AssetPath::BuiltIn("gui/keyboard.xml"), path: AssetPath::FileOrBuiltIn("gui/keyboard.xml"),
extra: Default::default(), extra: Default::default(),
}; };

View File

@@ -24,7 +24,7 @@ use crate::subsystem::osc::OscSender;
use crate::{ use crate::{
backend::{input::InputState, task::TaskContainer}, backend::{input::InputState, task::TaskContainer},
config::load_general_config, config::load_general_config,
config_io, config_io::{self, get_config_file_path},
graphics::WGfxExtras, graphics::WGfxExtras,
gui, gui,
subsystem::{audio::AudioOutput, input::HidWrapper}, subsystem::{audio::AudioOutput, input::HidWrapper},
@@ -85,6 +85,7 @@ impl AppState {
); );
let wgui_shared = WSharedContext::new(gfx.clone())?; let wgui_shared = WSharedContext::new(gfx.clone())?;
let theme = session.config.theme_path.clone();
Ok(Self { Ok(Self {
session, session,
@@ -103,6 +104,7 @@ impl AppState {
Box::new(gui::asset::GuiAsset {}), Box::new(gui::asset::GuiAsset {}),
wgui::globals::Defaults::default(), wgui::globals::Defaults::default(),
&WguiFontConfig::default(), &WguiFontConfig::default(),
get_config_file_path(&*theme),
)?, )?,
#[cfg(feature = "osc")] #[cfg(feature = "osc")]