persist sets between sessions
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use glam::{Affine3A, Vec3, Vec3A};
|
||||
use slotmap::{HopSlotMap, Key};
|
||||
use slotmap::{HopSlotMap, Key, SecondaryMap};
|
||||
|
||||
use crate::{
|
||||
overlays::{
|
||||
@@ -8,7 +10,10 @@ use crate::{
|
||||
},
|
||||
state::AppState,
|
||||
windowing::{
|
||||
set::OverlayWindowSet, snap_upright, window::OverlayWindowData, OverlayID, OverlaySelector,
|
||||
set::{OverlayWindowSet, SerializedWindowSet},
|
||||
snap_upright,
|
||||
window::OverlayWindowData,
|
||||
OverlayID, OverlaySelector,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -43,7 +48,9 @@ where
|
||||
if headless {
|
||||
log::info!("Running in headless mode; keyboard will be en-US");
|
||||
} else {
|
||||
// create one work set for each screen.
|
||||
// create one window set for each screen.
|
||||
// this is the default and would be overwritten by
|
||||
// OverlayWindowManager::restore_layout down below
|
||||
match create_screens(app) {
|
||||
Ok((data, keymap)) => {
|
||||
let last_idx = data.screens.len() - 1;
|
||||
@@ -68,6 +75,7 @@ where
|
||||
keyboard.config.show_on_spawn = true;
|
||||
let keyboard_id = me.add(keyboard, app);
|
||||
|
||||
// is this needed?
|
||||
me.switch_to_set(app, None);
|
||||
|
||||
// copy keyboard to all sets
|
||||
@@ -87,13 +95,79 @@ where
|
||||
let watch = OverlayWindowData::from_config(create_watch(app, me.sets.len())?);
|
||||
me.watch_id = me.add(watch, app);
|
||||
|
||||
me.switch_to_set(app, None);
|
||||
// overwrite default layout with saved layout, if exists
|
||||
me.restore_layout(app);
|
||||
|
||||
Ok(me)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OverlayWindowManager<T> {
|
||||
pub fn persist_layout(&mut self, app: &mut AppState) {
|
||||
app.session.config.sets.clear();
|
||||
app.session.config.sets.reserve(self.sets.len());
|
||||
app.session.config.last_set = self.restore_set as _;
|
||||
|
||||
let mut restore_after = false;
|
||||
// only safe to save when current_set is None
|
||||
if self.current_set.is_some() {
|
||||
self.switch_to_set(app, None);
|
||||
restore_after = true;
|
||||
}
|
||||
|
||||
for set in self.sets.iter() {
|
||||
let overlays: HashMap<_, _> = set
|
||||
.overlays
|
||||
.iter()
|
||||
.filter_map(|(k, v)| {
|
||||
let Some(n) = self.overlays.get(k).map(|o| o.config.name.clone()) else {
|
||||
return None;
|
||||
};
|
||||
Some((n, v.clone()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let serialized = SerializedWindowSet {
|
||||
name: set.name.clone(),
|
||||
overlays,
|
||||
};
|
||||
app.session.config.sets.push(serialized);
|
||||
}
|
||||
|
||||
if restore_after {
|
||||
self.switch_to_set(app, Some(self.restore_set));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restore_layout(&mut self, app: &mut AppState) {
|
||||
if app.session.config.sets.is_empty() {
|
||||
// keep defaults
|
||||
return;
|
||||
}
|
||||
|
||||
// only safe to load when current_set is None
|
||||
if self.current_set.is_some() {
|
||||
self.switch_to_set(app, None);
|
||||
}
|
||||
|
||||
self.sets.clear();
|
||||
self.sets.reserve(app.session.config.sets.len());
|
||||
|
||||
for s in app.session.config.sets.iter() {
|
||||
let overlays: SecondaryMap<_, _> = s
|
||||
.overlays
|
||||
.iter()
|
||||
.filter_map(|(name, v)| self.lookup(&name).map(|id| (id, v.clone())))
|
||||
.collect();
|
||||
|
||||
self.sets.push(OverlayWindowSet {
|
||||
name: s.name.clone(),
|
||||
overlays,
|
||||
});
|
||||
}
|
||||
self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1);
|
||||
}
|
||||
|
||||
pub fn mut_by_selector(
|
||||
&mut self,
|
||||
selector: &OverlaySelector,
|
||||
@@ -151,7 +225,6 @@ impl<T> OverlayWindowManager<T> {
|
||||
if overlay.config.show_on_spawn {
|
||||
overlay.config.activate(app);
|
||||
}
|
||||
|
||||
self.overlays.insert(overlay)
|
||||
}
|
||||
|
||||
@@ -188,7 +261,7 @@ impl<T> OverlayWindowManager<T> {
|
||||
|
||||
if let Some(new_set) = new_set {
|
||||
if new_set >= self.sets.len() {
|
||||
log::warn!("switch_to_set: new_set is out of range ({new_set:?})");
|
||||
log::error!("switch_to_set: new_set is out of range ({new_set:?})");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
||||
|
||||
pub mod backend;
|
||||
pub mod manager;
|
||||
mod set;
|
||||
pub mod set;
|
||||
pub mod window;
|
||||
|
||||
new_key_type! {
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slotmap::SecondaryMap;
|
||||
|
||||
use crate::windowing::{window::OverlayWindowState, OverlayID};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OverlayWindowSet {
|
||||
pub(super) name: Arc<str>,
|
||||
pub(super) overlays: SecondaryMap<OverlayID, OverlayWindowState>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SerializedWindowSet {
|
||||
pub name: Arc<str>,
|
||||
pub overlays: HashMap<Arc<str>, OverlayWindowState>,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use glam::{Affine3A, Mat3A, Quat, Vec3, Vec3A};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{f32::consts::PI, sync::Arc};
|
||||
use vulkano::image::view::ImageView;
|
||||
|
||||
use crate::{
|
||||
graphics::CommandBuffers,
|
||||
state::AppState,
|
||||
state::{AppState, LeftRight},
|
||||
subsystem::input::KeyboardFocus,
|
||||
windowing::{
|
||||
backend::{FrameMeta, OverlayBackend, ShouldRender},
|
||||
@@ -12,7 +13,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
|
||||
pub enum Positioning {
|
||||
/// Stays in place, recenters relative to HMD
|
||||
#[default]
|
||||
@@ -26,19 +27,14 @@ pub enum Positioning {
|
||||
/// Normally follows HMD, but paused due to interaction
|
||||
FollowHeadPaused { lerp: f32 },
|
||||
/// Following hand
|
||||
FollowHand { hand: usize, lerp: f32 },
|
||||
FollowHand { hand: LeftRight, lerp: f32 },
|
||||
/// Normally follows hand, but paused due to interaction
|
||||
FollowHandPaused { hand: usize, lerp: f32 },
|
||||
/// Follow another overlay
|
||||
FollowOverlay { id: usize },
|
||||
FollowHandPaused { hand: LeftRight, lerp: f32 },
|
||||
}
|
||||
|
||||
impl Positioning {
|
||||
pub const fn moves_with_space(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Floating | Self::Anchored | Self::Static
|
||||
)
|
||||
matches!(self, Self::Floating | Self::Anchored | Self::Static)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,9 +150,10 @@ impl OverlayWindowConfig {
|
||||
|
||||
let (target_transform, lerp) = match state.positioning {
|
||||
Positioning::FollowHead { lerp } => (app.input_state.hmd * cur_transform, lerp),
|
||||
Positioning::FollowHand { hand, lerp } => {
|
||||
(app.input_state.pointers[hand].pose * cur_transform, lerp)
|
||||
}
|
||||
Positioning::FollowHand { hand, lerp } => (
|
||||
app.input_state.pointers[hand as usize].pose * cur_transform,
|
||||
lerp,
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
@@ -196,10 +193,10 @@ impl OverlayWindowConfig {
|
||||
app.input_state.hmd
|
||||
}
|
||||
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
||||
app.input_state.pointers[hand].pose
|
||||
app.input_state.pointers[hand as usize].pose
|
||||
}
|
||||
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
|
||||
Positioning::FollowOverlay { .. } | Positioning::Static => return false,
|
||||
Positioning::Static => return false,
|
||||
};
|
||||
|
||||
self.saved_transform = Some(parent_transform.inverse() * state.transform);
|
||||
@@ -219,10 +216,10 @@ impl OverlayWindowConfig {
|
||||
| Positioning::FollowHead { .. }
|
||||
| Positioning::FollowHeadPaused { .. } => app.input_state.hmd,
|
||||
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
||||
app.input_state.pointers[hand].pose
|
||||
app.input_state.pointers[hand as usize].pose
|
||||
}
|
||||
Positioning::Anchored => app.anchor,
|
||||
Positioning::FollowOverlay { .. } | Positioning::Static => return,
|
||||
Positioning::Static => return,
|
||||
};
|
||||
|
||||
if hard_reset {
|
||||
@@ -284,7 +281,7 @@ impl OverlayWindowConfig {
|
||||
}
|
||||
|
||||
// Contains the window state for a given set
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct OverlayWindowState {
|
||||
pub transform: Affine3A,
|
||||
pub alpha: f32,
|
||||
|
||||
Reference in New Issue
Block a user