mirror of https://github.com/wayvr-org/wayvr.git
settings tab styles
This commit is contained in:
parent
6a064248dc
commit
031157ea8c
|
|
@ -56,17 +56,19 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<macro name="tab_style" color="background" sticky_color="primary" sticky_border_color="primary(rgb-mult-0.5)" hover_color="tertiary" hover_border_color="tertiary(rgb-mult-0.5)" />
|
||||||
|
|
||||||
<elements>
|
<elements>
|
||||||
<div gap="4">
|
<div gap="4">
|
||||||
<Tabs id="tabs">
|
<Tabs id="tabs">
|
||||||
<Tab name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="dashboard/palette.svg" />
|
<Tab macro="tab_style" name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="dashboard/palette.svg" />
|
||||||
<Tab name="skybox" translation="APP_SETTINGS.SKYBOX" sprite_src_builtin="dashboard/globe.svg" />
|
<Tab macro="tab_style" name="skybox" translation="APP_SETTINGS.SKYBOX" sprite_src_builtin="dashboard/globe.svg" />
|
||||||
<Tab name="features" translation="APP_SETTINGS.FEATURES" sprite_src_builtin="dashboard/options.svg" />
|
<Tab macro="tab_style" name="features" translation="APP_SETTINGS.FEATURES" sprite_src_builtin="dashboard/options.svg" />
|
||||||
<Tab name="controls" translation="APP_SETTINGS.CONTROLS" sprite_src_builtin="dashboard/controller.svg" />
|
<Tab macro="tab_style" name="controls" translation="APP_SETTINGS.CONTROLS" sprite_src_builtin="dashboard/controller.svg" />
|
||||||
<Tab name="space_drag" translation="APP_SETTINGS.SPACE_DRAG" sprite_src_builtin="dashboard/drag.svg" />
|
<Tab macro="tab_style" name="space_drag" translation="APP_SETTINGS.SPACE_DRAG" sprite_src_builtin="dashboard/drag.svg" />
|
||||||
<Tab name="misc" translation="APP_SETTINGS.MISC" sprite_src_builtin="dashboard/blocks.svg" />
|
<Tab macro="tab_style" name="misc" translation="APP_SETTINGS.MISC" sprite_src_builtin="dashboard/blocks.svg" />
|
||||||
<Tab name="autostart_apps" translation="APP_SETTINGS.AUTOSTART_APPS" sprite_src_builtin="dashboard/apps.svg" />
|
<Tab macro="tab_style" name="autostart_apps" translation="APP_SETTINGS.AUTOSTART_APPS" sprite_src_builtin="dashboard/apps.svg" />
|
||||||
<Tab name="troubleshooting" translation="APP_SETTINGS.TROUBLESHOOTING" sprite_src_builtin="dashboard/cpu.svg" />
|
<Tab macro="tab_style" name="troubleshooting" translation="APP_SETTINGS.TROUBLESHOOTING" sprite_src_builtin="dashboard/cpu.svg" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<div flex_wrap="wrap" justify_content="stretch" gap="4" id="settings_root" width="100%">
|
<div flex_wrap="wrap" justify_content="stretch" gap="4" id="settings_root" width="100%">
|
||||||
<!-- filled-in at runtime -->
|
<!-- filled-in at runtime -->
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,34 @@ use flate2::read::GzDecoder;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::i18n::LangsList;
|
use crate::i18n::LangsList;
|
||||||
|
|
||||||
|
pub enum AssetPathRc {
|
||||||
|
WguiInternal(Rc<str>), // tied to internal wgui AssetProvider. Used internally
|
||||||
|
BuiltIn(Rc<str>), // tied to user AssetProvider
|
||||||
|
FileOrBuiltIn(Rc<str>), // attempts to load from a path relative to asset_folder, falls back to BuiltIn
|
||||||
|
File(Rc<str>), // load from filesystem
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetPathRc {
|
||||||
|
pub fn as_borrowed(&self) -> AssetPath<'_> {
|
||||||
|
match self {
|
||||||
|
Self::WguiInternal(path) => AssetPath::WguiInternal(path.as_ref()),
|
||||||
|
Self::BuiltIn(path) => AssetPath::BuiltIn(path.as_ref()),
|
||||||
|
Self::FileOrBuiltIn(path) => AssetPath::FileOrBuiltIn(path.as_ref()),
|
||||||
|
Self::File(path) => AssetPath::File(path.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AssetPathRc> for AssetPath<'a> {
|
||||||
|
fn from(path: &'a AssetPathRc) -> Self {
|
||||||
|
path.as_borrowed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, 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
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::AssetPath,
|
assets::AssetPathRc,
|
||||||
color::WguiColorName,
|
color::WguiColor,
|
||||||
components::{
|
components::{
|
||||||
Component, ComponentBase, ComponentTrait, RefreshData,
|
Component, ComponentBase, ComponentTrait, RefreshData,
|
||||||
button::{self, ComponentButton},
|
button::{self, ComponentButton},
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
event::CallbackDataCommon,
|
event::CallbackDataCommon,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetPair,
|
layout::WidgetPair,
|
||||||
widget::{ConstructEssentials, div::WidgetDiv},
|
widget::{ConstructEssentials, div::WidgetDiv, util::WLength},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use taffy::{
|
use taffy::{
|
||||||
|
|
@ -16,17 +16,25 @@ use taffy::{
|
||||||
prelude::{length, percent},
|
prelude::{length, percent},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Entry<'a> {
|
pub struct Entry {
|
||||||
pub sprite_src: Option<AssetPath<'a>>,
|
pub sprite_src: Option<AssetPathRc>,
|
||||||
pub text: Translation,
|
pub text: Translation,
|
||||||
pub name: &'a str,
|
pub name: Rc<str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Params<'a> {
|
pub struct Params<'a> {
|
||||||
pub style: taffy::Style,
|
pub style: taffy::Style,
|
||||||
pub entries: Vec<Entry<'a>>,
|
pub entries: Vec<Entry>,
|
||||||
pub selected_entry_name: &'a str, // default: ""
|
pub selected_entry_name: &'a str, // default: ""
|
||||||
pub on_select: Option<TabSelectCallback>,
|
pub on_select: Option<TabSelectCallback>,
|
||||||
|
pub round: WLength,
|
||||||
|
pub color: Option<WguiColor>,
|
||||||
|
pub border: f32,
|
||||||
|
pub border_color: Option<WguiColor>,
|
||||||
|
pub hover_color: Option<WguiColor>,
|
||||||
|
pub hover_border_color: Option<WguiColor>,
|
||||||
|
pub sticky_color: Option<WguiColor>,
|
||||||
|
pub sticky_border_color: Option<WguiColor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MountedEntry {
|
struct MountedEntry {
|
||||||
|
|
@ -65,18 +73,10 @@ impl ComponentTrait for ComponentTabs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_button_selected(common: &mut CallbackDataCommon, button: &Rc<ComponentButton>, selected: bool) {
|
|
||||||
if selected {
|
|
||||||
button.set_color(common, WguiColorName::Primary.into());
|
|
||||||
} else {
|
|
||||||
button.set_color(common, WguiColorName::Background.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn select_entry(&mut self, common: &mut CallbackDataCommon, name: &Rc<str>) {
|
fn select_entry(&mut self, common: &mut CallbackDataCommon, name: &Rc<str>) {
|
||||||
for entry in &self.mounted_entries {
|
for entry in &self.mounted_entries {
|
||||||
set_button_selected(common, &entry.button, *entry.name == **name);
|
entry.button.set_sticky_state(common, *entry.name == **name);
|
||||||
}
|
}
|
||||||
self.selected_entry_name = name.clone();
|
self.selected_entry_name = name.clone();
|
||||||
|
|
||||||
|
|
@ -121,7 +121,9 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
let mut mounted_entries = Vec::<MountedEntry>::new();
|
let mut mounted_entries = Vec::<MountedEntry>::new();
|
||||||
|
|
||||||
// Mount entries
|
// Mount entries
|
||||||
for entry in params.entries {
|
for (idx, entry) in params.entries.into_iter().enumerate() {
|
||||||
|
let sprite_src = entry.sprite_src.as_ref().map(AssetPathRc::as_borrowed);
|
||||||
|
|
||||||
let (_, button) = button::construct(
|
let (_, button) = button::construct(
|
||||||
&mut ConstructEssentials {
|
&mut ConstructEssentials {
|
||||||
layout: ess.layout,
|
layout: ess.layout,
|
||||||
|
|
@ -129,7 +131,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
},
|
},
|
||||||
button::Params {
|
button::Params {
|
||||||
text: Some(entry.text),
|
text: Some(entry.text),
|
||||||
sprite_src: entry.sprite_src,
|
sprite_src,
|
||||||
style: taffy::Style {
|
style: taffy::Style {
|
||||||
min_size: taffy::Size {
|
min_size: taffy::Size {
|
||||||
width: percent(1.0),
|
width: percent(1.0),
|
||||||
|
|
@ -138,15 +140,23 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
justify_content: Some(taffy::JustifyContent::START),
|
justify_content: Some(taffy::JustifyContent::START),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
round: params.round,
|
||||||
|
color: params.color,
|
||||||
|
border: params.border,
|
||||||
|
border_color: params.border_color,
|
||||||
|
hover_color: params.hover_color,
|
||||||
|
hover_border_color: params.hover_border_color,
|
||||||
|
sticky_color: params.sticky_color,
|
||||||
|
sticky_border_color: params.sticky_border_color,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// init colors
|
// init colors
|
||||||
set_button_selected(&mut ess.layout.common(), &button, false);
|
button.set_sticky_state(&mut ess.layout.common(), idx == 0);
|
||||||
|
|
||||||
mounted_entries.push(MountedEntry {
|
mounted_entries.push(MountedEntry {
|
||||||
name: Rc::from(entry.name),
|
name: entry.name,
|
||||||
button,
|
button,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::AssetPath,
|
assets::AssetPathRc,
|
||||||
|
color::WguiColor,
|
||||||
components::{Component, tabs},
|
components::{Component, tabs},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{AttribPair, ParserContext, get_asset_path_from_kv, process_component, style::parse_style},
|
parser::{
|
||||||
|
AttribPair, ParserContext, ParserFile, get_asset_path_rc_from_kv, process_attribs, process_component,
|
||||||
|
style::{parse_color_opt, parse_round, parse_style},
|
||||||
|
},
|
||||||
|
widget::util::WLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_component_tabs<'a>(
|
pub fn parse_component_tabs<'a>(
|
||||||
|
file: &'a ParserFile,
|
||||||
ctx: &mut ParserContext,
|
ctx: &mut ParserContext,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
|
@ -17,25 +25,71 @@ pub fn parse_component_tabs<'a>(
|
||||||
|
|
||||||
let mut entries = Vec::<tabs::Entry>::new();
|
let mut entries = Vec::<tabs::Entry>::new();
|
||||||
|
|
||||||
|
let mut border = 2.0;
|
||||||
|
let mut color: Option<WguiColor> = None;
|
||||||
|
let mut border_color: Option<WguiColor> = None;
|
||||||
|
let mut hover_color: Option<WguiColor> = None;
|
||||||
|
let mut hover_border_color: Option<WguiColor> = None;
|
||||||
|
let mut sticky_color: Option<WguiColor> = None;
|
||||||
|
let mut sticky_border_color: Option<WguiColor> = None;
|
||||||
|
let mut round = WLength::Units(4.0);
|
||||||
|
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
match child.tag_name().name() {
|
match child.tag_name().name() {
|
||||||
"" => { /* ignore */ }
|
"" => { /* ignore */ }
|
||||||
"Tab" => {
|
"Tab" => {
|
||||||
let mut name: Option<&str> = None;
|
let mut name: Option<Rc<str>> = None;
|
||||||
let mut text: Option<Translation> = None;
|
let mut text: Option<Translation> = None;
|
||||||
let mut sprite_src: Option<AssetPath> = None;
|
let mut sprite_src: Option<AssetPathRc> = None;
|
||||||
|
|
||||||
for attrib in child.attributes() {
|
let attribs = process_attribs(file, ctx, &child, false);
|
||||||
let (key, value) = (attrib.name(), attrib.value());
|
|
||||||
match key {
|
for attrib in attribs.iter() {
|
||||||
"name" => name = Some(value),
|
match &*attrib.attrib {
|
||||||
"text" => text = Some(Translation::from_raw_text(value)),
|
"name" => name = Some(attrib.value.clone()),
|
||||||
"translation" => text = Some(Translation::from_translation_key(value)),
|
"text" => text = Some(Translation::from_raw_text(&*attrib.value)),
|
||||||
|
"translation" => text = Some(Translation::from_translation_key(&*attrib.value)),
|
||||||
"sprite_src" | "sprite_src_ext" | "sprite_src_builtin" | "sprite_src_internal" => {
|
"sprite_src" | "sprite_src_ext" | "sprite_src_builtin" | "sprite_src_internal" => {
|
||||||
sprite_src = Some(get_asset_path_from_kv("sprite_", key, value));
|
sprite_src = Some(get_asset_path_rc_from_kv(
|
||||||
|
"sprite_",
|
||||||
|
&*attrib.attrib,
|
||||||
|
attrib.value.clone(),
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
"round" => {
|
||||||
|
parse_round(
|
||||||
|
ctx,
|
||||||
|
tag_name,
|
||||||
|
&*attrib.attrib,
|
||||||
|
&*attrib.value,
|
||||||
|
&mut round,
|
||||||
|
ctx.layout.state.theme.rounding_mult,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut color);
|
||||||
|
}
|
||||||
|
"border" => {
|
||||||
|
ctx.parse_check_f32(tag_name, &*attrib.attrib, &*attrib.value, &mut border);
|
||||||
|
}
|
||||||
|
"border_color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut border_color);
|
||||||
|
}
|
||||||
|
"hover_color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut hover_color);
|
||||||
|
}
|
||||||
|
"hover_border_color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut hover_border_color);
|
||||||
|
}
|
||||||
|
"sticky_color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut sticky_color);
|
||||||
|
}
|
||||||
|
"sticky_border_color" => {
|
||||||
|
parse_color_opt(ctx, tag_name, &*attrib.attrib, &*attrib.value, &mut sticky_border_color);
|
||||||
}
|
}
|
||||||
other_key => {
|
other_key => {
|
||||||
ctx.print_invalid_attrib("Tab", other_key, value);
|
ctx.print_invalid_attrib("Tab", other_key, &*attrib.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +113,14 @@ pub fn parse_component_tabs<'a>(
|
||||||
selected_entry_name: "first",
|
selected_entry_name: "first",
|
||||||
entries,
|
entries,
|
||||||
on_select: None,
|
on_select: None,
|
||||||
|
border,
|
||||||
|
color,
|
||||||
|
border_color,
|
||||||
|
hover_color,
|
||||||
|
hover_border_color,
|
||||||
|
sticky_color,
|
||||||
|
sticky_border_color,
|
||||||
|
round,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ mod widget_rectangle;
|
||||||
mod widget_sprite;
|
mod widget_sprite;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{AssetPath, AssetPathOwned, normalize_path},
|
assets::{AssetPath, AssetPathOwned, AssetPathRc, normalize_path},
|
||||||
components::{Component, ComponentWeak},
|
components::{Component, ComponentWeak},
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
|
|
@ -1082,7 +1082,9 @@ fn parse_child<'a>(
|
||||||
"EditBox" => new_widget_id = Some(parse_component_editbox(ctx, parent_id, &attribs, tag_name)?),
|
"EditBox" => new_widget_id = Some(parse_component_editbox(ctx, parent_id, &attribs, tag_name)?),
|
||||||
"BarGraph" => new_widget_id = Some(parse_component_bar_graph(ctx, parent_id, &attribs, tag_name)?),
|
"BarGraph" => new_widget_id = Some(parse_component_bar_graph(ctx, parent_id, &attribs, tag_name)?),
|
||||||
"Tabs" => {
|
"Tabs" => {
|
||||||
new_widget_id = Some(parse_component_tabs(ctx, child_node, parent_id, &attribs, tag_name)?);
|
new_widget_id = Some(parse_component_tabs(
|
||||||
|
file, ctx, child_node, parent_id, &attribs, tag_name,
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
"" => { /* ignore */ }
|
"" => { /* ignore */ }
|
||||||
other_tag_name => {
|
other_tag_name => {
|
||||||
|
|
@ -1327,21 +1329,26 @@ fn parse_document_root(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_asset_path_from_kv<'a>(prefix: &'static str, key: &'a str, value: &'a str) -> AssetPath<'a> {
|
fn get_asset_path_from_kv<'a>(prefix: &str, key: &'a str, value: &'a str) -> AssetPath<'a> {
|
||||||
let key_split = match key.find(prefix) {
|
let key = key.strip_prefix(prefix).unwrap_or(key);
|
||||||
Some(pos) => {
|
|
||||||
assert!(pos == 0, "invalid split");
|
match key {
|
||||||
key.get(prefix.len()..).unwrap()
|
|
||||||
}
|
|
||||||
None => key,
|
|
||||||
};
|
|
||||||
match key_split {
|
|
||||||
"src" => AssetPath::FileOrBuiltIn(value),
|
"src" => AssetPath::FileOrBuiltIn(value),
|
||||||
"src_ext" => AssetPath::File(value),
|
"src_ext" => AssetPath::File(value),
|
||||||
"src_builtin" => AssetPath::BuiltIn(value),
|
"src_builtin" => AssetPath::BuiltIn(value),
|
||||||
"src_internal" => AssetPath::WguiInternal(value),
|
"src_internal" => AssetPath::WguiInternal(value),
|
||||||
other => {
|
other => panic!("unexpected attrib {other}"),
|
||||||
panic!("unexpected attrib {other}");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_asset_path_rc_from_kv(prefix: &'static str, key: &str, value: Rc<str>) -> AssetPathRc {
|
||||||
|
let key = key.strip_prefix(prefix).unwrap_or(key);
|
||||||
|
|
||||||
|
match key {
|
||||||
|
"src" => AssetPathRc::FileOrBuiltIn(value),
|
||||||
|
"src_ext" => AssetPathRc::File(value),
|
||||||
|
"src_builtin" => AssetPathRc::BuiltIn(value),
|
||||||
|
"src_internal" => AssetPathRc::WguiInternal(value),
|
||||||
|
other => panic!("unexpected attrib {other}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue