watch & edit to use theme.xml; device batteries
This commit is contained in:
@@ -8,7 +8,7 @@ mod widget_rectangle;
|
||||
mod widget_sprite;
|
||||
|
||||
use crate::{
|
||||
assets::{AssetPath, AssetPathOwned, normalize_path},
|
||||
assets::{normalize_path, AssetPath, AssetPathOwned},
|
||||
components::{Component, ComponentWeak},
|
||||
drawing::{self},
|
||||
globals::WguiGlobals,
|
||||
@@ -545,11 +545,14 @@ fn parse_tag_include(
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<()> {
|
||||
let mut path = None;
|
||||
let mut optional = false;
|
||||
|
||||
for pair in attribs {
|
||||
#[allow(clippy::single_match)]
|
||||
match pair.attrib.as_ref() {
|
||||
"src" => {
|
||||
let new_path = {
|
||||
"src" | "src_ext" | "src_internal" => {
|
||||
path = Some({
|
||||
let this = &file.path.clone();
|
||||
let include: &str = &pair.value;
|
||||
let buf = this.get_path_buf();
|
||||
@@ -557,17 +560,21 @@ fn parse_tag_include(
|
||||
new_path.push(include);
|
||||
let new_path = normalize_path(&new_path);
|
||||
|
||||
match this {
|
||||
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
|
||||
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
|
||||
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path),
|
||||
match pair.attrib.as_ref() {
|
||||
"src" => match this {
|
||||
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
|
||||
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
|
||||
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path),
|
||||
},
|
||||
"src_ext" => AssetPathOwned::Filesystem(new_path),
|
||||
"src_internal" => AssetPathOwned::WguiInternal(new_path),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
let new_path_ref = new_path.as_ref();
|
||||
let (new_file, node_layout) = get_doc_from_asset_path(ctx, new_path_ref)?;
|
||||
parse_document_root(&new_file, ctx, parent_id, node_layout)?;
|
||||
|
||||
return Ok(());
|
||||
});
|
||||
}
|
||||
"optional" => {
|
||||
let mut optional_i32 = 0;
|
||||
optional = parse_check_i32(&pair.value, &mut optional_i32) && optional_i32 == 1;
|
||||
}
|
||||
_ => {
|
||||
print_invalid_attrib(pair.attrib.as_ref(), pair.value.as_ref());
|
||||
@@ -575,6 +582,20 @@ fn parse_tag_include(
|
||||
}
|
||||
}
|
||||
|
||||
let Some(path) = path else {
|
||||
log::warn!("include tag with no source! specify either: src, src_ext, src_internal");
|
||||
return Ok(());
|
||||
};
|
||||
let path_ref = path.as_ref();
|
||||
match get_doc_from_asset_path(ctx, path_ref) {
|
||||
Ok((new_file, node_layout)) => parse_document_root(&new_file, ctx, parent_id, node_layout)?,
|
||||
Err(e) => {
|
||||
if !optional {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
<layout>
|
||||
<include src="theme.xml" />
|
||||
|
||||
<macro name="button_style"
|
||||
margin="2" overflow="hidden" box_sizing="border_box"
|
||||
border_color="~color_accent_translucent" border="2" round="8" color="~color_accent_5" color2="~color_accent_1" gradient="vertical"
|
||||
align_items="center" justify_content="center" />
|
||||
|
||||
<macro name="button_style"
|
||||
margin="2" overflow="hidden" box_sizing="border_box" align_items="center" justify_content="center"
|
||||
border="2" round="50%" padding="8" gradient="vertical" tooltip_side="bottom" />
|
||||
|
||||
<template name="TopButton">
|
||||
<Button id="${id}" macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" sticky="${sticky}" border_color="#0044CC" color="#000A1C" color2="#000002">
|
||||
<Button id="${id}" macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" sticky="${sticky}" border_color="~color_accent_translucent" color="~color_accent_5" color2="~color_accent_1">
|
||||
<sprite id="${id}_sprite" width="48" height="48" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="TopButtonDanger">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="#CC0000" color="#110000" color2="#020000">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1">
|
||||
<sprite width="48" height="48" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="TopButtonFaded">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="#707070" color="#202020" color2="#010101">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="~color_faded_translucent" color="~color_faded_5" color2="~color_faded_1">
|
||||
<sprite width="48" height="48" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="PosButton">
|
||||
<Button id="${id}" macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="#0044CC" color="#000A1C" color2="#000002">
|
||||
<Button id="${id}" macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="~color_accent_translucent" color="~color_accent_5" color2="~color_accent_1">
|
||||
<sprite id="${id}_sprite" width="40" height="40" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div width="100%" height="100%">
|
||||
<rectangle id="shadow" width="100%" height="100%" padding="4" gap="4" align_items="center" justify_content="center" color="#000000DD" flex_direction="row">
|
||||
<rectangle id="shadow" width="100%" height="100%" padding="4" gap="4" align_items="center" justify_content="center" color="#000000c0" flex_direction="row">
|
||||
<div flex_direction="column">
|
||||
<rectangle padding="16" gap="8" round="32" color="~color_bg" border="2" border_color="~color_accent" justify_content="center">
|
||||
<div flex_direction="column" gap="8">
|
||||
|
||||
@@ -8,5 +8,18 @@
|
||||
<var key="color_accent_20" value="#001c33" /> <!-- 20% brightness -->
|
||||
<var key="color_accent_5" value="#00070d" /> <!-- 5% brightness -->
|
||||
<var key="color_accent_1" value="#000103" /> <!-- 1% brightness -->
|
||||
|
||||
|
||||
<var key="color_danger" value="#ff3300" />
|
||||
<var key="color_danger_translucent" value="#ff330040" />
|
||||
<var key="color_danger_20" value="#330a00" /> <!-- 20% brightness -->
|
||||
<var key="color_danger_5" value="#0d0200" /> <!-- 5% brightness -->
|
||||
<var key="color_danger_1" value="#030000" /> <!-- 1% brightness -->
|
||||
|
||||
<var key="color_faded" value="#668299" />
|
||||
<var key="color_faded_translucent" value="#66829940" />
|
||||
<var key="color_faded_20" value="#141a1f" /> <!-- 20% brightness -->
|
||||
<var key="color_faded_5" value="#050708" /> <!-- 5% brightness -->
|
||||
<var key="color_faded_1" value="#010102" /> <!-- 1% brightness -->
|
||||
</theme>
|
||||
</layout>
|
||||
</layout>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<layout>
|
||||
<include src="theme.xml" />
|
||||
|
||||
<theme>
|
||||
<var key="border" value="2" />
|
||||
<var key="kbd_color" value="#a6da95" />
|
||||
@@ -15,30 +17,26 @@
|
||||
</theme>
|
||||
|
||||
<macro name="button_style"
|
||||
margin="2" overflow="hidden" box_sizing="border_box" align_items="center" justify_content="center"
|
||||
border_color="#0044CC" border="2" round="8" color="#000A1C" color2="#000002" gradient="vertical" />
|
||||
margin="2" overflow="hidden" box_sizing="border_box"
|
||||
border_color="~color_accent_translucent" border="2" round="8" color="~color_accent_5" color2="~color_accent_1" gradient="vertical"
|
||||
align_items="center" justify_content="center" />
|
||||
|
||||
<template name="Device">
|
||||
<div margin="4">
|
||||
<sprite width="${size}" height="${size}" src="${src}" />
|
||||
<div margin_top="10" margin_left="-31">
|
||||
<label _source="battery" _device="${device}" size="18" shadow="#000000" weight="bold" />
|
||||
<div id="dev_${idx}" margin="2" display="none">
|
||||
<sprite id="dev_${idx}_sprite" width="32" height="32" src="${src}" />
|
||||
<!-- div margin_top="10" margin_left="-31" -->
|
||||
<div position="absolute" margin_top="6" margin_left="4">
|
||||
<label _source="battery" _device="${idx}" size="18" shadow="#000000" weight="bold" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="SpriteButton">
|
||||
<Button id="${id}" macro="button_style" tooltip="${tooltip}" _press="${press}">
|
||||
<sprite width="40" height="40" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="Overlay">
|
||||
<Button macro="button_style" padding="4" id="overlay_${idx}" text="WLX-${idx}" tooltip="Toggle for current set" _press="::EditModeOverlayToggle ${idx}" />
|
||||
</template>
|
||||
|
||||
<template name="Set">
|
||||
<Button macro="button_style" id="set_${handle}" _press="::SetToggle ${handle}" tooltip="Switch to set" tooltip_side="top">
|
||||
<Button macro="button_style" id="set_${idx}" _press="::SetToggle ${idx}" tooltip="Switch to set" tooltip_side="top">
|
||||
<sprite width="40" height="40" color="~set_color" src="watch/set2.svg" />
|
||||
<div position="absolute" margin_top="9">
|
||||
<label text="${display}" size="24" color="#00050F" weight="bold" />
|
||||
@@ -46,60 +44,67 @@
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<!-- Elements with id="norm_*" show in normal mode. -->
|
||||
<!-- Elements with id="edit_*" show in edit mode. -->
|
||||
<elements>
|
||||
<div width="460" height="260" padding="30" interactable="0">
|
||||
<rectangle width="100%" height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="~color_bg" justify_content="space_between">
|
||||
<div width="100%" flex_direction="row" id="norm_top">
|
||||
<Device src="watch/hmd.svg" size="40" device="0" />
|
||||
<Device src="watch/controller_l.svg" size="36" device="1" />
|
||||
<Device src="watch/controller_r.svg" size="36" device="2" />
|
||||
<Device src="watch/track3.svg" size="40" device="3" />
|
||||
<Device src="watch/track3.svg" size="40" device="4" />
|
||||
<Device src="watch/track3.svg" size="40" device="5" />
|
||||
</div>
|
||||
<div width="100%" flex_direction="row" id="norm_pane">
|
||||
<div width="460" height="260" padding="30" interactable="0" flex_direction="column">
|
||||
<div padding="2" flex_direction="row" id="devices">
|
||||
<!-- Src here may be changed, but maintain order: HMD, Left, Right, Tracker -->
|
||||
<Device src="watch/hmd.svg" idx="0" />
|
||||
<Device src="watch/controller_l.svg" idx="1" />
|
||||
<Device src="watch/controller_r.svg" idx="2" />
|
||||
<Device src="watch/track.svg" idx="3" />
|
||||
<!-- Will populate additional <Device> tags at runtime -->
|
||||
</div>
|
||||
<rectangle height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="#000000c0" border_color="~color_accent" border="2" round="8" justify_content="space_between">
|
||||
<div flex_direction="row" id="norm_pane">
|
||||
<div flex_direction="column" padding="4">
|
||||
<label text="23:59" _source="clock" _display="time" color="~clock0_color" size="~clock0_size" weight="bold" />
|
||||
<label text="22/2/2022" _source="clock" _display="date" color="~clock0_color" size="~clock0_date_size" weight="bold" />
|
||||
<div width="100%" padding="2" />
|
||||
<label text="Tuesday" _source="clock" _display="dow" color="~clock0_color" size="~clock0_dow_size" weight="bold" />
|
||||
<div padding="2" gap="2" flex_direction="column">
|
||||
<label text="22/2/2022" _source="clock" _display="date" color="~clock0_color" size="~clock0_date_size" weight="bold" />
|
||||
<label text="Tuesday" _source="clock" _display="dow" color="~clock0_color" size="~clock0_dow_size" weight="bold" />
|
||||
</div>
|
||||
</div>
|
||||
<div width="10" height="100%" />
|
||||
<div flex_direction="column" padding="4">
|
||||
<!-- Timezone names here are only placeholders. Set your timezones via ~/.config/wlxoverlay/conf.d -->
|
||||
<div width="100%" padding="2" />
|
||||
<div padding="2" />
|
||||
<label text="Paris" _source="clock" _display="name" _timezone="0" color="~clock_alt1_color" size="~clock_alt_tz_size" weight="bold" />
|
||||
<label text="23:59" _source="clock" _display="time" _timezone="0" color="~clock_alt1_color" size="~clock_alt_size" weight="bold" />
|
||||
<div width="100%" padding="2" />
|
||||
<div padding="2" />
|
||||
<label text="New York" _source="clock" _display="name" _timezone="1" color="~clock_alt2_color" size="~clock_alt_tz_size" weight="bold" />
|
||||
<label text="23:59" _source="clock" _display="time" _timezone="1" color="~clock_alt2_color" size="~clock_alt_size" weight="bold" />
|
||||
</div>
|
||||
<div flex_direction="column" padding="4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div width="100%" flex_direction="column" id="edit_pane" display="none" >
|
||||
<div flex_direction="column" id="edit_pane" display="none" >
|
||||
<div flex_direction="column" padding="4" align_items="center" justify_content="center">
|
||||
<label text="Overlays can now be moved and tuned individually." />
|
||||
<label text="Control which overlays are visible on this set:" />
|
||||
</div>
|
||||
<div flex_direction="row" flex_wrap="wrap" padding="4" align_items="center" justify_content="center" id="toolbox">
|
||||
<Button macro="button_style" padding="4" translation="Keyboard" tooltip="Toggle for current set" _press="::OverlayToggle kbd" />
|
||||
<!-- Will populate <Overlay> tags at runtime -->
|
||||
<!-- Will populate additional <Overlay> tags at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
<div width="100%" flex_direction="row">
|
||||
<div flex_direction="row">
|
||||
<div id="norm_dash">
|
||||
<Button macro="button_style" _press="::DashToggle" tooltip="Dashboard" tooltip_side="top" id="norm_dash">
|
||||
<sprite color="~set_color" width="40" height="40" src="watch/home.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
<div id="edit_delete">
|
||||
<Button macro="button_style" _press="::EditModeDeleteDown" _release="::EditModeDeleteUp" tooltip="Long Press: Delete Set" tooltip_side="top" border_color="#CC0000" color="#110000" color2="#020000" >
|
||||
<div id="edit_delete" display="none">
|
||||
<Button macro="button_style" _press="::EditModeDeleteDown" _release="::EditModeDeleteUp" tooltip="Long Press: Delete Set" tooltip_side="top" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1" >
|
||||
<sprite color="~set_color" width="40" height="40" src="edit/delete.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
<div id="sets">
|
||||
<!-- Will populate <Set> tags at runtime -->
|
||||
<Set idx="0" display="1" />
|
||||
<!-- Will populate additional <Set> tags at runtime -->
|
||||
</div>
|
||||
<div id="edit_add">
|
||||
<div id="edit_add" display="none">
|
||||
<Button macro="button_style" _press="::EditModeAddSet" tooltip="Add a new set" tooltip_side="top">
|
||||
<sprite color="~set_color" width="40" height="40" src="edit/add.svg" />
|
||||
</Button>
|
||||
|
||||
@@ -1 +1,41 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="white" d="M7.5 18q-1.65 0-2.825-1.175T3.5 14V9.925q0-1.275.8-2.238T6.35 6.5q1.425-.275 2.825-.387T12 6t2.838.113t2.812.387q1.25.25 2.05 1.2t.8 2.225V14q0 1.65-1.175 2.825T16.5 18h-1q-.325 0-.65-.038t-.625-.162l-1.6-.55q-.3-.125-.625-.125t-.625.125l-1.6.55q-.3.125-.625.162T8.5 18zm0-2h1q.175 0 .338-.025t.312-.075q.725-.225 1.413-.475t1.437-.25t1.45.238t1.4.487q.15.05.313.075T15.5 16h1q.825 0 1.413-.587T18.5 14V9.925q0-.55-.35-.95t-.875-.525q-1.3-.275-2.613-.362T12 8t-2.65.1t-2.625.35q-.525.1-.875.513t-.35.962V14q0 .825.588 1.413T7.5 16M1 14v-4h1.5v4zm20.5 0v-4H23v4zm-14 2q-.825 0-1.412-.587T5.5 14V9.925q0-.55.35-.962t.875-.513Q8.05 8.2 9.35 8.1T12 8t2.663.088t2.612.362q.525.125.875.525t.35.95V14q0 .825-.587 1.413T16.5 16h-1q-.175 0-.337-.025t-.313-.075q-.7-.25-1.4-.488T12 15.176t-1.437.25t-1.413.475q-.15.05-.312.075T8.5 16z"/></svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="hmd.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="12.462757"
|
||||
inkscape:cx="21.54419"
|
||||
inkscape:cy="10.832274"
|
||||
inkscape:window-width="1277"
|
||||
inkscape:window-height="1398"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1" />
|
||||
<!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
||||
<path
|
||||
fill="white"
|
||||
d="m 5.7477204,20.336375 c -1.5283351,0 -2.8366825,-0.544181 -3.9250422,-1.63254 C 0.73431841,17.615476 0.19013847,16.307128 0.19013847,14.778793 V 9.1170061 c 0,-1.1809862 0.37050551,-2.2174752 1.11151643,-3.1094671 C 2.0426657,5.1155471 2.9920861,4.5658096 4.1499156,4.3583266 5.4698413,4.1036041 6.7781887,3.9243721 8.0749578,3.8206305 9.3717264,3.716889 10.680074,3.6645552 12,3.6636289 c 1.319926,-9.264e-4 2.634294,0.051408 3.943104,0.1570016 1.308811,0.1055941 2.611137,0.2848261 3.90698,0.5376961 1.15783,0.2315659 2.107251,0.7873241 2.848261,1.6672746 0.741011,0.8799504 1.111517,1.9104187 1.111517,3.0914049 v 5.6617869 c 0,1.528335 -0.544181,2.836683 -1.63254,3.925042 -1.088359,1.088359 -2.396707,1.63254 -3.925042,1.63254 h -1.389396 c -0.301036,0 -0.602071,-0.0176 -0.903107,-0.0528 -0.301036,-0.03519 -0.590493,-0.110221 -0.868372,-0.225083 L 12.868372,19.294328 C 12.590493,19.17855 12.301036,19.120653 12,19.120653 c -0.301036,0 -0.590493,0.0579 -0.868372,0.173675 l -2.2230329,0.764167 c -0.2778791,0.115783 -0.5673365,0.19081 -0.8683722,0.225083 -0.3010357,0.03427 -0.6020713,0.05187 -0.9031071,0.0528 z m 0,-2.778791 h 1.3893954 c 0.1620962,0 0.3186347,-0.01153 0.4696157,-0.03473 0.150981,-0.02316 0.2954782,-0.0579 0.4334914,-0.104205 0.6715411,-0.208409 1.325946,-0.428396 1.9632161,-0.659963 0.63727,-0.231566 1.30279,-0.347349 1.996561,-0.347349 0.693771,0 1.365313,0.110221 2.014623,0.330676 0.649311,0.220452 1.297696,0.445996 1.945154,0.676636 0.13894,0.04631 0.283899,0.08104 0.434881,0.104205 0.150981,0.02316 0.307056,0.03473 0.468226,0.03473 h 1.389396 c 0.764167,0 1.418572,-0.271859 1.963215,-0.815576 0.544643,-0.543716 0.816502,-1.198121 0.815576,-1.963215 V 9.1170061 c 0,-0.5094451 -0.162097,-0.9494202 -0.486289,-1.3199257 C 20.22059,7.4265749 19.81535,7.1834307 19.329061,7.0676478 18.124918,6.8129253 16.914754,6.6452715 15.698571,6.5646866 14.482387,6.4841017 13.249529,6.4433461 12,6.4424198 10.750471,6.4414935 9.5231705,6.4878068 8.318102,6.5813593 7.113033,6.6749119 5.897312,6.8370081 4.6709389,7.0676478 4.1846505,7.1602742 3.7794101,7.3978608 3.4552178,7.7804076 3.1310256,8.1629545 2.9689294,8.6084873 2.9689294,9.1170061 v 5.6617869 c 0,0.764167 0.2723215,1.418572 0.8169646,1.963215 0.544643,0.544643 1.1985852,0.816502 1.9618264,0.815576 m 0,0 c -0.7641675,0 -1.4181097,-0.271859 -1.9618264,-0.815576 C 3.2421772,16.198292 2.9698557,15.543887 2.9689294,14.778793 V 9.1170061 c 0,-0.5094451 0.1620962,-0.9549778 0.4862884,-1.3365985 C 3.7794101,7.398787 4.1846505,7.1612003 4.6709389,7.0676478 5.8982382,6.8360818 7.1139592,6.6739858 8.318102,6.5813593 9.5222452,6.4887329 10.749544,6.4424198 12,6.4424198 c 1.250456,0 2.483776,0.040755 3.69996,0.1222668 1.216184,0.081512 2.425885,0.2491649 3.629101,0.5029612 0.486289,0.1157825 0.891529,0.3589271 1.215721,0.7294326 0.324192,0.3705055 0.486289,0.8104806 0.486289,1.3199257 v 5.6617869 c 0,0.764167 -0.271859,1.418572 -0.815576,1.963215 -0.543716,0.544643 -1.198121,0.816502 -1.963215,0.815576 h -1.389396 c -0.162096,0 -0.318171,-0.01153 -0.468226,-0.03473 -0.150055,-0.02316 -0.295015,-0.0579 -0.434881,-0.104205 C 15.311392,17.187078 14.663008,16.96107 14.014623,16.740619 13.366238,16.520168 12.694698,16.41087 12,16.412722 c -0.694698,0.0018 -1.360218,0.11764 -1.996561,0.347349 -0.6363434,0.229713 -1.2907487,0.449701 -1.9632161,0.659962 -0.1389395,0.04631 -0.2834367,0.08104 -0.4334914,0.104205 -0.1500547,0.02316 -0.3065933,0.03427 -0.4696157,0.03335 z"
|
||||
id="path1"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.3894"
|
||||
sodipodi:nodetypes="ssssscssscsssssssccsccscscsscssscsssscsscssscsssscsscsscssscsssscsscssscscs" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 4.7 KiB |
@@ -4,7 +4,8 @@ use std::{collections::VecDeque, time::Instant};
|
||||
|
||||
use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
||||
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use idmap_derive::IntegerId;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
||||
|
||||
use crate::overlays::anchor::ANCHOR_NAME;
|
||||
@@ -12,7 +13,7 @@ use crate::state::{AppSession, AppState};
|
||||
use crate::subsystem::hid::WheelDelta;
|
||||
use crate::subsystem::input::KeyboardFocus;
|
||||
use crate::windowing::manager::OverlayWindowManager;
|
||||
use crate::windowing::window::{self, OverlayWindowData, realign};
|
||||
use crate::windowing::window::{self, realign, OverlayWindowData};
|
||||
use crate::windowing::{OverlayID, OverlaySelector};
|
||||
|
||||
use super::task::TaskType;
|
||||
@@ -31,7 +32,7 @@ pub struct TrackedDevice {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntegerId)]
|
||||
pub enum TrackedDeviceRole {
|
||||
None,
|
||||
Hmd,
|
||||
|
||||
@@ -239,7 +239,8 @@ impl OpenVrInputSource {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_devices(&mut self, system: &mut SystemManager, app: &mut AppState) {
|
||||
pub fn update_devices(&mut self, system: &mut SystemManager, app: &mut AppState) -> bool {
|
||||
let old_len = app.input_state.devices.len();
|
||||
app.input_state.devices.clear();
|
||||
for idx in 0..TrackedDeviceIndex::MAX {
|
||||
let device = TrackedDeviceIndex::new(idx as _).unwrap(); // safe
|
||||
@@ -282,6 +283,8 @@ impl OpenVrInputSource {
|
||||
.then((a.role as u8).cmp(&(b.role as u8)))
|
||||
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
||||
});
|
||||
|
||||
old_len != app.input_state.devices.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,10 @@ pub fn openvr_run(
|
||||
}
|
||||
|
||||
if next_device_update <= Instant::now() {
|
||||
input_source.update_devices(&mut system_mgr, &mut app);
|
||||
let changed = input_source.update_devices(&mut system_mgr, &mut app);
|
||||
if changed {
|
||||
overlays.devices_changed(&mut app)?;
|
||||
}
|
||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use glam::{Affine3A, Quat, Vec3, bool};
|
||||
use glam::{bool, Affine3A, Quat, Vec3};
|
||||
use libmonado as mnd;
|
||||
use openxr::{self as xr, Quaternionf, Vector2f, Vector3f};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
state::{AppSession, AppState},
|
||||
};
|
||||
|
||||
use super::{XrState, helpers::posef_to_transform};
|
||||
use super::{helpers::posef_to_transform, XrState};
|
||||
|
||||
static CLICK_TIMES: [Duration; 3] = [
|
||||
Duration::ZERO,
|
||||
@@ -247,7 +247,8 @@ impl OpenXrInputSource {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_devices(app: &mut AppState, monado: &mut mnd::Monado) {
|
||||
pub fn update_devices(app: &mut AppState, monado: &mut mnd::Monado) -> bool {
|
||||
let old_len = app.input_state.devices.len();
|
||||
app.input_state.devices.clear();
|
||||
|
||||
let roles = [
|
||||
@@ -294,6 +295,8 @@ impl OpenXrInputSource {
|
||||
.then((a.role as u8).cmp(&(b.role as u8)))
|
||||
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
||||
});
|
||||
|
||||
old_len != app.input_state.devices.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,10 @@ pub fn openxr_run(
|
||||
if next_device_update <= Instant::now()
|
||||
&& let Some(monado) = &mut monado
|
||||
{
|
||||
OpenXrInputSource::update_devices(&mut app, monado);
|
||||
let changed = OpenXrInputSource::update_devices(&mut app, monado);
|
||||
if changed {
|
||||
overlays.devices_changed(&mut app)?;
|
||||
}
|
||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use button::setup_custom_button;
|
||||
use glam::{Affine2, Vec2, vec2};
|
||||
use glam::{vec2, Affine2, Vec2};
|
||||
use label::setup_custom_label;
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
drawing,
|
||||
event::{
|
||||
Event as WguiEvent, EventAlterables, EventCallback, EventListenerID, EventListenerKind,
|
||||
Event as WguiEvent, EventCallback, EventListenerID, EventListenerKind,
|
||||
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
||||
MouseMotionEvent, MouseUpEvent, MouseWheelEvent, StyleSetRequest,
|
||||
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
|
||||
},
|
||||
gfx::cmd::WGfxClearMode,
|
||||
layout::{Layout, LayoutParams, WidgetID},
|
||||
parser::{CustomAttribsInfoOwned, ParserState},
|
||||
renderer_vk::context::Context as WguiContext,
|
||||
taffy,
|
||||
widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle},
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -24,7 +23,7 @@ use crate::{
|
||||
state::AppState,
|
||||
subsystem::hid::WheelDelta,
|
||||
windowing::backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform,
|
||||
ui_transform, FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -221,15 +220,6 @@ impl<S: 'static> GuiPanel<S> {
|
||||
) -> Option<EventListenerID> {
|
||||
self.layout.add_event_listener(widget_id, kind, callback)
|
||||
}
|
||||
|
||||
pub fn widget_set_display(
|
||||
&self,
|
||||
widget_id: WidgetID,
|
||||
display: taffy::Display,
|
||||
alterables: &mut EventAlterables,
|
||||
) {
|
||||
alterables.set_style(widget_id, StyleSetRequest::Display(display));
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||
|
||||
@@ -5,19 +5,24 @@ use std::{
|
||||
};
|
||||
|
||||
use glam::{Affine3A, Vec3, Vec3A};
|
||||
use idmap::DirectIdMap;
|
||||
use wgui::{
|
||||
components::button::ComponentButton,
|
||||
event::{CallbackDataCommon, EventAlterables, EventCallback},
|
||||
event::{CallbackDataCommon, EventAlterables, EventCallback, StyleSetRequest},
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::Fetchable,
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
taffy,
|
||||
widget::EventResult,
|
||||
widget::{sprite::WidgetSprite, EventResult},
|
||||
};
|
||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
||||
|
||||
use crate::{
|
||||
backend::task::{ManagerTask, TaskType},
|
||||
backend::{
|
||||
input::TrackedDeviceRole,
|
||||
task::{ManagerTask, TaskType},
|
||||
},
|
||||
gui::{
|
||||
panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams, OnCustomAttribFunc},
|
||||
timer::GuiTimer,
|
||||
@@ -34,6 +39,7 @@ use crate::{
|
||||
|
||||
pub const WATCH_NAME: &str = "watch";
|
||||
const MAX_TOOLBOX_BUTTONS: usize = 16;
|
||||
const MAX_DEVICES: usize = 9;
|
||||
|
||||
#[derive(Default)]
|
||||
struct WatchState {
|
||||
@@ -43,6 +49,8 @@ struct WatchState {
|
||||
overlay_metas: Vec<OverlayMeta>,
|
||||
edit_mode_widgets: Vec<(WidgetID, bool)>,
|
||||
edit_add_widget: WidgetID,
|
||||
device_role_icons: DirectIdMap<TrackedDeviceRole, CustomGlyphData>,
|
||||
devices: Vec<(WidgetID, WidgetID)>,
|
||||
num_sets: usize,
|
||||
delete: LongPressButtonState,
|
||||
}
|
||||
@@ -127,30 +135,85 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
} else if id.starts_with("edit_") {
|
||||
state.edit_mode_widgets.push((widget, true));
|
||||
} else if &*id == "sets" {
|
||||
for idx in 0..MAX_OVERLAY_SETS {
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("display".into(), (idx + 1).to_string().into());
|
||||
params.insert("handle".into(), idx.to_string().into());
|
||||
parser_state
|
||||
.instantiate_template(doc_params, "Set", layout, widget, params)?;
|
||||
let node = layout.state.nodes[widget];
|
||||
let num_children = layout.state.tree.children(node).iter().len();
|
||||
|
||||
let button_id = format!("set_{idx}");
|
||||
let component =
|
||||
parser_state.fetch_component_as::<ComponentButton>(&button_id)?;
|
||||
state.set_buttons.push(component);
|
||||
for idx in 0..MAX_OVERLAY_SETS {
|
||||
if idx >= num_children {
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("display".into(), (idx + 1).to_string().into());
|
||||
params.insert("idx".into(), idx.to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
doc_params, "Set", layout, widget, params,
|
||||
)?;
|
||||
}
|
||||
|
||||
let comp = parser_state
|
||||
.fetch_component_as::<ComponentButton>(&format!("set_{idx}"))?;
|
||||
state.set_buttons.push(comp);
|
||||
}
|
||||
} else if &*id == "toolbox" {
|
||||
for idx in 0..MAX_TOOLBOX_BUTTONS {
|
||||
let overlay_id = format!("overlay_{idx}");
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("idx".into(), idx.to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
doc_params, "Overlay", layout, widget, params,
|
||||
)?;
|
||||
let node = layout.state.nodes[widget];
|
||||
let num_children = layout.state.tree.children(node).iter().len() - 1; // -1 for keyboard
|
||||
|
||||
let component =
|
||||
parser_state.fetch_component_as::<ComponentButton>(&overlay_id)?;
|
||||
state.overlay_buttons.push(component);
|
||||
for idx in 0..MAX_TOOLBOX_BUTTONS {
|
||||
if idx >= num_children {
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("idx".into(), idx.to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
doc_params, "Overlay", layout, widget, params,
|
||||
)?;
|
||||
}
|
||||
|
||||
let comp = parser_state
|
||||
.fetch_component_as::<ComponentButton>(&format!("overlay_{idx}"))?;
|
||||
state.overlay_buttons.push(comp);
|
||||
}
|
||||
} else if id.starts_with("dev_") && id.ends_with("_sprite") {
|
||||
// store device icons from xml
|
||||
let id_n = id
|
||||
.replace("dev_", "")
|
||||
.replace("_sprite", "")
|
||||
.parse::<u64>()?;
|
||||
|
||||
let role = match id_n {
|
||||
0 => TrackedDeviceRole::Hmd,
|
||||
1 => TrackedDeviceRole::LeftHand,
|
||||
2 => TrackedDeviceRole::RightHand,
|
||||
3 => TrackedDeviceRole::Tracker,
|
||||
_ => return Ok(()), // not parsing the first 4 elems
|
||||
};
|
||||
|
||||
let sprite = layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(widget)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("{id} is expected to be a sprite, but it isn't.")
|
||||
})?;
|
||||
|
||||
let src = sprite.params.glyph_data.clone().ok_or_else(|| {
|
||||
anyhow::anyhow!("{id} is expected to have a src, but it doesn't.")
|
||||
})?;
|
||||
|
||||
state.device_role_icons.insert(role, src);
|
||||
} else if &*id == "devices" {
|
||||
let node = layout.state.nodes[widget];
|
||||
let num_children = layout.state.tree.children(node).iter().len();
|
||||
|
||||
for idx in 0..MAX_DEVICES {
|
||||
if idx >= num_children {
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("idx".into(), idx.to_string().into());
|
||||
params.insert("src".into(), "".to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
doc_params, "Device", layout, widget, params,
|
||||
)?;
|
||||
}
|
||||
|
||||
let div = parser_state.get_widget_id(&format!("dev_{idx}"))?;
|
||||
let spr = parser_state.get_widget_id(&format!("dev_{idx}_sprite"))?;
|
||||
state.devices.push((div, spr));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -161,9 +224,9 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
},
|
||||
)?;
|
||||
|
||||
panel.on_notify = Some(Box::new(|panel, _app, event_data| {
|
||||
panel.on_notify = Some(Box::new(|panel, app, event_data| {
|
||||
let mut alterables = EventAlterables::default();
|
||||
let mut common = CallbackDataCommon {
|
||||
let mut com = CallbackDataCommon {
|
||||
alterables: &mut alterables,
|
||||
state: &panel.layout.state,
|
||||
};
|
||||
@@ -171,31 +234,34 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
match event_data {
|
||||
OverlayEventData::ActiveSetChanged(current_set) => {
|
||||
if let Some(old_set) = panel.state.current_set.take() {
|
||||
panel.state.set_buttons[old_set].set_sticky_state(&mut common, false);
|
||||
panel.state.set_buttons[old_set].set_sticky_state(&mut com, false);
|
||||
}
|
||||
if let Some(new_set) = current_set {
|
||||
panel.state.set_buttons[new_set].set_sticky_state(&mut common, true);
|
||||
panel.state.set_buttons[new_set].set_sticky_state(&mut com, true);
|
||||
}
|
||||
panel.state.current_set = current_set;
|
||||
}
|
||||
OverlayEventData::NumSetsChanged(num_sets) => {
|
||||
panel.state.num_sets = num_sets;
|
||||
for i in 0..MAX_OVERLAY_SETS {
|
||||
let comp = panel.state.set_buttons[i].clone();
|
||||
for (i, comp) in panel.state.set_buttons.iter().enumerate() {
|
||||
let rect_id = comp.get_rect();
|
||||
let display = if i < num_sets {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
panel.widget_set_display(rect_id, display, common.alterables);
|
||||
com.alterables
|
||||
.set_style(rect_id, StyleSetRequest::Display(display));
|
||||
}
|
||||
let display = if num_sets < 7 {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
panel.widget_set_display(panel.state.edit_add_widget, display, common.alterables);
|
||||
com.alterables.set_style(
|
||||
panel.state.edit_add_widget,
|
||||
StyleSetRequest::Display(display),
|
||||
);
|
||||
}
|
||||
OverlayEventData::EditModeChanged(edit_mode) => {
|
||||
for (w, e) in &panel.state.edit_mode_widgets {
|
||||
@@ -204,26 +270,49 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
panel.widget_set_display(*w, display, common.alterables);
|
||||
com.alterables
|
||||
.set_style(*w, StyleSetRequest::Display(display));
|
||||
}
|
||||
let display = if edit_mode && panel.state.num_sets < 7 {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
panel.widget_set_display(panel.state.edit_add_widget, display, common.alterables);
|
||||
com.alterables.set_style(
|
||||
panel.state.edit_add_widget,
|
||||
StyleSetRequest::Display(display),
|
||||
);
|
||||
}
|
||||
OverlayEventData::OverlaysChanged(metas) => {
|
||||
panel.state.overlay_metas = metas;
|
||||
for (idx, btn) in panel.state.overlay_buttons.iter().enumerate() {
|
||||
let display = if let Some(meta) = panel.state.overlay_metas.get(idx) {
|
||||
btn.set_text(&mut common, Translation::from_raw_text(&meta.name));
|
||||
btn.set_text(&mut com, Translation::from_raw_text(&meta.name));
|
||||
//TODO: add category icons
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
panel.widget_set_display(btn.get_rect(), display, common.alterables);
|
||||
com.alterables
|
||||
.set_style(btn.get_rect(), StyleSetRequest::Display(display));
|
||||
}
|
||||
}
|
||||
OverlayEventData::DevicesChanged => {
|
||||
log::info!("dev");
|
||||
for (i, (div, s)) in panel.state.devices.iter().enumerate() {
|
||||
if let Some(dev) = app.input_state.devices.get(i)
|
||||
&& let Some(glyph) = panel.state.device_role_icons.get(dev.role)
|
||||
&& let Some(mut s) = panel.layout.state.widgets.get_as::<WidgetSprite>(*s)
|
||||
{
|
||||
log::info!("dev {i} ok");
|
||||
s.params.glyph_data = Some(glyph.clone());
|
||||
com.alterables
|
||||
.set_style(*div, StyleSetRequest::Display(taffy::Display::Flex));
|
||||
} else {
|
||||
log::info!("dev {i} nok");
|
||||
com.alterables
|
||||
.set_style(*div, StyleSetRequest::Display(taffy::Display::None));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ use crate::{
|
||||
},
|
||||
state::AppState,
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector,
|
||||
backend::{OverlayEventData, OverlayMeta},
|
||||
set::OverlayWindowSet,
|
||||
snap_upright,
|
||||
window::{OverlayCategory, OverlayWindowData},
|
||||
OverlayID, OverlaySelector,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -106,6 +106,7 @@ where
|
||||
for ev in [
|
||||
OverlayEventData::NumSetsChanged(me.sets.len()),
|
||||
OverlayEventData::EditModeChanged(false),
|
||||
OverlayEventData::DevicesChanged,
|
||||
] {
|
||||
watch.config.backend.notify(app, ev)?;
|
||||
}
|
||||
@@ -470,4 +471,15 @@ impl<T> OverlayWindowManager<T> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn devices_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
||||
watch
|
||||
.config
|
||||
.backend
|
||||
.notify(app, OverlayEventData::DevicesChanged)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user