feat: persist layout between sessions

This commit is contained in:
galister
2024-04-25 08:53:54 +09:00
parent 5afb5ed4ab
commit c70833b86a
9 changed files with 65 additions and 44 deletions

1
Cargo.lock generated
View File

@@ -1651,6 +1651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9"
dependencies = [ dependencies = [
"approx", "approx",
"serde",
] ]
[[package]] [[package]]

View File

@@ -23,7 +23,7 @@ flexi_logger = "0.28.0"
fontconfig-rs = "0.1.1" fontconfig-rs = "0.1.1"
freetype-rs = "0.36.0" freetype-rs = "0.36.0"
futures = "0.3.29" futures = "0.3.29"
glam = { version = "0.27.0", features = ["approx"] } glam = { version = "0.27.0", features = ["approx", "serde"] }
idmap = { version = "0.2.21", features = ["serde"] } idmap = { version = "0.2.21", features = ["serde"] }
idmap-derive = "0.1.2" idmap-derive = "0.1.2"
input-linux = "0.6.0" input-linux = "0.6.0"

View File

@@ -10,10 +10,10 @@ use serde::Deserialize;
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
config::{AStrMapExt, AStrSetExt}, config::AStrSetExt,
overlays::{ overlays::{
anchor::create_anchor, anchor::create_anchor,
keyboard::{create_keyboard, KEYBOARD_NAME}, keyboard::create_keyboard,
screen::WlxClientAlias, screen::WlxClientAlias,
watch::{create_watch, WATCH_NAME}, watch::{create_watch, WATCH_NAME},
}, },
@@ -82,12 +82,6 @@ where
state.show_hide = true; state.show_hide = true;
state.want_visible = false; state.want_visible = false;
} }
state.curvature = app
.session
.config
.curve_values
.arc_get(state.name.as_ref())
.copied();
overlays.insert( overlays.insert(
state.id, state.id,
OverlayData::<T> { OverlayData::<T> {
@@ -109,12 +103,6 @@ where
let mut keyboard = create_keyboard(app)?; let mut keyboard = create_keyboard(app)?;
keyboard.state.show_hide = true; keyboard.state.show_hide = true;
keyboard.state.want_visible = false; keyboard.state.want_visible = false;
keyboard.state.curvature = app
.session
.config
.curve_values
.arc_get(KEYBOARD_NAME)
.copied();
overlays.insert(keyboard.state.id, keyboard); overlays.insert(keyboard.state.id, keyboard);
Ok(Self { overlays, wl }) Ok(Self { overlays, wl })

View File

@@ -535,7 +535,6 @@ impl Pointer {
Some(snap_upright(*anchor, Vec3A::Y).inverse() * overlay.state.transform); Some(snap_upright(*anchor, Vec3A::Y).inverse() * overlay.state.transform);
if let Some(grab_data) = self.interaction.grabbed.as_ref() { if let Some(grab_data) = self.interaction.grabbed.as_ref() {
let mut state_dirty = false;
if overlay.state.curvature != grab_data.old_curvature { if overlay.state.curvature != grab_data.old_curvature {
if let Some(val) = overlay.state.curvature { if let Some(val) = overlay.state.curvature {
config.curve_values.arc_ins(overlay.state.name.clone(), val); config.curve_values.arc_ins(overlay.state.name.clone(), val);
@@ -543,13 +542,14 @@ impl Pointer {
let ref_name = overlay.state.name.as_ref(); let ref_name = overlay.state.name.as_ref();
config.curve_values.arc_rm(ref_name); config.curve_values.arc_rm(ref_name);
} }
state_dirty = true;
} }
if state_dirty { config.transform_values.arc_ins(
match save_state(config) { overlay.state.name.clone(),
Ok(_) => log::debug!("Saved state"), overlay.state.saved_transform.unwrap(),
Err(e) => log::error!("Failed to save state: {:?}", e), );
} match save_state(config) {
Ok(_) => log::debug!("Saved state"),
Err(e) => log::error!("Failed to save state: {:?}", e),
} }
} }

View File

@@ -10,7 +10,7 @@ use anyhow::Ok;
use glam::{Affine2, Affine3A, Mat3A, Quat, Vec2, Vec3, Vec3A}; use glam::{Affine2, Affine3A, Mat3A, Quat, Vec2, Vec3, Vec3A};
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
use crate::state::AppState; use crate::{config::AStrMapExt, state::AppState};
use super::input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit}; use super::input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit};
@@ -178,7 +178,26 @@ where
T: Default, T: Default,
{ {
pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
self.state.reset(app, true); self.state.curvature = app
.session
.config
.curve_values
.arc_get(self.state.name.as_ref())
.copied();
let hard_reset;
if let Some(transform) = app
.session
.config
.transform_values
.arc_get(self.state.name.as_ref())
{
self.state.saved_transform = Some(*transform);
hard_reset = false;
} else {
hard_reset = true;
}
self.state.reset(app, hard_reset);
self.backend.init(app) self.backend.init(app)
} }
pub fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { pub fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {

View File

@@ -11,6 +11,10 @@ use crate::state::LeftRight;
use anyhow::bail; use anyhow::bail;
use config::Config; use config::Config;
use config::File; use config::File;
use glam::vec3a;
use glam::Affine3A;
use glam::Quat;
use glam::Vec3A;
use idmap::IdMap; use idmap::IdMap;
use log::error; use log::error;
use serde::Deserialize; use serde::Deserialize;
@@ -78,12 +82,12 @@ impl AStrSetExt for AStrSet {
pub type PwTokenMap = AStrMap<String>; pub type PwTokenMap = AStrMap<String>;
pub fn def_watch_pos() -> [f32; 3] { pub fn def_watch_pos() -> Vec3A {
[-0.03, -0.01, 0.125] vec3a(-0.03, -0.01, 0.125)
} }
pub fn def_watch_rot() -> [f32; 4] { pub fn def_watch_rot() -> Quat {
[-0.7071066, 0.0007963618, 0.7071066, 0.0] Quat::from_xyzw(-0.7071066, 0.0007963618, 0.7071066, 0.0)
} }
pub fn def_left() -> LeftRight { pub fn def_left() -> LeftRight {
@@ -130,6 +134,10 @@ fn def_curve_values() -> AStrMap<f32> {
AStrMap::new() AStrMap::new()
} }
fn def_transforms() -> AStrMap<Affine3A> {
AStrMap::new()
}
fn def_auto() -> Arc<str> { fn def_auto() -> Arc<str> {
"auto".into() "auto".into()
} }
@@ -145,10 +153,10 @@ fn def_font() -> Arc<str> {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct GeneralConfig { pub struct GeneralConfig {
#[serde(default = "def_watch_pos")] #[serde(default = "def_watch_pos")]
pub watch_pos: [f32; 3], pub watch_pos: Vec3A,
#[serde(default = "def_watch_rot")] #[serde(default = "def_watch_rot")]
pub watch_rot: [f32; 4], pub watch_rot: Quat,
#[serde(default = "def_left")] #[serde(default = "def_left")]
pub watch_hand: LeftRight, pub watch_hand: LeftRight,
@@ -198,6 +206,9 @@ pub struct GeneralConfig {
#[serde(default = "def_curve_values")] #[serde(default = "def_curve_values")]
pub curve_values: AStrMap<f32>, pub curve_values: AStrMap<f32>,
#[serde(default = "def_transforms")]
pub transform_values: AStrMap<Affine3A>,
#[serde(default = "def_auto")] #[serde(default = "def_auto")]
pub capture_method: Arc<str>, pub capture_method: Arc<str>,
@@ -355,8 +366,8 @@ pub fn load_general() -> GeneralConfig {
#[derive(Serialize)] #[derive(Serialize)]
pub struct AutoSettings { pub struct AutoSettings {
pub watch_pos: [f32; 3], pub watch_pos: Vec3A,
pub watch_rot: [f32; 4], pub watch_rot: Quat,
pub watch_hand: LeftRight, 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,
@@ -396,6 +407,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
pub struct AutoState { pub struct AutoState {
pub show_screens: AStrSet, pub show_screens: AStrSet,
pub curve_values: AStrMap<f32>, pub curve_values: AStrMap<f32>,
pub transform_values: AStrMap<Affine3A>,
} }
fn get_state_path() -> PathBuf { fn get_state_path() -> PathBuf {
@@ -403,10 +415,12 @@ fn get_state_path() -> PathBuf {
path.push("zz-saved-state.json5"); path.push("zz-saved-state.json5");
path path
} }
pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> { pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> {
let conf = AutoState { let conf = AutoState {
show_screens: config.show_screens.clone(), show_screens: config.show_screens.clone(),
curve_values: config.curve_values.clone(), curve_values: config.curve_values.clone(),
transform_values: config.transform_values.clone(),
}; };
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic

View File

@@ -6,7 +6,7 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use glam::{Quat, Vec3A, Vec4}; use glam::{Quat, Vec4};
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
@@ -486,15 +486,15 @@ fn run_watch(data: &WatchAction, app: &mut AppState) {
Box::new(|app, o| { Box::new(|app, o| {
if let RelativeTo::Hand(0) = o.relative_to { if let RelativeTo::Hand(0) = o.relative_to {
o.relative_to = RelativeTo::Hand(1); o.relative_to = RelativeTo::Hand(1);
o.spawn_rotation = Quat::from_slice(&app.session.config.watch_rot) o.spawn_rotation = app.session.config.watch_rot
* Quat::from_rotation_x(PI) * Quat::from_rotation_x(PI)
* Quat::from_rotation_z(PI); * Quat::from_rotation_z(PI);
o.spawn_point = Vec3A::from_slice(&app.session.config.watch_pos); o.spawn_point = app.session.config.watch_pos;
o.spawn_point.x *= -1.; o.spawn_point.x *= -1.;
} else { } else {
o.relative_to = RelativeTo::Hand(0); o.relative_to = RelativeTo::Hand(0);
o.spawn_rotation = Quat::from_slice(&app.session.config.watch_rot); o.spawn_rotation = app.session.config.watch_rot;
o.spawn_point = Vec3A::from_slice(&app.session.config.watch_pos); o.spawn_point = app.session.config.watch_pos;
} }
o.dirty = true; o.dirty = true;
Toast::new( Toast::new(

View File

@@ -1,6 +1,6 @@
use std::{f32::consts::PI, ops::Add, sync::Arc, time::Instant}; use std::{f32::consts::PI, ops::Add, sync::Arc, time::Instant};
use glam::{vec3a, Quat, Vec3A}; use glam::{vec3a, Quat};
use idmap_derive::IntegerId; use idmap_derive::IntegerId;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -127,9 +127,8 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
DisplayMethod::Hide => return None, DisplayMethod::Hide => return None,
DisplayMethod::Center => (vec3a(0., -0.2, -0.5), Quat::IDENTITY, RelativeTo::Head), DisplayMethod::Center => (vec3a(0., -0.2, -0.5), Quat::IDENTITY, RelativeTo::Head),
DisplayMethod::Watch => { DisplayMethod::Watch => {
let mut watch_pos = let mut watch_pos = app.session.config.watch_pos + vec3a(-0.005, -0.05, 0.02);
Vec3A::from_slice(&app.session.config.watch_pos) + vec3a(-0.005, -0.05, 0.02); let mut watch_rot = app.session.config.watch_rot;
let mut watch_rot = Quat::from_slice(&app.session.config.watch_rot);
let relative_to = match app.session.config.watch_hand { let relative_to = match app.session.config.watch_hand {
LeftRight::Left => RelativeTo::Hand(0), LeftRight::Left => RelativeTo::Hand(0),
LeftRight::Right => { LeftRight::Right => {

View File

@@ -1,4 +1,4 @@
use glam::{Quat, Vec3A}; use glam::Vec3A;
use crate::{ use crate::{
backend::overlay::{ui_transform, OverlayData, OverlayState, RelativeTo}, backend::overlay::{ui_transform, OverlayData, OverlayState, RelativeTo},
@@ -26,8 +26,8 @@ where
want_visible: true, want_visible: true,
interactable: true, interactable: true,
spawn_scale: config.width, spawn_scale: config.width,
spawn_point: Vec3A::from_slice(&state.session.config.watch_pos), spawn_point: state.session.config.watch_pos,
spawn_rotation: Quat::from_slice(&state.session.config.watch_rot), spawn_rotation: state.session.config.watch_rot,
interaction_transform: ui_transform(&config.size), interaction_transform: ui_transform(&config.size),
relative_to, relative_to,
..Default::default() ..Default::default()