fix set/overlay persistence
This commit is contained in:
@@ -1,35 +1,23 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use chrono::Offset;
|
use chrono::Offset;
|
||||||
use glam::{vec3, Affine3A, Quat, Vec3};
|
use glam::Affine3A;
|
||||||
use idmap::IdMap;
|
use idmap::IdMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
astr_containers::{AStrMap, AStrSet},
|
astr_containers::{AStrMap, AStrSet},
|
||||||
common::LeftRight,
|
|
||||||
overlays::{ToastDisplayMethod, ToastTopic},
|
overlays::{ToastDisplayMethod, ToastTopic},
|
||||||
windowing::OverlayWindowState,
|
windowing::OverlayWindowState,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type PwTokenMap = AStrMap<String>;
|
pub type PwTokenMap = AStrMap<String>;
|
||||||
|
pub type SerializedWindowStates = HashMap<Arc<str>, OverlayWindowState>;
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct SerializedWindowSet {
|
pub struct SerializedWindowSet {
|
||||||
pub name: Arc<str>,
|
pub name: Arc<str>,
|
||||||
pub overlays: HashMap<Arc<str>, OverlayWindowState>,
|
pub overlays: SerializedWindowStates,
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn def_watch_pos() -> Vec3 {
|
|
||||||
vec3(-0.03, -0.01, 0.125)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn def_watch_rot() -> Quat {
|
|
||||||
Quat::from_xyzw(-0.707_106_6, 0.000_796_361_8, 0.707_106_6, 0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn def_left() -> LeftRight {
|
|
||||||
LeftRight::Left
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn def_pw_tokens() -> PwTokenMap {
|
pub const fn def_pw_tokens() -> PwTokenMap {
|
||||||
@@ -44,7 +32,7 @@ const fn def_click_freeze_time_ms() -> u32 {
|
|||||||
300
|
300
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn def_true() -> bool {
|
const fn def_true() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,15 +44,15 @@ const fn def_one() -> f32 {
|
|||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn def_half() -> f32 {
|
const fn def_half() -> f32 {
|
||||||
0.5
|
0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn def_point7() -> f32 {
|
const fn def_point7() -> f32 {
|
||||||
0.7
|
0.7
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn def_point3() -> f32 {
|
const fn def_point3() -> f32 {
|
||||||
0.3
|
0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +68,10 @@ const fn def_sets() -> Vec<SerializedWindowSet> {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn def_global_set() -> SerializedWindowStates {
|
||||||
|
HashMap::new()
|
||||||
|
}
|
||||||
|
|
||||||
const fn def_zero_u32() -> u32 {
|
const fn def_zero_u32() -> u32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@@ -137,15 +129,6 @@ pub struct GeneralConfig {
|
|||||||
#[serde(default = "def_theme_path")]
|
#[serde(default = "def_theme_path")]
|
||||||
pub theme_path: Arc<str>,
|
pub theme_path: Arc<str>,
|
||||||
|
|
||||||
#[serde(default = "def_watch_pos")]
|
|
||||||
pub watch_pos: Vec3,
|
|
||||||
|
|
||||||
#[serde(default = "def_watch_rot")]
|
|
||||||
pub watch_rot: Quat,
|
|
||||||
|
|
||||||
#[serde(default = "def_left")]
|
|
||||||
pub watch_hand: LeftRight,
|
|
||||||
|
|
||||||
#[serde(default = "def_click_freeze_time_ms")]
|
#[serde(default = "def_click_freeze_time_ms")]
|
||||||
pub click_freeze_time_ms: u32,
|
pub click_freeze_time_ms: u32,
|
||||||
|
|
||||||
@@ -287,6 +270,9 @@ pub struct GeneralConfig {
|
|||||||
#[serde(default = "def_sets")]
|
#[serde(default = "def_sets")]
|
||||||
pub sets: Vec<SerializedWindowSet>,
|
pub sets: Vec<SerializedWindowSet>,
|
||||||
|
|
||||||
|
#[serde(default = "def_global_set")]
|
||||||
|
pub global_set: SerializedWindowStates,
|
||||||
|
|
||||||
#[serde(default = "def_zero_u32")]
|
#[serde(default = "def_zero_u32")]
|
||||||
pub last_set: u32,
|
pub last_set: u32,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub struct OverlayWindowState {
|
|||||||
pub positioning: Positioning,
|
pub positioning: Positioning,
|
||||||
pub curvature: Option<f32>,
|
pub curvature: Option<f32>,
|
||||||
pub additive: bool,
|
pub additive: bool,
|
||||||
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
pub saved_transform: Option<Affine3A>,
|
pub saved_transform: Option<Affine3A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::process::{Child, Command};
|
use std::process::{Child, Command};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{collections::VecDeque, time::Instant};
|
use std::{collections::VecDeque, time::Instant};
|
||||||
|
|
||||||
use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
ops::Add,
|
ops::Add,
|
||||||
sync::{
|
sync::{atomic::Ordering, Arc},
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::backend::wayvr::egl_ex::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::egl_ex;
|
use super::egl_ex;
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::Context;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EGLData {
|
pub struct EGLData {
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
use crate::config_io;
|
use crate::config_io;
|
||||||
use config::{Config, File};
|
use config::{Config, File};
|
||||||
use glam::{Quat, Vec3};
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use wlx_common::{
|
use wlx_common::config::{GeneralConfig, SerializedWindowSet, SerializedWindowStates};
|
||||||
common::LeftRight,
|
|
||||||
config::{GeneralConfig, SerializedWindowSet},
|
|
||||||
};
|
|
||||||
|
|
||||||
const FALLBACKS: [&str; 2] = [
|
const FALLBACKS: [&str; 2] = [
|
||||||
include_str!("res/keyboard.yaml"),
|
include_str!("res/keyboard.yaml"),
|
||||||
@@ -105,9 +101,6 @@ pub fn load_general_config() -> GeneralConfig {
|
|||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct AutoSettings {
|
pub struct AutoSettings {
|
||||||
pub watch_pos: Vec3,
|
|
||||||
pub watch_rot: Quat,
|
|
||||||
pub watch_hand: LeftRight,
|
|
||||||
pub watch_view_angle_min: f32,
|
pub watch_view_angle_min: f32,
|
||||||
pub watch_view_angle_max: f32,
|
pub watch_view_angle_max: f32,
|
||||||
pub notifications_enabled: bool,
|
pub notifications_enabled: bool,
|
||||||
@@ -125,9 +118,6 @@ fn get_settings_path() -> PathBuf {
|
|||||||
|
|
||||||
pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
||||||
let conf = AutoSettings {
|
let conf = AutoSettings {
|
||||||
watch_pos: config.watch_pos,
|
|
||||||
watch_rot: config.watch_rot,
|
|
||||||
watch_hand: config.watch_hand,
|
|
||||||
watch_view_angle_min: config.watch_view_angle_min,
|
watch_view_angle_min: config.watch_view_angle_min,
|
||||||
watch_view_angle_max: config.watch_view_angle_max,
|
watch_view_angle_max: config.watch_view_angle_max,
|
||||||
notifications_enabled: config.notifications_enabled,
|
notifications_enabled: config.notifications_enabled,
|
||||||
@@ -148,6 +138,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct AutoState {
|
pub struct AutoState {
|
||||||
pub sets: Vec<SerializedWindowSet>,
|
pub sets: Vec<SerializedWindowSet>,
|
||||||
|
pub global_set: SerializedWindowStates,
|
||||||
pub last_set: u32,
|
pub last_set: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +152,7 @@ pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> {
|
|||||||
let conf = AutoState {
|
let conf = AutoState {
|
||||||
sets: config.sets.clone(),
|
sets: config.sets.clone(),
|
||||||
last_set: config.last_set,
|
last_set: config.last_set,
|
||||||
|
global_set: config.global_set.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::{
|
use std::{
|
||||||
f32::consts::PI,
|
|
||||||
ops::Add,
|
ops::Add,
|
||||||
sync::{Arc, LazyLock},
|
sync::{Arc, LazyLock},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
@@ -17,6 +16,7 @@ use wlx_common::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::task::{OverlayTask, TaskType},
|
backend::task::{OverlayTask, TaskType},
|
||||||
gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomIdFunc},
|
gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomIdFunc},
|
||||||
|
overlays::watch::{WATCH_POS, WATCH_ROT},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::{window::OverlayWindowConfig, OverlaySelector, Z_ORDER_TOAST},
|
windowing::{window::OverlayWindowConfig, OverlaySelector, Z_ORDER_TOAST},
|
||||||
};
|
};
|
||||||
@@ -121,12 +121,14 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<OverlayWindowConfig> {
|
|||||||
Positioning::FollowHead { lerp: 0.1 },
|
Positioning::FollowHead { lerp: 0.1 },
|
||||||
),
|
),
|
||||||
ToastDisplayMethod::Watch => {
|
ToastDisplayMethod::Watch => {
|
||||||
let mut watch_pos = app.session.config.watch_pos + vec3(-0.005, -0.05, 0.02);
|
//FIXME: properly follow watch
|
||||||
let mut watch_rot = app.session.config.watch_rot;
|
let watch_pos = WATCH_POS + vec3(-0.005, -0.05, 0.02);
|
||||||
let relative_to = match app.session.config.watch_hand {
|
let watch_rot = WATCH_ROT;
|
||||||
LeftRight::Left => Positioning::FollowHand {
|
let relative_to = /*match app.session.config.watch_hand {
|
||||||
|
LeftRight::Left =>*/ Positioning::FollowHand {
|
||||||
hand: LeftRight::Left,
|
hand: LeftRight::Left,
|
||||||
lerp: 1.0,
|
lerp: 1.0,
|
||||||
|
/*
|
||||||
},
|
},
|
||||||
LeftRight::Right => {
|
LeftRight::Right => {
|
||||||
watch_pos.x = -watch_pos.x;
|
watch_pos.x = -watch_pos.x;
|
||||||
@@ -135,7 +137,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<OverlayWindowConfig> {
|
|||||||
hand: LeftRight::Right,
|
hand: LeftRight::Right,
|
||||||
lerp: 1.0,
|
lerp: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
};
|
};
|
||||||
(watch_pos, watch_rot, relative_to)
|
(watch_pos, watch_rot, relative_to)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use glam::{Affine3A, Vec3};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
gui::{panel::GuiPanel, timer::GuiTimer},
|
|
||||||
state::AppState,
|
|
||||||
windowing::{
|
|
||||||
window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
|
||||||
Z_ORDER_WATCH,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const EDIT_NAME: &str = "edit";
|
|
||||||
|
|
||||||
struct EditState {
|
|
||||||
num_sets: usize,
|
|
||||||
current_set: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::significant_drop_tightening)]
|
|
||||||
pub fn create_edit(
|
|
||||||
app: &mut AppState,
|
|
||||||
num_sets: usize,
|
|
||||||
current_set: usize,
|
|
||||||
) -> anyhow::Result<OverlayWindowConfig> {
|
|
||||||
let state = EditState {
|
|
||||||
num_sets,
|
|
||||||
current_set,
|
|
||||||
};
|
|
||||||
let mut panel = GuiPanel::new_from_template(
|
|
||||||
app,
|
|
||||||
"gui/watch.xml",
|
|
||||||
state,
|
|
||||||
Some(Box::new(
|
|
||||||
move |id, widget, doc_params, layout, parser_state| {
|
|
||||||
if &*id != "sets" {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx in 0..num_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)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
panel
|
|
||||||
.timers
|
|
||||||
.push(GuiTimer::new(Duration::from_millis(100), 0));
|
|
||||||
|
|
||||||
let positioning = Positioning::FollowHand {
|
|
||||||
hand: app.session.config.watch_hand as _,
|
|
||||||
lerp: 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
panel.update_layout()?;
|
|
||||||
|
|
||||||
Ok(OverlayWindowConfig {
|
|
||||||
name: EDIT_NAME.into(),
|
|
||||||
z_order: Z_ORDER_WATCH,
|
|
||||||
default_state: OverlayWindowState {
|
|
||||||
interactable: true,
|
|
||||||
positioning,
|
|
||||||
transform: Affine3A::from_scale_rotation_translation(
|
|
||||||
Vec3::ONE * 0.115,
|
|
||||||
app.session.config.watch_rot,
|
|
||||||
app.session.config.watch_pos,
|
|
||||||
) * Affine3A::from_translation(Vec3::Y * 0.075),
|
|
||||||
..OverlayWindowState::default()
|
|
||||||
},
|
|
||||||
show_on_spawn: true,
|
|
||||||
global: true,
|
|
||||||
..OverlayWindowConfig::from_backend(Box::new(panel))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use glam::{Affine3A, Vec3, Vec3A};
|
use glam::{vec3, Affine3A, Quat, Vec3, Vec3A};
|
||||||
use idmap::DirectIdMap;
|
use idmap::DirectIdMap;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
components::button::ComponentButton,
|
components::button::ComponentButton,
|
||||||
@@ -16,7 +16,10 @@ use wgui::{
|
|||||||
taffy,
|
taffy,
|
||||||
widget::{sprite::WidgetSprite, EventResult},
|
widget::{sprite::WidgetSprite, EventResult},
|
||||||
};
|
};
|
||||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
use wlx_common::{
|
||||||
|
common::LeftRight,
|
||||||
|
windowing::{OverlayWindowState, Positioning},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{
|
||||||
@@ -41,6 +44,9 @@ pub const WATCH_NAME: &str = "watch";
|
|||||||
const MAX_TOOLBOX_BUTTONS: usize = 16;
|
const MAX_TOOLBOX_BUTTONS: usize = 16;
|
||||||
const MAX_DEVICES: usize = 9;
|
const MAX_DEVICES: usize = 9;
|
||||||
|
|
||||||
|
pub(crate) const WATCH_POS: Vec3 = vec3(-0.03, -0.01, 0.125);
|
||||||
|
pub(crate) const WATCH_ROT: Quat = Quat::from_xyzw(-0.707_106_6, 0.000_796_361_8, 0.707_106_6, 0.0);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct WatchState {
|
struct WatchState {
|
||||||
current_set: Option<usize>,
|
current_set: Option<usize>,
|
||||||
@@ -323,7 +329,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
|||||||
.push(GuiTimer::new(Duration::from_millis(100), 0));
|
.push(GuiTimer::new(Duration::from_millis(100), 0));
|
||||||
|
|
||||||
let positioning = Positioning::FollowHand {
|
let positioning = Positioning::FollowHand {
|
||||||
hand: app.session.config.watch_hand,
|
hand: LeftRight::Left,
|
||||||
lerp: 1.0,
|
lerp: 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -337,8 +343,8 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
|||||||
positioning,
|
positioning,
|
||||||
transform: Affine3A::from_scale_rotation_translation(
|
transform: Affine3A::from_scale_rotation_translation(
|
||||||
Vec3::ONE * 0.115,
|
Vec3::ONE * 0.115,
|
||||||
app.session.config.watch_rot,
|
WATCH_ROT,
|
||||||
app.session.config.watch_pos,
|
WATCH_POS,
|
||||||
),
|
),
|
||||||
..OverlayWindowState::default()
|
..OverlayWindowState::default()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ where
|
|||||||
if newly_created {
|
if newly_created {
|
||||||
log::info!("Creating dashboard overlay");
|
log::info!("Creating dashboard overlay");
|
||||||
|
|
||||||
let mut overlay = OverlayWindowData::from_config(OverlayWindowConfig {
|
let overlay = OverlayWindowData::from_config(OverlayWindowConfig {
|
||||||
default_state: OverlayWindowState {
|
default_state: OverlayWindowState {
|
||||||
interactable: true,
|
interactable: true,
|
||||||
grabbable: true,
|
grabbable: true,
|
||||||
@@ -284,8 +284,6 @@ where
|
|||||||
)?
|
)?
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay.config.reset(app, true);
|
|
||||||
|
|
||||||
let overlay_id = overlays.add(overlay, app);
|
let overlay_id = overlays.add(overlay, app);
|
||||||
wayvr.set_overlay_display_handle(overlay_id, disp_handle);
|
wayvr.set_overlay_display_handle(overlay_id, disp_handle);
|
||||||
|
|
||||||
@@ -433,7 +431,14 @@ where
|
|||||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||||
OverlaySelector::Id(overlay_id),
|
OverlaySelector::Id(overlay_id),
|
||||||
Box::new(move |app, o| {
|
Box::new(move |app, o| {
|
||||||
o.toggle(app);
|
if visible == o.is_active() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if visible {
|
||||||
|
o.activate(app);
|
||||||
|
} else {
|
||||||
|
o.deactivate();
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ use std::{
|
|||||||
|
|
||||||
use glam::{Affine3A, Vec3, Vec3A};
|
use glam::{Affine3A, Vec3, Vec3A};
|
||||||
use slotmap::{HopSlotMap, Key, SecondaryMap};
|
use slotmap::{HopSlotMap, Key, SecondaryMap};
|
||||||
use wlx_common::{config::SerializedWindowSet, overlays::ToastTopic};
|
use wlx_common::{
|
||||||
|
astr_containers::{AStrMap, AStrMapExt},
|
||||||
|
config::SerializedWindowSet,
|
||||||
|
overlays::ToastTopic,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::task::OverlayTask,
|
backend::task::OverlayTask,
|
||||||
@@ -107,21 +111,24 @@ where
|
|||||||
let anchor = OverlayWindowData::from_config(create_anchor(app)?);
|
let anchor = OverlayWindowData::from_config(create_anchor(app)?);
|
||||||
me.add(anchor, app);
|
me.add(anchor, app);
|
||||||
|
|
||||||
let mut watch = OverlayWindowData::from_config(create_watch(app)?);
|
let watch = OverlayWindowData::from_config(create_watch(app)?);
|
||||||
|
me.watch_id = me.add(watch, app);
|
||||||
|
|
||||||
|
// overwrite default layout with saved layout, if exists
|
||||||
|
me.restore_layout(app);
|
||||||
|
me.overlays_changed(app)?;
|
||||||
|
|
||||||
for ev in [
|
for ev in [
|
||||||
OverlayEventData::NumSetsChanged(me.sets.len()),
|
OverlayEventData::NumSetsChanged(me.sets.len()),
|
||||||
OverlayEventData::EditModeChanged(false),
|
OverlayEventData::EditModeChanged(false),
|
||||||
OverlayEventData::DevicesChanged,
|
OverlayEventData::DevicesChanged,
|
||||||
] {
|
] {
|
||||||
watch.config.backend.notify(app, ev)?;
|
me.mut_by_id(me.watch_id)
|
||||||
|
.unwrap()
|
||||||
|
.config
|
||||||
|
.backend
|
||||||
|
.notify(app, ev)?;
|
||||||
}
|
}
|
||||||
me.watch_id = me.add(watch, app);
|
|
||||||
|
|
||||||
me.overlays_changed(app)?;
|
|
||||||
|
|
||||||
// overwrite default layout with saved layout, if exists
|
|
||||||
me.restore_layout(app);
|
|
||||||
|
|
||||||
Ok(me)
|
Ok(me)
|
||||||
}
|
}
|
||||||
@@ -227,6 +234,7 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn persist_layout(&mut self, app: &mut AppState) {
|
pub fn persist_layout(&mut self, app: &mut AppState) {
|
||||||
|
app.session.config.global_set.clear();
|
||||||
app.session.config.sets.clear();
|
app.session.config.sets.clear();
|
||||||
app.session.config.sets.reserve(self.sets.len());
|
app.session.config.sets.reserve(self.sets.len());
|
||||||
app.session.config.last_set = self.restore_set as _;
|
app.session.config.last_set = self.restore_set as _;
|
||||||
@@ -240,7 +248,7 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for set in &self.sets {
|
for set in &self.sets {
|
||||||
let overlays: HashMap<_, _> = set
|
let mut overlays: HashMap<_, _> = set
|
||||||
.overlays
|
.overlays
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(k, v)| {
|
.filter_map(|(k, v)| {
|
||||||
@@ -249,6 +257,13 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// overlays that we haven't seen since startup (e.g. wayvr apps)
|
||||||
|
for (k, o) in set.inactive_overlays.iter() {
|
||||||
|
if !overlays.contains_key(k) {
|
||||||
|
overlays.insert(k.clone(), o.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let serialized = SerializedWindowSet {
|
let serialized = SerializedWindowSet {
|
||||||
name: set.name.clone(),
|
name: set.name.clone(),
|
||||||
overlays,
|
overlays,
|
||||||
@@ -256,6 +271,23 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
app.session.config.sets.push(serialized);
|
app.session.config.sets.push(serialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// global overlays; watch, toast
|
||||||
|
for oid in &[self.watch_id] {
|
||||||
|
let Some(o) = self.get_by_id(*oid) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
let Some(mut state) = o.config.active_state.clone() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if let Some(transform) = state.saved_transform.as_ref() {
|
||||||
|
state.transform = *transform;
|
||||||
|
}
|
||||||
|
app.session
|
||||||
|
.config
|
||||||
|
.global_set
|
||||||
|
.insert(o.config.name.clone(), state.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if restore_after {
|
if restore_after {
|
||||||
self.switch_to_set(app, Some(self.restore_set));
|
self.switch_to_set(app, Some(self.restore_set));
|
||||||
}
|
}
|
||||||
@@ -275,18 +307,42 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
self.sets.clear();
|
self.sets.clear();
|
||||||
self.sets.reserve(app.session.config.sets.len());
|
self.sets.reserve(app.session.config.sets.len());
|
||||||
|
|
||||||
for s in &app.session.config.sets {
|
for (i, s) in app.session.config.sets.iter().enumerate() {
|
||||||
let overlays: SecondaryMap<_, _> = s
|
let mut overlays = SecondaryMap::new();
|
||||||
.overlays
|
let mut inactive_overlays = AStrMap::new();
|
||||||
.iter()
|
|
||||||
.filter_map(|(name, v)| self.lookup(name).map(|id| (id, v.clone())))
|
for (name, o) in s.overlays.iter() {
|
||||||
.collect();
|
if let Some(id) = self.lookup(&*name) {
|
||||||
|
log::debug!("set {i}: loaded state for {name}");
|
||||||
|
overlays.insert(id, o.clone());
|
||||||
|
} else {
|
||||||
|
log::debug!("set {i} has saved state for {name} which doesn't exist. will apply state once added.");
|
||||||
|
inactive_overlays.arc_set(name.clone(), o.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.sets.push(OverlayWindowSet {
|
self.sets.push(OverlayWindowSet {
|
||||||
name: s.name.clone(),
|
name: s.name.clone(),
|
||||||
overlays,
|
overlays,
|
||||||
|
inactive_overlays,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// global overlays
|
||||||
|
for oid in &[self.watch_id] {
|
||||||
|
if let Some(o) = self.mut_by_id(*oid) {
|
||||||
|
if let Some(mut state) = app.session.config.global_set.get(&*o.config.name).cloned()
|
||||||
|
{
|
||||||
|
state.saved_transform = Some(state.transform);
|
||||||
|
o.config.active_state = Some(state);
|
||||||
|
o.config.reset(app, false);
|
||||||
|
log::debug!("global set: loaded state for {}", o.config.name);
|
||||||
|
} else {
|
||||||
|
log::debug!("global set: no state for {}", o.config.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1);
|
self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,8 +459,6 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, mut overlay: OverlayWindowData<T>, app: &mut AppState) -> OverlayID {
|
pub fn add(&mut self, mut overlay: OverlayWindowData<T>, app: &mut AppState) -> OverlayID {
|
||||||
let internal = matches!(overlay.config.category, OverlayCategory::Internal);
|
|
||||||
|
|
||||||
while self.lookup(&overlay.config.name).is_some() {
|
while self.lookup(&overlay.config.name).is_some() {
|
||||||
log::error!(
|
log::error!(
|
||||||
"An overlay with name {} already exists. Deduplicating, but things may break!",
|
"An overlay with name {} already exists. Deduplicating, but things may break!",
|
||||||
@@ -413,15 +467,41 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
overlay.config.name = format!("{}_2", overlay.config.name).into();
|
overlay.config.name = format!("{}_2", overlay.config.name).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if overlay.config.show_on_spawn {
|
let name = overlay.config.name.clone();
|
||||||
log::debug!("activating {} due to show_on_spawn", overlay.config.name);
|
let global = overlay.config.global;
|
||||||
overlay.config.activate(app);
|
let internal = matches!(overlay.config.category, OverlayCategory::Internal);
|
||||||
|
let show_on_spawn = overlay.config.show_on_spawn;
|
||||||
|
|
||||||
|
let oid = self.overlays.insert(overlay);
|
||||||
|
let mut shown = false;
|
||||||
|
|
||||||
|
if !global {
|
||||||
|
for (i, set) in self.sets.iter_mut().enumerate() {
|
||||||
|
let Some(mut state) = set.inactive_overlays.arc_rm(&*name) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if self.current_set == Some(i) {
|
||||||
|
let o = &mut self.overlays[oid];
|
||||||
|
state.saved_transform = Some(state.transform);
|
||||||
|
o.config.active_state = Some(state);
|
||||||
|
o.config.reset(app, false);
|
||||||
|
shown = true;
|
||||||
|
log::debug!("loaded state for {name} to active set!");
|
||||||
|
} else {
|
||||||
|
set.overlays.insert(oid, state);
|
||||||
|
log::debug!("loaded state for {name} to set {i}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !shown && show_on_spawn {
|
||||||
|
log::debug!("activating {} due to show_on_spawn", name);
|
||||||
|
self.overlays[oid].config.activate(app);
|
||||||
}
|
}
|
||||||
let ret_val = self.overlays.insert(overlay);
|
|
||||||
if !internal && let Err(e) = self.overlays_changed(app) {
|
if !internal && let Err(e) = self.overlays_changed(app) {
|
||||||
log::error!("Error while adding overlay: {e:?}");
|
log::error!("Error while adding overlay: {e:?}");
|
||||||
}
|
}
|
||||||
ret_val
|
oid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn switch_or_toggle_set(&mut self, app: &mut AppState, set: usize) {
|
pub fn switch_or_toggle_set(&mut self, app: &mut AppState, set: usize) {
|
||||||
@@ -495,9 +575,6 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
} else {
|
} else {
|
||||||
self.switch_to_set(app, None);
|
self.switch_to_set(app, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle watch back on if it was hidden
|
|
||||||
self.mut_by_id(self.watch_id).unwrap().config.activate(app);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlays_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
fn overlays_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use slotmap::SecondaryMap;
|
use slotmap::SecondaryMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wlx_common::windowing::OverlayWindowState;
|
use wlx_common::{astr_containers::AStrMap, windowing::OverlayWindowState};
|
||||||
|
|
||||||
use crate::windowing::OverlayID;
|
use crate::windowing::OverlayID;
|
||||||
|
|
||||||
@@ -8,4 +8,7 @@ use crate::windowing::OverlayID;
|
|||||||
pub struct OverlayWindowSet {
|
pub struct OverlayWindowSet {
|
||||||
pub(super) name: Arc<str>,
|
pub(super) name: Arc<str>,
|
||||||
pub(super) overlays: SecondaryMap<OverlayID, OverlayWindowState>,
|
pub(super) overlays: SecondaryMap<OverlayID, OverlayWindowState>,
|
||||||
|
|
||||||
|
// stores overlays that have not been seen since startup.
|
||||||
|
pub(super) inactive_overlays: AStrMap<OverlayWindowState>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,10 @@ impl OverlayWindowConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_active(&self) -> bool {
|
||||||
|
self.active_state.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn activate(&mut self, app: &mut AppState) {
|
pub fn activate(&mut self, app: &mut AppState) {
|
||||||
log::debug!("activate {}", self.name.as_ref());
|
log::debug!("activate {}", self.name.as_ref());
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
@@ -111,14 +115,6 @@ impl OverlayWindowConfig {
|
|||||||
self.reset(app, true);
|
self.reset(app, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate_static(&mut self, global_transform: Affine3A) {
|
|
||||||
log::debug!("activate {}", self.name.as_ref());
|
|
||||||
self.dirty = true;
|
|
||||||
let mut state = self.default_state.clone();
|
|
||||||
state.transform = global_transform;
|
|
||||||
self.active_state = Some(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deactivate(&mut self) {
|
pub fn deactivate(&mut self) {
|
||||||
log::debug!("deactivate {}", self.name.as_ref());
|
log::debug!("deactivate {}", self.name.as_ref());
|
||||||
self.active_state = None;
|
self.active_state = None;
|
||||||
@@ -128,7 +124,7 @@ impl OverlayWindowConfig {
|
|||||||
if self.active_state.take().is_none() {
|
if self.active_state.take().is_none() {
|
||||||
self.activate(app);
|
self.activate(app);
|
||||||
} else {
|
} else {
|
||||||
log::debug!("deactivate {}", self.name.as_ref());
|
log::debug!("deactivate {} (toggle)", self.name.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,16 +245,14 @@ pub fn realign(transform: &mut Affine3A, hmd: &Affine3A) {
|
|||||||
transform.matrix3 = Mat3A::from_cols(col_x, col_y, col_z).mul_scalar(scale) * rot;
|
transform.matrix3 = Mat3A::from_cols(col_x, col_y, col_z).mul_scalar(scale) * rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_transform(state: &mut OverlayWindowState, app: &mut AppState) -> bool {
|
pub fn save_transform(state: &mut OverlayWindowState, app: &mut AppState) {
|
||||||
let parent_transform = match state.positioning {
|
let parent_transform = match state.positioning {
|
||||||
Positioning::Floating => snap_upright(app.input_state.hmd, Vec3A::Y),
|
Positioning::Floating => snap_upright(app.input_state.hmd, Vec3A::Y),
|
||||||
Positioning::FollowHead { .. } => app.input_state.hmd,
|
Positioning::FollowHead { .. } => app.input_state.hmd,
|
||||||
Positioning::FollowHand { hand, .. } => app.input_state.pointers[hand as usize].pose,
|
Positioning::FollowHand { hand, .. } => app.input_state.pointers[hand as usize].pose,
|
||||||
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
|
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
|
||||||
Positioning::Static => return false,
|
Positioning::Static => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
state.saved_transform = Some(parent_transform.inverse() * state.transform);
|
state.saved_transform = Some(parent_transform.inverse() * state.transform);
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user