watch rework
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
"HIDE_GRAB_HELP": "Greif-Hilfe ausblenden",
|
||||
"ANIMATION_SPEED": "UI-Animationsgeschwindigkeit",
|
||||
"ROUND_MULTIPLIER": "UI-Kantenrundung",
|
||||
"SINGLE_SET_MODE": "Einzelnes Modus",
|
||||
"USE_SKYBOX": "Skybox aktivieren",
|
||||
"USE_PASSTHROUGH": "Passthrough aktivieren",
|
||||
"CLOCK_12H": "12-Stunden-Uhr",
|
||||
@@ -48,7 +47,6 @@
|
||||
"SCREEN_RENDER_DOWN": "Bildschirm bei niedrigerer Auflösung rendern",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Behebt hochstehende Bildschirme auf einigen Desktops",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Aktivieren Sie dies, wenn Sie 2 Cursor sehen",
|
||||
"SINGLE_SET_MODE_HELP": "Optimieren Sie die Anzeige für die Arbeit mit einem einzelnen Monitor",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Analoge Trigger-Empfindlichkeit",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Muss niedriger als Klick sein",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Hilft bei der Präzision von Doppelklicks",
|
||||
@@ -102,4 +100,4 @@
|
||||
},
|
||||
"TERMINATE_PROCESS": "Prozess beenden",
|
||||
"GAME_LAUNCHED": "Spiel gestartet"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"HIDE_GRAB_HELP": "Hide grab help",
|
||||
"ANIMATION_SPEED": "UI Animation speed",
|
||||
"ROUND_MULTIPLIER": "UI Edge roundness",
|
||||
"SINGLE_SET_MODE": "Single set mode",
|
||||
"SETS_ON_WATCH": "Sets on watch",
|
||||
"USE_SKYBOX": "Enable skybox",
|
||||
"USE_PASSTHROUGH": "Enable passthrough",
|
||||
"CLOCK_12H": "12-hour clock",
|
||||
@@ -49,7 +49,6 @@
|
||||
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Fixes upright screens on some desktops",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Enable this if you see 2 cursors",
|
||||
"SINGLE_SET_MODE_HELP": "Optimize the watch for working with a single set",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Analog trigger sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Must be lower than click",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Helps with double-click precision",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"HIDE_GRAB_HELP": "掴み操作のヘルプを非表示にする",
|
||||
"ANIMATION_SPEED": "UIアニメーション速度",
|
||||
"ROUND_MULTIPLIER": "UI エッジの丸み",
|
||||
"SINGLE_SET_MODE": "単一設定モード",
|
||||
"USE_SKYBOX": "スカイボックスを有効にする",
|
||||
"USE_PASSTHROUGH": "パススルーを有効にする",
|
||||
"CLOCK_12H": "12時間制",
|
||||
@@ -48,7 +47,6 @@
|
||||
"SCREEN_RENDER_DOWN": "低い解像度で画面をレンダリングする",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "一部のデスクトップで縦向きの画面を修正",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "2つのカーソルが表示される場合は、これを有効にします",
|
||||
"SINGLE_SET_MODE_HELP": "シングルセットでの作業用に最適化",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "アナログトリガの感度",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "クリックより低くする必要があります",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "ダブルクリックの精度向上に役立ちます",
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"HIDE_GRAB_HELP": "Ukryj pomoc dotyczącą chwytania",
|
||||
"ANIMATION_SPEED": "Prędkość animacji UI",
|
||||
"ROUND_MULTIPLIER": "Zaokrąglenie krawędzi UI",
|
||||
"SINGLE_SET_MODE": "Tryb pojedynczego zestawu",
|
||||
"USE_SKYBOX": "Włącz niebo",
|
||||
"USE_PASSTHROUGH": "Włącz passthrough",
|
||||
"CLOCK_12H": "Zegar 12-godzinny",
|
||||
@@ -42,7 +41,6 @@
|
||||
"SCREEN_RENDER_DOWN": "Renderuj ekran w niższej rozdzielczości",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Naprawia pionowe ekrany na niektórych komputerach",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Włącz to, jeśli widzisz 2 kursory",
|
||||
"SINGLE_SET_MODE_HELP": "Zoptymalizuj oglądanie dla pracy z jednym zestawem",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Czułość analogowego spustu",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Musi być niższa niż kliknięcie",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Pomaga w precyzji podwójnego kliknięcia",
|
||||
@@ -102,4 +100,4 @@
|
||||
},
|
||||
"TERMINATE_PROCESS": "Zakończ proces",
|
||||
"GAME_LAUNCHED": "Gra uruchomiona"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,22 +36,29 @@ impl<T> Tab<T> for TabSettings<T> {
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
let config = frontend.interface.general_config(data);
|
||||
let mut changed = false;
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::UpdateBool(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_bool(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
Task::UpdateFloat(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_f32(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
Task::UpdateInt(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_i32(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
frontend.interface.config_changed(data);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -70,7 +77,7 @@ enum SettingType {
|
||||
KeyboardSoundEnabled,
|
||||
UprightScreenFix,
|
||||
DoubleCursorFix,
|
||||
SingleSetMode,
|
||||
SetsOnWatch,
|
||||
HideGrabHelp,
|
||||
XrClickSensitivity,
|
||||
XrClickSensitivityRelease,
|
||||
@@ -103,7 +110,7 @@ impl SettingType {
|
||||
Self::KeyboardSoundEnabled => &mut config.keyboard_sound_enabled,
|
||||
Self::UprightScreenFix => &mut config.upright_screen_fix,
|
||||
Self::DoubleCursorFix => &mut config.double_cursor_fix,
|
||||
Self::SingleSetMode => &mut config.single_set_mode,
|
||||
Self::SetsOnWatch => &mut config.sets_on_watch,
|
||||
Self::HideGrabHelp => &mut config.hide_grab_help,
|
||||
Self::AllowSliding => &mut config.allow_sliding,
|
||||
Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode,
|
||||
@@ -158,7 +165,7 @@ impl SettingType {
|
||||
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
||||
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
||||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||
Self::SingleSetMode => Ok("APP_SETTINGS.SINGLE_SET_MODE"),
|
||||
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
|
||||
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
|
||||
@@ -186,7 +193,6 @@ impl SettingType {
|
||||
match self {
|
||||
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||
Self::SingleSetMode => Some("APP_SETTINGS.SINGLE_SET_MODE_HELP"),
|
||||
Self::XrClickSensitivity => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
|
||||
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE_HELP"),
|
||||
Self::FocusFollowsMouseMode => Some("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE_HELP"),
|
||||
@@ -207,7 +213,7 @@ impl SettingType {
|
||||
| Self::RoundMultiplier
|
||||
| Self::UprightScreenFix
|
||||
| Self::DoubleCursorFix
|
||||
| Self::SingleSetMode
|
||||
| Self::SetsOnWatch
|
||||
| Self::UseSkybox
|
||||
| Self::UsePassthrough
|
||||
| Self::ScreenRenderDown => true,
|
||||
@@ -388,7 +394,7 @@ impl<T> TabSettings<T> {
|
||||
checkbox!(mp, c, SettingType::HideGrabHelp);
|
||||
slider_f32!(mp, c, SettingType::AnimationSpeed, 0.5, 5.0, 0.1); // min, max, step
|
||||
slider_f32!(mp, c, SettingType::RoundMultiplier, 0.5, 5.0, 0.1);
|
||||
checkbox!(mp, c, SettingType::SingleSetMode);
|
||||
checkbox!(mp, c, SettingType::SetsOnWatch);
|
||||
checkbox!(mp, c, SettingType::UseSkybox);
|
||||
checkbox!(mp, c, SettingType::UsePassthrough);
|
||||
checkbox!(mp, c, SettingType::Clock12h);
|
||||
|
||||
@@ -166,7 +166,7 @@ pub struct GeneralConfig {
|
||||
pub double_cursor_fix: bool,
|
||||
|
||||
#[serde(default = "def_false")]
|
||||
pub single_set_mode: bool,
|
||||
pub sets_on_watch: bool,
|
||||
|
||||
#[serde(default = "def_false")]
|
||||
pub hide_grab_help: bool,
|
||||
|
||||
@@ -16,6 +16,7 @@ pub trait DashInterface<T> {
|
||||
fn recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()>;
|
||||
fn desktop_finder<'a>(&'a mut self, data: &'a mut T) -> &'a mut DesktopFinder;
|
||||
fn general_config<'a>(&'a mut self, data: &'a mut T) -> &'a mut GeneralConfig;
|
||||
fn config_changed(&mut self, data: &mut T);
|
||||
}
|
||||
|
||||
pub type BoxDashInterface<T> = Box<dyn DashInterface<T>>;
|
||||
|
||||
@@ -178,4 +178,6 @@ impl DashInterface<()> for DashInterfaceEmulated {
|
||||
fn general_config<'a>(&'a mut self, _: &'a mut ()) -> &'a mut crate::config::GeneralConfig {
|
||||
&mut self.general_config
|
||||
}
|
||||
|
||||
fn config_changed(&mut self, _: &mut ()) {}
|
||||
}
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
<!--
|
||||
Variant of the watch with no sets.
|
||||
All overlays are listed on bottom row.
|
||||
-->
|
||||
<layout>
|
||||
<theme>
|
||||
<var key="set_color" value="#cad3f5" />
|
||||
<var key="bgcolor" value="#010206d5" />
|
||||
|
||||
<var key="clock0_color" value="#cad3f5" />
|
||||
<var key="clock0_size" value="46" />
|
||||
<var key="clock0_date_size" value="16" />
|
||||
<var key="clock0_dow_size" value="16" />
|
||||
<var key="clock_alt1_color" value="#8bd5ca" />
|
||||
<var key="clock_alt2_color" value="#b7bdf8" />
|
||||
<var key="clock_alt_size" value="24" />
|
||||
<var key="clock_alt_tz_size" value="14" />
|
||||
</theme>
|
||||
|
||||
<macro name="decorative_rect"
|
||||
padding="8" color="~bgcolor"
|
||||
border="2" border_color="~color_accent" round="8" />
|
||||
|
||||
<macro name="button_style"
|
||||
padding="8"
|
||||
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">
|
||||
<rectangle id="dev_${idx}" macro="decorative_rect" padding_top="4" padding_bottom="4" display="none" align_items="center" gap="8">
|
||||
<sprite id="dev_${idx}_sprite" width="32" height="32" src_builtin="${src}" />
|
||||
<label _source="battery" _device="${idx}" size="24" weight="bold" />
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<template name="Overlay">
|
||||
<Button macro="button_style" id="overlay_${idx}"
|
||||
tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::OverlayToggle ${idx}" _long_release="::SingleSetOverlayReset ${idx}"
|
||||
align_items="center"
|
||||
height="40">
|
||||
<sprite id="overlay_${idx}_sprite" src_builtin="${src}" width="32" height="32" />
|
||||
<label id="overlay_${idx}_label" text="WLX-${idx}" size="18" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
[!!!!!!!!] Disclaimer [!!!!!!!!]
|
||||
Elements with id="norm_*" show in normal mode.
|
||||
Elements with id="edit_*" show in edit mode.
|
||||
-->
|
||||
<elements>
|
||||
<!-- padding="32" is required there (to make room for tooltips) -->
|
||||
<div
|
||||
padding="32" interactable="0"
|
||||
flex_direction="column" gap="8">
|
||||
<!-- Top elements (device battery levels) -->
|
||||
<div id="devices" interactable="0" gap="6" width="100%" max_width="400" flex_direction="row" flex_wrap="wrap">
|
||||
<!-- Src here may be changed, but maintain `TrackedDeviceRole` 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>
|
||||
|
||||
<!-- All other elements inside the container -->
|
||||
<div flex_direction="column" gap="8">
|
||||
<rectangle macro="decorative_rect" flex_direction="row" gap="8">
|
||||
<!-- Clock, date and various timezones -->
|
||||
<div gap="8">
|
||||
<div flex_direction="column">
|
||||
<label text="23:59" _source="clock" _display="time" color="~clock0_color" size="~clock0_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 flex_direction="column" gap="8">
|
||||
<!-- Timezone names here are only placeholders. Set your timezones via ~/.config/wlxoverlay/conf.d -->
|
||||
<div flex_direction="column">
|
||||
<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>
|
||||
<div flex_direction="column">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- Four buttons -->
|
||||
<div flex_direction="column" gap="8">
|
||||
<div gap="8">
|
||||
<Button macro="button_style" _press="::NewMirror" tooltip="WATCH.MIRROR" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~set_color" src="edit/mirror.svg" />
|
||||
</Button>
|
||||
<Button macro="button_style" _press="::CleanupMirrors" tooltip="WATCH.CLEANUP_MIRRORS" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~set_color" src="watch/mirror-off.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
<div gap="8">
|
||||
<Button macro="button_style" _press="::PlayspaceRecenter" tooltip="WATCH.RECENTER" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~set_color" src="watch/recenter.svg" />
|
||||
</Button>
|
||||
<Button macro="button_style" _press="::PlayspaceFixFloor" tooltip="WATCH.FIX_FLOOR" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~set_color" src="watch/fix-floor.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</rectangle>
|
||||
|
||||
<!-- Bottom buttons -->
|
||||
<div id="toolbox-condensed" gap="6" width="100%" max_width="400" flex_direction="row" flex_wrap="wrap">
|
||||
<Button id="btn_dashboard" height="40" macro="button_style" _press="::DashToggle" tooltip="WATCH.DASHBOARD" tooltip_side="top" >
|
||||
<sprite color="~set_color" width="32" height="32" src="watch/wayvr_dashboard_mono.svg" />
|
||||
</Button>
|
||||
<Button id="btn_edit_mode" height="40" macro="button_style" _press="::EditToggle" tooltip="WATCH.EDIT_MODE" tooltip_side="top">
|
||||
<sprite color="~set_color" width="32" height="32" src="watch/edit.svg" />
|
||||
</Button>
|
||||
<Button id="btn_keyboard" height="40" macro="button_style" tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::OverlayToggle kbd" >
|
||||
<sprite src_builtin="watch/keyboard.svg" width="32" height="32" />
|
||||
</Button>
|
||||
<!-- Src here may be changed, but maintain `OverlayCategory` order: Panel, Screen, Mirror, WayVR -->
|
||||
<Overlay src="edit/panel.svg" idx="0" />
|
||||
<Overlay src="edit/screen.svg" idx="1" />
|
||||
<Overlay src="edit/mirror.svg" idx="2" />
|
||||
<Overlay src="edit/wayvr.svg" idx="3" />
|
||||
<!-- Will populate additional <Overlay> tags at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -19,22 +19,52 @@
|
||||
align_items="center" justify_content="center" />
|
||||
|
||||
<template name="Device">
|
||||
<rectangle id="dev_${idx}" macro="decorative_rect" padding_top="4" padding_bottom="4" display="none" align_items="center" gap="8">
|
||||
<sprite id="dev_${idx}_sprite" width="32" height="32" src_builtin="${src}" />
|
||||
<rectangle macro="decorative_rect" padding_top="4" padding_bottom="4" align_items="center" gap="8">
|
||||
<sprite width="32" height="32" src_builtin="${src}" />
|
||||
<label _source="battery" _device="${idx}" size="24" weight="bold" />
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<template name="Overlay">
|
||||
<Button macro="button_style" id="overlay_${idx}"
|
||||
tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::EditModeOverlayToggle ${idx}"
|
||||
align_items="center"
|
||||
height="40">
|
||||
<sprite id="overlay_${idx}_sprite" src_builtin="${src}" width="32" height="32" />
|
||||
<label id="overlay_${idx}_label" text="WLX-${idx}" size="18" />
|
||||
</Button>
|
||||
<template name="Hmd">
|
||||
<Device idx="${idx}" src="watch/hmd.svg" />
|
||||
</template>
|
||||
<template name="LeftHand">
|
||||
<Device idx="${idx}" src="watch/controller_l.svg" />
|
||||
</template>
|
||||
<template name="RightHand">
|
||||
<Device idx="${idx}" src="watch/controller_r.svg" />
|
||||
</template>
|
||||
<template name="Tracker">
|
||||
<Device idx="${idx}" src="watch/track.svg" />
|
||||
</template>
|
||||
|
||||
<template name="Screen">
|
||||
<Button macro="button_style" id="overlay_${idx}" tooltip_str="${name}" _press="::OverlayToggle ${name}">
|
||||
<sprite width="38" height="38" color="~text_color" src_builtin="edit/screen.svg" />
|
||||
<div position="absolute" margin_top="-7" margin_left="-1">
|
||||
<label text="${display}" size="18" color="~color_faded_20" weight="bold" />
|
||||
</div>
|
||||
</Button>
|
||||
</template>
|
||||
<template name="Panel">
|
||||
<Button macro="button_style" id="overlay_${idx}" tooltip_str="${name}" _press="::OverlayToggle ${name}">
|
||||
<sprite width="38" height="38" color="~text_color" src_builtin="edit/panel.svg" />
|
||||
</Button>
|
||||
</template>
|
||||
<template name="Mirror">
|
||||
<Button macro="button_style" id="overlay_${idx}" tooltip_str="${name}" _press="::OverlayToggle ${name}">
|
||||
<sprite width="38" height="38" color="~text_color" src_builtin="edit/mirror.svg" />
|
||||
<div position="absolute" margin_top="5" margin_left="13">
|
||||
<label text="${display}" size="20" color="~color_faded_20" weight="bold" />
|
||||
</div>
|
||||
</Button>
|
||||
</template>
|
||||
<template name="App">
|
||||
<Button macro="button_style" id="overlay_${idx}" tooltip_str="${name}" _press="::OverlayToggle ${name}">
|
||||
<sprite width="38" height="38" color="~text_color" src_ext="${icon}" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="Set">
|
||||
<Button macro="button_style" id="set_${idx}" _press="::SetToggle ${idx}" tooltip="WATCH.SWITCH_TO_SET" tooltip_side="top">
|
||||
<sprite width="40" height="40" color="~text_color" src_builtin="watch/set2.svg" />
|
||||
@@ -44,63 +74,64 @@
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="Clock">
|
||||
<div gap="12" flex_direction="column" padding="4">
|
||||
<div flex_direction="column" >
|
||||
<label text="11:22 PM" _source="clock" _display="time" color="~text_color" size="~clock0_size" weight="bold" align="center" />
|
||||
<div padding_left="2" gap="16" flex_direction="row" justify_content="center">
|
||||
<label text="Tue" _source="clock" _display="dow_short" color="~clock0_color" size="~clock0_dow_size" weight="bold" />
|
||||
<label text="22/2/2022" _source="clock" _display="date" color="~clock0_color" size="~clock0_date_size" weight="bold" />
|
||||
</div>
|
||||
</div>
|
||||
<div flex_direction="row" gap="8" justify_content="space_around">
|
||||
<!-- Timezone names here are only placeholders. Set your timezones via ~/.config/wlxoverlay/conf.d -->
|
||||
<div flex_direction="column">
|
||||
<label text="Paris" _source="clock" _display="name" _timezone="0" color="~clock_alt1_color" size="~clock_alt_tz_size" weight="bold" align="center" />
|
||||
<label text="23:59" _source="clock" _display="time" _timezone="0" color="~clock_alt1_color" size="~clock_alt_size" weight="bold" align="center" />
|
||||
</div>
|
||||
<div flex_direction="column">
|
||||
<label text="New York" _source="clock" _display="name" _timezone="1" color="~clock_alt2_color" size="~clock_alt_tz_size" weight="bold" align="center" />
|
||||
<label text="23:59" _source="clock" _display="time" _timezone="1" color="~clock_alt2_color" size="~clock_alt_size" weight="bold" align="center" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="VerticalSeparator">
|
||||
<rectangle width="2" height="100%" color="~color_accent" />
|
||||
</template>
|
||||
|
||||
<!--
|
||||
[!!!!!!!!] Disclaimer [!!!!!!!!]
|
||||
Elements with id="norm_*" show in normal mode.
|
||||
Elements with id="edit_*" show in edit mode.
|
||||
-->
|
||||
<elements>
|
||||
<!-- padding="32" is required there (to make room for tooltips) -->
|
||||
<div
|
||||
padding="32" interactable="0"
|
||||
flex_direction="column" gap="8">
|
||||
<!-- Top elements (device battery levels) -->
|
||||
<div id="devices" interactable="0" gap="6" width="100%" max_width="400" flex_direction="row" flex_wrap="wrap">
|
||||
<!-- Src here may be changed, but maintain `TrackedDeviceRole` 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 id="devices_root" interactable="0" gap="6" width="100%" max_width="400" flex_direction="row" flex_wrap="wrap">
|
||||
<!-- Will populate tags at runtime -->
|
||||
<!-- These are examples for uidev -->
|
||||
<Hmd idx="0" />
|
||||
<LeftHand idx="1" />
|
||||
<RightHand idx="2" />
|
||||
<Track idx="3" />
|
||||
</div>
|
||||
|
||||
<!-- All other elements inside the container -->
|
||||
<div flex_direction="column" gap="8">
|
||||
<rectangle macro="decorative_rect" flex_direction="row" id="norm_pane" gap="8">
|
||||
<div flex_direction="column" gap="8" min_width="300">
|
||||
<rectangle macro="decorative_rect" flex_direction="row" gap="8" justify_content="space_evenly">
|
||||
<!-- Clock, date and various timezones -->
|
||||
<div gap="8">
|
||||
<div flex_direction="column">
|
||||
<label text="23:59" _source="clock" _display="time" color="~text_color" size="~clock0_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 flex_direction="column" gap="8">
|
||||
<!-- Timezone names here are only placeholders. Set your timezones via ~/.config/wlxoverlay/conf.d -->
|
||||
<div flex_direction="column">
|
||||
<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>
|
||||
<div flex_direction="column">
|
||||
<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>
|
||||
<div id="clock_root">
|
||||
<Clock />
|
||||
</div>
|
||||
|
||||
<!-- Four buttons -->
|
||||
<div flex_direction="column" gap="8">
|
||||
<div gap="8">
|
||||
<Button macro="button_style" _press="::NewMirror" tooltip="WATCH.MIRROR" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~text_color" src="edit/mirror.svg" />
|
||||
<Button id="btn_keyboard" macro="button_style" _press="::OverlayToggle kbd" tooltip="EDIT_MODE.KEYBOARD" tooltip_side="left">
|
||||
<sprite src_builtin="watch/keyboard.svg" width="40" height="40" />
|
||||
</Button>
|
||||
<Button macro="button_style" _press="::CleanupMirrors" tooltip="WATCH.CLEANUP_MIRRORS" tooltip_side="left">
|
||||
<sprite width="40" height="40" color="~text_color" src="watch/mirror-off.svg" />
|
||||
<Button id="btn_edit_mode" macro="button_style" _press="::EditToggle" tooltip="WATCH.EDIT_MODE" tooltip_side="left">
|
||||
<sprite color="~text_color" width="40" height="40" src="watch/edit.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
<div gap="8">
|
||||
@@ -114,53 +145,28 @@
|
||||
</div>
|
||||
</rectangle>
|
||||
|
||||
<rectangle macro="decorative_rect" flex_direction="column" id="edit_pane" display="none" gap="8">
|
||||
<div flex_direction="column" padding="4" align_items="center" justify_content="center">
|
||||
<label translation="WATCH.EDIT_MODE_EXPLANATION" align="center" />
|
||||
</div>
|
||||
<div flex_direction="column" align_items="center" justify_content="center">
|
||||
<div id="toolbox" gap="8" width="100%" max_width="400" flex_direction="row" flex_wrap="wrap">
|
||||
<Button id="btn_keyboard" height="40" macro="button_style" tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::OverlayToggle kbd">
|
||||
<sprite src_builtin="watch/keyboard.svg" width="32" height="32" />
|
||||
<label translation="EDIT_MODE.KEYBOARD" size="18" />
|
||||
</Button>
|
||||
<!-- Src here may be changed, but maintain `OverlayCategory` order: Panel, Screen, Mirror, WayVR -->
|
||||
<Overlay src="edit/panel.svg" idx="0" />
|
||||
<Overlay src="edit/screen.svg" idx="1" />
|
||||
<Overlay src="edit/mirror.svg" idx="2" />
|
||||
<Overlay src="edit/wayvr.svg" idx="3" />
|
||||
<!-- Will populate additional <Overlay> tags at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
</rectangle>
|
||||
|
||||
<!-- Bottom buttons -->
|
||||
<div flex_direction="row" gap="8">
|
||||
<div gap="4">
|
||||
<Button id="btn_dashboard" macro="button_style" _press="::DashToggle" tooltip="WATCH.DASHBOARD" tooltip_side="top">
|
||||
<sprite color="~text_color" width="40" height="40" src="watch/wayvr_dashboard_mono.svg" />
|
||||
</Button>
|
||||
<Button id="btn_edit_mode" macro="button_style" _press="::EditToggle" tooltip="WATCH.EDIT_MODE" tooltip_side="top">
|
||||
<sprite color="~text_color" width="40" height="40" src="watch/edit.svg" />
|
||||
</Button>
|
||||
<div id="edit_delete" display="none">
|
||||
<Button macro="button_style" _long_release="::EditModeDeleteSet" tooltip="WATCH.LONG_PRESS_TO_DELETE_SET" tooltip_side="top" border_color="~color_danger_translucent" color="~color_danger_40" color2="~color_danger_10">
|
||||
<sprite color="~text_color" width="40" height="40" src="edit/delete.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
<div id="edit_add" display="none">
|
||||
<Button macro="button_style" _press="::EditModeAddSet" tooltip="WATCH.ADD_NEW_SET" tooltip_side="top">
|
||||
<sprite color="~text_color" width="40" height="40" src="edit/add.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<VerticalSeparator />
|
||||
<div id="sets" gap="4">
|
||||
<div id="sets_root" gap="4">
|
||||
<!-- Will populate tags at runtime -->
|
||||
<!-- These are examples for uidev -->
|
||||
<Set idx="0" display="1" />
|
||||
<!-- Will populate additional <Set> tags at runtime -->
|
||||
<Set idx="1" display="2" />
|
||||
</div>
|
||||
<div id="panels_root" gap="4" display="none">
|
||||
<!-- Will populate tags at runtime -->
|
||||
<!-- These are examples for uidev -->
|
||||
<Screen idx="0" display="H1" />
|
||||
<Screen idx="1" display="D2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
</layout>
|
||||
|
||||
@@ -7,6 +7,7 @@ use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
||||
|
||||
use idmap_derive::IntegerId;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use strum::AsRefStr;
|
||||
use wlx_common::common::LeftRight;
|
||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
||||
|
||||
@@ -37,7 +38,7 @@ pub struct TrackedDevice {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntegerId)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntegerId, AsRefStr)]
|
||||
pub enum TrackedDeviceRole {
|
||||
None,
|
||||
Hmd,
|
||||
|
||||
@@ -76,18 +76,26 @@ pub struct ModifyPanelTask {
|
||||
pub command: ModifyPanelCommand,
|
||||
}
|
||||
|
||||
pub enum ToggleMode {
|
||||
EnsureOn,
|
||||
EnsureOff,
|
||||
Toggle,
|
||||
}
|
||||
|
||||
pub type ModifyOverlayTask = dyn FnOnce(&mut AppState, &mut OverlayWindowConfig) + Send;
|
||||
pub type CreateOverlayTask = dyn FnOnce(&mut AppState) -> Option<OverlayWindowConfig> + Send;
|
||||
pub enum OverlayTask {
|
||||
AddSet,
|
||||
ToggleSet(usize),
|
||||
SwitchSet(Option<usize>),
|
||||
ToggleOverlay(OverlaySelector),
|
||||
ToggleOverlay(OverlaySelector, ToggleMode),
|
||||
ResetOverlay(OverlaySelector),
|
||||
DeleteActiveSet,
|
||||
ToggleEditMode,
|
||||
ToggleDashboard,
|
||||
ShowHide,
|
||||
CleanupMirrors,
|
||||
SettingsChanged,
|
||||
Modify(OverlaySelector, Box<ModifyOverlayTask>),
|
||||
Create(OverlaySelector, Box<CreateOverlayTask>),
|
||||
ModifyPanel(ModifyPanelTask),
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
RUNNING,
|
||||
backend::{
|
||||
XrBackend,
|
||||
task::{OverlayTask, PlayspaceTask, TaskType},
|
||||
task::{OverlayTask, PlayspaceTask, TaskType, ToggleMode},
|
||||
wayvr::process::KillSignal,
|
||||
},
|
||||
overlays::{custom::create_custom, toast::Toast, wayvr::WvrCommand},
|
||||
@@ -337,12 +337,10 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Name(arg.clone()),
|
||||
Box::new(move |app, owc| {
|
||||
owc.activate(app);
|
||||
}),
|
||||
)));
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::ResetOverlay(
|
||||
OverlaySelector::Name(arg.clone()),
|
||||
)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
@@ -361,6 +359,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::ToggleOverlay(
|
||||
OverlaySelector::Name(arg.clone()),
|
||||
ToggleMode::Toggle,
|
||||
)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
@@ -384,6 +383,23 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
"::DeleteSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::DeleteActiveSet));
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::AddSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::AddSet));
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::CustomOverlayReload" => {
|
||||
let arg: Arc<str> = args.collect::<Vec<_>>().join(" ").into();
|
||||
if arg.len() < 1 {
|
||||
|
||||
67
wlx-overlay-s/src/gui/panel/device_list.rs
Normal file
67
wlx-overlay-s/src/gui/panel/device_list.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use slotmap::Key;
|
||||
use wgui::{
|
||||
layout::Layout,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::input::TrackedDeviceRole, state::AppState, windowing::backend::OverlayEventData,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
/// Helper for managing a list of overlays
|
||||
/// Populates `id="devices_root"` with `<Hmd>`, `<LeftHand>`, `<RightHand>`, `<Tracker>` templates
|
||||
pub struct DeviceList;
|
||||
|
||||
impl DeviceList {
|
||||
pub fn on_notify(
|
||||
&mut self,
|
||||
app: &AppState,
|
||||
layout: &mut Layout,
|
||||
parser_state: &mut ParserState,
|
||||
event_data: &OverlayEventData,
|
||||
doc_params: &ParseDocumentParams,
|
||||
) -> anyhow::Result<bool> {
|
||||
let mut elements_changed = false;
|
||||
match event_data {
|
||||
OverlayEventData::DevicesChanged => {
|
||||
let devices_root = parser_state
|
||||
.get_widget_id("devices_root")
|
||||
.unwrap_or_default();
|
||||
|
||||
if devices_root.is_null() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
layout.remove_children(devices_root);
|
||||
|
||||
for (i, device) in app.input_state.devices.iter().enumerate() {
|
||||
let mut params = HashMap::new();
|
||||
|
||||
if matches!(device.role, TrackedDeviceRole::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let template = device.role.as_ref();
|
||||
|
||||
log::warn!("creating {template} tag for {i}");
|
||||
|
||||
params.insert("idx".into(), i.to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
&doc_params,
|
||||
template,
|
||||
layout,
|
||||
devices_root,
|
||||
params,
|
||||
)?;
|
||||
}
|
||||
elements_changed = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(elements_changed)
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,7 @@ pub(super) fn setup_custom_label<S: 'static>(
|
||||
}
|
||||
"date" => "%x",
|
||||
"dow" => "%A",
|
||||
"dow_short" => "%a",
|
||||
"time" => {
|
||||
if app.session.config.clock_12h {
|
||||
"%I:%M %p"
|
||||
|
||||
@@ -35,6 +35,7 @@ use crate::{
|
||||
use super::timer::GuiTimer;
|
||||
|
||||
pub mod button;
|
||||
pub mod device_list;
|
||||
mod label;
|
||||
pub mod overlay_list;
|
||||
pub mod set_list;
|
||||
|
||||
@@ -75,9 +75,18 @@ impl OverlayList {
|
||||
);
|
||||
("App", apps_root)
|
||||
}
|
||||
OverlayCategory::Dashboard => {
|
||||
let overlay_button = parser_state
|
||||
.fetch_component_as::<ComponentButton>("btn_dashboard")?;
|
||||
OverlayCategory::Dashboard | OverlayCategory::Keyboard => {
|
||||
let key = if matches!(meta.category, OverlayCategory::Dashboard) {
|
||||
"btn_dashboard"
|
||||
} else {
|
||||
"btn_keyboard"
|
||||
};
|
||||
|
||||
let Ok(overlay_button) =
|
||||
parser_state.fetch_component_as::<ComponentButton>(key)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if meta.visible {
|
||||
let mut com = CallbackDataCommon {
|
||||
|
||||
@@ -18,6 +18,10 @@ pub struct SetList {
|
||||
}
|
||||
|
||||
impl SetList {
|
||||
pub fn num_sets(&self) -> usize {
|
||||
self.set_buttons.len()
|
||||
}
|
||||
|
||||
pub fn on_notify(
|
||||
&mut self,
|
||||
layout: &mut Layout,
|
||||
|
||||
@@ -25,7 +25,7 @@ use wlx_common::{
|
||||
use crate::{
|
||||
backend::{
|
||||
input::{Haptics, HoverResult, PointerHit, PointerMode},
|
||||
task::{OverlayTask, PlayspaceTask, TaskType},
|
||||
task::{OverlayTask, PlayspaceTask, TaskType, ToggleMode},
|
||||
wayvr::{
|
||||
process::{KillSignal, ProcessHandle},
|
||||
window::WindowHandle,
|
||||
@@ -383,16 +383,14 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Id(oid),
|
||||
Box::new(move |app, owc| {
|
||||
if visible && !owc.is_active() {
|
||||
owc.activate(app);
|
||||
} else if !visible && owc.is_active() {
|
||||
owc.deactivate();
|
||||
}
|
||||
}),
|
||||
)));
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::ToggleOverlay(
|
||||
OverlaySelector::Id(oid),
|
||||
match visible {
|
||||
true => ToggleMode::EnsureOn,
|
||||
false => ToggleMode::EnsureOff,
|
||||
},
|
||||
)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -415,4 +413,9 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
||||
) -> &'a mut wlx_common::config::GeneralConfig {
|
||||
&mut data.session.config
|
||||
}
|
||||
|
||||
fn config_changed(&mut self, data: &mut AppState) {
|
||||
data.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::SettingsChanged));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use wlx_common::{
|
||||
use crate::{
|
||||
backend::{
|
||||
input::{HoverResult, PointerHit},
|
||||
task::{OverlayTask, TaskType},
|
||||
task::{OverlayTask, TaskType, ToggleMode},
|
||||
},
|
||||
overlays::screen::capture::{MainThreadWlxCapture, new_wlx_capture},
|
||||
state::{AppSession, AppState},
|
||||
@@ -96,12 +96,11 @@ impl OverlayBackend for MirrorBackend {
|
||||
app.xr_backend,
|
||||
capture,
|
||||
));
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Name(self.name.clone()),
|
||||
Box::new(|app, o| {
|
||||
o.activate(app);
|
||||
}),
|
||||
)));
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::ToggleOverlay(
|
||||
OverlaySelector::Name(self.name.clone()),
|
||||
ToggleMode::EnsureOn,
|
||||
)));
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Failed to create mirror due to PipeWire error: {e:?}");
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
use std::{collections::HashMap, rc::Rc, time::Duration};
|
||||
use std::{rc::Rc, time::Duration};
|
||||
|
||||
use glam::{Affine3A, Quat, Vec3, Vec3A, vec3};
|
||||
use idmap::DirectIdMap;
|
||||
use slotmap::SecondaryMap;
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
components::button::ComponentButton,
|
||||
event::{CallbackDataCommon, EventAlterables, EventCallback, StyleSetRequest},
|
||||
i18n::Translation,
|
||||
event::{CallbackDataCommon, EventAlterables, StyleSetRequest},
|
||||
layout::WidgetID,
|
||||
parser::Fetchable,
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
parser::{Fetchable, ParseDocumentParams},
|
||||
taffy,
|
||||
widget::{EventResult, label::WidgetLabel, sprite::WidgetSprite},
|
||||
};
|
||||
use wlx_common::{
|
||||
common::LeftRight,
|
||||
@@ -19,20 +15,18 @@ use wlx_common::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
input::TrackedDeviceRole,
|
||||
task::{OverlayTask, TaskType},
|
||||
},
|
||||
gui::{
|
||||
panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
|
||||
panel::{
|
||||
GuiPanel, NewGuiPanelParams, device_list::DeviceList, overlay_list::OverlayList,
|
||||
set_list::SetList,
|
||||
},
|
||||
timer::GuiTimer,
|
||||
},
|
||||
state::AppState,
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector, Z_ORDER_WATCH,
|
||||
backend::{OverlayEventData, OverlayMeta},
|
||||
manager::MAX_OVERLAY_SETS,
|
||||
window::{OverlayCategory, OverlayWindowConfig, OverlayWindowData},
|
||||
Z_ORDER_WATCH,
|
||||
backend::OverlayEventData,
|
||||
window::{OverlayWindowConfig, OverlayWindowData},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -52,462 +46,121 @@ struct OverlayButton {
|
||||
|
||||
#[derive(Default)]
|
||||
struct WatchState {
|
||||
current_set: Option<usize>,
|
||||
set_buttons: Vec<Rc<ComponentButton>>,
|
||||
overlay_buttons: Vec<OverlayButton>,
|
||||
overlay_metas: Vec<OverlayMeta>,
|
||||
overlay_indices: SecondaryMap<OverlayID, usize>,
|
||||
edit_mode_widgets: Vec<(WidgetID, bool)>,
|
||||
edit_add_widget: WidgetID,
|
||||
device_role_icons: DirectIdMap<TrackedDeviceRole, CustomGlyphData>,
|
||||
overlay_cat_icons: DirectIdMap<OverlayCategory, CustomGlyphData>,
|
||||
devices: Vec<(WidgetID, WidgetID)>,
|
||||
keyboard_oid: OverlayID,
|
||||
dashboard_oid: OverlayID,
|
||||
num_sets: usize,
|
||||
device_list: DeviceList,
|
||||
overlay_list: OverlayList,
|
||||
set_list: SetList,
|
||||
clock_12h: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::significant_drop_tightening)]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
let state = WatchState::default();
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
|
||||
let Ok(button) =
|
||||
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (name, kind, test_button, test_duration) in &BUTTON_EVENTS {
|
||||
let Some(action) = attribs.get_value(name) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut args = action.split_whitespace();
|
||||
let Some(command) = args.next() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let button = button.clone();
|
||||
|
||||
let callback: EventCallback<AppState, WatchState> = match command {
|
||||
"::EditModeDeleteSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::DeleteActiveSet));
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeAddSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::AddSet));
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeOverlayToggle" => {
|
||||
let arg = args.next().unwrap_or_default();
|
||||
let Ok(idx) = arg.parse::<usize>() else {
|
||||
log::error!("{command} has invalid argument: \"{arg}\"");
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
let Some(overlay) = state.overlay_metas.get(idx) else {
|
||||
log::error!("No overlay at index {idx}.");
|
||||
return Ok(EventResult::Consumed);
|
||||
};
|
||||
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::ToggleOverlay(
|
||||
OverlaySelector::Id(overlay.id),
|
||||
)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
"::SingleSetOverlayReset" => {
|
||||
let arg = args.next().unwrap_or_default();
|
||||
let Ok(idx) = arg.parse::<usize>() else {
|
||||
log::error!("{command} has invalid argument: \"{arg}\"");
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
let Some(overlay) = state.overlay_metas.get(idx) else {
|
||||
log::error!("No overlay at index {idx}.");
|
||||
return Ok(EventResult::Consumed);
|
||||
};
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Id(overlay.id),
|
||||
Box::new(|app, owc| owc.activate(app)),
|
||||
)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let id = layout.add_event_listener(attribs.widget_id, *kind, callback);
|
||||
log::debug!("Registered {action} on {:?} as {id:?}", attribs.widget_id);
|
||||
}
|
||||
});
|
||||
|
||||
let watch_xml = if app.session.config.single_set_mode {
|
||||
"gui/watch-noset.xml"
|
||||
} else {
|
||||
"gui/watch.xml"
|
||||
let state = WatchState {
|
||||
clock_12h: app.session.config.clock_12h,
|
||||
..Default::default()
|
||||
};
|
||||
let watch_xml = "gui/watch.xml";
|
||||
|
||||
let mut panel = GuiPanel::new_from_template(
|
||||
app,
|
||||
watch_xml,
|
||||
state,
|
||||
NewGuiPanelParams {
|
||||
on_custom_id: Some(Box::new(
|
||||
move |id, widget, doc_params, layout, parser_state, state| {
|
||||
if id.starts_with("norm_") {
|
||||
state.edit_mode_widgets.push((widget, false));
|
||||
} else if &*id == "edit_add" {
|
||||
state.edit_add_widget = widget;
|
||||
} else if id.starts_with("edit_") {
|
||||
state.edit_mode_widgets.push((widget, true));
|
||||
} else if &*id == "sets" {
|
||||
let node = layout.state.nodes[widget];
|
||||
let num_children = layout.state.tree.children(node).iter().len();
|
||||
let mut panel =
|
||||
GuiPanel::new_from_template(app, watch_xml, state, NewGuiPanelParams::default())?;
|
||||
|
||||
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" || &*id == "toolbox-condensed" {
|
||||
for idx in 0..MAX_TOOLBOX_BUTTONS {
|
||||
let id_str = format!("overlay_{idx}");
|
||||
|
||||
let button = if let Ok(button) =
|
||||
parser_state.fetch_component_as::<ComponentButton>(&id_str)
|
||||
{
|
||||
button
|
||||
} else {
|
||||
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,
|
||||
)?;
|
||||
parser_state.fetch_component_as::<ComponentButton>(&id_str)?
|
||||
};
|
||||
|
||||
state.overlay_buttons.push(OverlayButton {
|
||||
button,
|
||||
label: parser_state
|
||||
.get_widget_id(&format!("overlay_{idx}_label"))
|
||||
.inspect_err(|e| log::warn!("{e:?}"))
|
||||
.unwrap_or_default(),
|
||||
sprite: parser_state
|
||||
.get_widget_id(&format!("overlay_{idx}_sprite"))
|
||||
.inspect_err(|e| log::warn!("{e:?}"))
|
||||
.unwrap_or_default(),
|
||||
condensed: id.ends_with("-condensed"),
|
||||
});
|
||||
}
|
||||
} else if id.starts_with("overlay_") && id.ends_with("_sprite") {
|
||||
// store device icons from xml
|
||||
let id_n = id
|
||||
.replace("overlay_", "")
|
||||
.replace("_sprite", "")
|
||||
.parse::<u64>()?;
|
||||
|
||||
let category = match id_n {
|
||||
0 => OverlayCategory::Panel,
|
||||
1 => OverlayCategory::Screen,
|
||||
2 => OverlayCategory::Mirror,
|
||||
3 => OverlayCategory::WayVR,
|
||||
_ => 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.get_content().ok_or_else(|| {
|
||||
anyhow::anyhow!("{id} is expected to have a src, but it doesn't.")
|
||||
})?;
|
||||
|
||||
state.overlay_cat_icons.insert(category, src);
|
||||
} 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.get_content().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(), String::new().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(())
|
||||
},
|
||||
)),
|
||||
on_custom_attrib: Some(on_custom_attrib),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
let btn_edit_mode = panel
|
||||
.parser_state
|
||||
.fetch_component_as::<ComponentButton>("btn_edit_mode")
|
||||
.ok();
|
||||
let btn_keyboard = panel
|
||||
.parser_state
|
||||
.fetch_component_as::<ComponentButton>("btn_keyboard")
|
||||
.ok();
|
||||
let btn_dashboard = panel
|
||||
.parser_state
|
||||
.fetch_component_as::<ComponentButton>("btn_dashboard")
|
||||
.ok();
|
||||
let doc_params = ParseDocumentParams {
|
||||
globals: panel.layout.state.globals.clone(),
|
||||
path: AssetPath::FileOrBuiltIn(watch_xml),
|
||||
extra: panel.doc_extra.take().unwrap_or_default(),
|
||||
};
|
||||
|
||||
panel.on_notify = Some(Box::new(move |panel, app, event_data| {
|
||||
let mut alterables = EventAlterables::default();
|
||||
let mut com = CallbackDataCommon {
|
||||
alterables: &mut alterables,
|
||||
state: &panel.layout.state,
|
||||
};
|
||||
|
||||
let mut elems_changed = panel.state.overlay_list.on_notify(
|
||||
&mut panel.layout,
|
||||
&mut panel.parser_state,
|
||||
&event_data,
|
||||
&mut alterables,
|
||||
&doc_params,
|
||||
)?;
|
||||
|
||||
elems_changed |= panel.state.set_list.on_notify(
|
||||
&mut panel.layout,
|
||||
&mut panel.parser_state,
|
||||
&event_data,
|
||||
&mut alterables,
|
||||
&doc_params,
|
||||
)?;
|
||||
|
||||
elems_changed |= panel.state.device_list.on_notify(
|
||||
app,
|
||||
&mut panel.layout,
|
||||
&mut panel.parser_state,
|
||||
&event_data,
|
||||
&doc_params,
|
||||
)?;
|
||||
|
||||
match event_data {
|
||||
OverlayEventData::ActiveSetChanged(current_set) => {
|
||||
if let Some(old_set) = panel.state.current_set.take()
|
||||
&& let Some(old_set) = panel.state.set_buttons.get_mut(old_set)
|
||||
{
|
||||
old_set.set_sticky_state(&mut com, false);
|
||||
}
|
||||
if let Some(new_set) = current_set
|
||||
&& let Some(new_set) = panel.state.set_buttons.get_mut(new_set)
|
||||
{
|
||||
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, 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
|
||||
};
|
||||
com.alterables
|
||||
.set_style(rect_id, StyleSetRequest::Display(display));
|
||||
}
|
||||
let display = if num_sets < 7 {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
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 {
|
||||
let display = if *e == edit_mode {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
if let Ok(btn_edit_mode) = panel
|
||||
.parser_state
|
||||
.fetch_component_as::<ComponentButton>("btn_edit_mode")
|
||||
{
|
||||
let mut com = CallbackDataCommon {
|
||||
alterables: &mut alterables,
|
||||
state: &panel.layout.state,
|
||||
};
|
||||
com.alterables
|
||||
.set_style(*w, StyleSetRequest::Display(display));
|
||||
btn_edit_mode.set_sticky_state(&mut com, edit_mode);
|
||||
}
|
||||
let display = if edit_mode && panel.state.num_sets < 7 {
|
||||
taffy::Display::Flex
|
||||
}
|
||||
OverlayEventData::SettingsChanged => {
|
||||
panel.layout.mark_redraw();
|
||||
|
||||
let display = if app.session.config.sets_on_watch {
|
||||
[taffy::Display::Flex, taffy::Display::None]
|
||||
} else {
|
||||
taffy::Display::None
|
||||
[taffy::Display::None, taffy::Display::Flex]
|
||||
};
|
||||
com.alterables.set_style(
|
||||
panel.state.edit_add_widget,
|
||||
StyleSetRequest::Display(display),
|
||||
);
|
||||
|
||||
if let Some(btn) = btn_edit_mode.as_ref() {
|
||||
btn.set_sticky_state(&mut com, edit_mode);
|
||||
}
|
||||
}
|
||||
OverlayEventData::OverlaysChanged(metas) => {
|
||||
panel.state.overlay_metas.clear();
|
||||
for meta in &*metas {
|
||||
match meta.category {
|
||||
OverlayCategory::Keyboard => {
|
||||
panel.state.keyboard_oid = meta.id;
|
||||
if let Some(btn_keyboard) = btn_keyboard.as_ref() {
|
||||
btn_keyboard.set_sticky_state(&mut com, meta.visible);
|
||||
}
|
||||
}
|
||||
OverlayCategory::Dashboard => {
|
||||
if let Some(btn_dashboard) = btn_dashboard.as_ref() {
|
||||
btn_dashboard.set_sticky_state(&mut com, meta.visible);
|
||||
}
|
||||
panel.state.dashboard_oid = meta.id;
|
||||
}
|
||||
OverlayCategory::Internal => {}
|
||||
_ => panel.state.overlay_metas.push(meta.clone()),
|
||||
}
|
||||
let widget = [
|
||||
panel
|
||||
.parser_state
|
||||
.get_widget_id("panels_root")
|
||||
.unwrap_or_default(),
|
||||
panel
|
||||
.parser_state
|
||||
.get_widget_id("sets_root")
|
||||
.unwrap_or_default(),
|
||||
];
|
||||
|
||||
for i in 0..2 {
|
||||
alterables.set_style(widget[i], StyleSetRequest::Display(display[i]));
|
||||
}
|
||||
|
||||
panel.state.overlay_indices.clear();
|
||||
for (idx, meta) in panel.state.overlay_metas.iter().enumerate() {
|
||||
panel.state.overlay_indices.insert(meta.id, idx);
|
||||
}
|
||||
if app.session.config.clock_12h != panel.state.clock_12h {
|
||||
panel.state.clock_12h = app.session.config.clock_12h;
|
||||
|
||||
for (idx, btn) in panel.state.overlay_buttons.iter().enumerate() {
|
||||
let display = if let Some(meta) = panel.state.overlay_metas.get(idx) {
|
||||
let name = if btn.condensed {
|
||||
condense_overlay_name(&meta.name)
|
||||
} else {
|
||||
sanitize_overlay_name(&meta.name)
|
||||
};
|
||||
let clock_root = panel.parser_state.get_widget_id("clock_root")?;
|
||||
panel.layout.remove_children(clock_root);
|
||||
|
||||
if let Some(mut label) =
|
||||
panel.layout.state.widgets.get_as::<WidgetLabel>(btn.label)
|
||||
{
|
||||
label.set_text(&mut com, Translation::from_raw_text_rc(name));
|
||||
} else {
|
||||
btn.button
|
||||
.set_text(&mut com, Translation::from_raw_text_rc(name));
|
||||
}
|
||||
panel.parser_state.instantiate_template(
|
||||
&doc_params,
|
||||
"Clock",
|
||||
&mut panel.layout,
|
||||
clock_root,
|
||||
Default::default(),
|
||||
)?;
|
||||
|
||||
if let Some(mut sprite) = panel
|
||||
.layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(btn.sprite)
|
||||
&& let Some(glyph) = panel.state.overlay_cat_icons.get(meta.category)
|
||||
{
|
||||
sprite.set_content(&mut com, Some(glyph.clone()));
|
||||
}
|
||||
|
||||
btn.button.set_sticky_state(&mut com, meta.visible);
|
||||
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
com.alterables
|
||||
.set_style(btn.button.get_rect(), StyleSetRequest::Display(display));
|
||||
}
|
||||
}
|
||||
OverlayEventData::VisibleOverlaysChanged(overlays) => {
|
||||
for meta in &mut panel.state.overlay_metas {
|
||||
meta.visible = false;
|
||||
}
|
||||
|
||||
let mut keyboard_visible = false;
|
||||
let mut dashboard_visible = false;
|
||||
|
||||
for visible in &*overlays {
|
||||
if let Some(idx) = panel.state.overlay_indices.get(*visible)
|
||||
&& let Some(o) = panel.state.overlay_metas.get_mut(*idx)
|
||||
{
|
||||
o.visible = true;
|
||||
} else if panel.state.keyboard_oid == *visible {
|
||||
keyboard_visible = true;
|
||||
} else if panel.state.dashboard_oid == *visible {
|
||||
dashboard_visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (idx, btn) in panel.state.overlay_buttons.iter().enumerate() {
|
||||
let Some(meta) = panel.state.overlay_metas.get(idx) else {
|
||||
continue;
|
||||
};
|
||||
btn.button.set_sticky_state(&mut com, meta.visible);
|
||||
}
|
||||
if let Some(btn_keyboard) = btn_keyboard.as_ref() {
|
||||
btn_keyboard.set_sticky_state(&mut com, keyboard_visible);
|
||||
}
|
||||
if let Some(btn_dashboard) = btn_dashboard.as_ref() {
|
||||
btn_dashboard.set_sticky_state(&mut com, dashboard_visible);
|
||||
}
|
||||
}
|
||||
OverlayEventData::DevicesChanged => {
|
||||
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)
|
||||
{
|
||||
s.set_content(&mut com, Some(glyph.clone()));
|
||||
com.alterables
|
||||
.set_style(*div, StyleSetRequest::Display(taffy::Display::Flex));
|
||||
} else {
|
||||
com.alterables
|
||||
.set_style(*div, StyleSetRequest::Display(taffy::Display::None));
|
||||
}
|
||||
elems_changed = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if elems_changed {
|
||||
panel.process_custom_elems(app);
|
||||
}
|
||||
|
||||
panel.layout.process_alterables(alterables)?;
|
||||
Ok(())
|
||||
}));
|
||||
@@ -557,16 +210,3 @@ pub fn watch_fade<D>(app: &mut AppState, watch: &mut OverlayWindowData<D>) {
|
||||
state.alpha += 0.1;
|
||||
state.alpha = state.alpha.clamp(0., 1.);
|
||||
}
|
||||
|
||||
fn sanitize_overlay_name(str: &str) -> Rc<str> {
|
||||
str.replace("-wvr", "").into()
|
||||
}
|
||||
|
||||
fn condense_overlay_name(str: &str) -> Rc<str> {
|
||||
str.replace("DP-", "D")
|
||||
.replace("HDMI-A-", "H")
|
||||
.replace("WVR-wvr_", "W")
|
||||
.replace("WVR-wvr", "W0")
|
||||
.replace("Keyboard", "")
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
|
||||
################ EXPERIENCE ################
|
||||
|
||||
## When enabled, sets functionality will be disabled and
|
||||
## the bottom of the watch will list overlays instead of sets.
|
||||
#single_set_mode: false
|
||||
## The bottom of the watch will list sets instead of overlays.
|
||||
#sets_on_watch: false
|
||||
|
||||
## Force an alternative method for Wayland desktop capture.
|
||||
## `auto`: default
|
||||
|
||||
@@ -126,6 +126,7 @@ pub enum OverlayEventData {
|
||||
OverlaysChanged(Rc<[OverlayMeta]>),
|
||||
VisibleOverlaysChanged(Rc<[OverlayID]>),
|
||||
DevicesChanged,
|
||||
SettingsChanged,
|
||||
OverlayGrabbed {
|
||||
name: Arc<str>,
|
||||
pos: Positioning,
|
||||
|
||||
@@ -16,7 +16,7 @@ use wlx_common::{
|
||||
|
||||
use crate::{
|
||||
FRAME_COUNTER,
|
||||
backend::task::OverlayTask,
|
||||
backend::task::{OverlayTask, ToggleMode},
|
||||
config::save_state,
|
||||
overlays::{
|
||||
anchor::{create_anchor, create_grab_help},
|
||||
@@ -172,13 +172,29 @@ where
|
||||
OverlayTask::SwitchSet(maybe_set) => {
|
||||
self.switch_to_set(app, maybe_set, false);
|
||||
}
|
||||
OverlayTask::ToggleOverlay(sel) => {
|
||||
OverlayTask::ResetOverlay(sel) => {
|
||||
if let Some(o) = self.mut_by_selector(&sel) {
|
||||
let was_active = o.config.is_active();
|
||||
o.config.activate(app);
|
||||
if !was_active {
|
||||
self.visible_overlays_changed(app)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
OverlayTask::ToggleOverlay(sel, mode) => {
|
||||
let Some(id) = self.id_by_selector(&sel) else {
|
||||
log::warn!("Overlay not found for task: {sel:?}");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let o = &mut self.overlays[id];
|
||||
|
||||
match mode {
|
||||
ToggleMode::EnsureOn if o.config.is_active() => return Ok(()),
|
||||
ToggleMode::EnsureOff if !o.config.is_active() => return Ok(()),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
if let Some(active_state) = o.config.active_state.take() {
|
||||
log::debug!("{}: toggle off", o.config.name);
|
||||
|
||||
@@ -214,6 +230,7 @@ where
|
||||
} else {
|
||||
overlay.config.deactivate();
|
||||
}
|
||||
self.visible_overlays_changed(app)?;
|
||||
}
|
||||
}
|
||||
OverlayTask::AddSet => {
|
||||
@@ -267,6 +284,15 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
OverlayTask::SettingsChanged => {
|
||||
for o in self.overlays.values_mut() {
|
||||
let _ = o
|
||||
.config
|
||||
.backend
|
||||
.notify(app, OverlayEventData::SettingsChanged)
|
||||
.log_err("Could not notify SettingsChanged");
|
||||
}
|
||||
}
|
||||
OverlayTask::CleanupMirrors => {
|
||||
let mut ids_to_remove = vec![];
|
||||
for (oid, o) in &self.overlays {
|
||||
|
||||
@@ -113,6 +113,8 @@ impl OverlayWindowConfig {
|
||||
self.active_state.is_some()
|
||||
}
|
||||
|
||||
/// only call this directly for `OverlayCategory::Internal`
|
||||
/// for anything else, use `OverlayTask::ToggleOverlay` instead
|
||||
pub fn activate(&mut self, app: &mut AppState) {
|
||||
log::debug!("activate {}", self.name.as_ref());
|
||||
self.dirty = true;
|
||||
@@ -120,19 +122,13 @@ impl OverlayWindowConfig {
|
||||
self.reset(app, true);
|
||||
}
|
||||
|
||||
/// only call this directly for `OverlayCategory::Internal`
|
||||
/// for anything else, use `OverlayTask::ToggleOverlay` instead
|
||||
pub fn deactivate(&mut self) {
|
||||
log::debug!("deactivate {}", self.name.as_ref());
|
||||
self.active_state = None;
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, app: &mut AppState) {
|
||||
if self.active_state.take().is_none() {
|
||||
self.activate(app);
|
||||
} else {
|
||||
log::debug!("deactivate {} (toggle)", self.name.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auto_movement(&mut self, app: &mut AppState) {
|
||||
if self.pause_movement {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user