mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-20 11:35:48 +00:00
Merge branch 'feat/genericTrackersFromLibmonado' into 'main'
feat: list generic trackers from libmonado, remove log parsing See merge request gabmus/envision!27
This commit is contained in:
commit
a081639a6f
14 changed files with 70 additions and 683 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -67,17 +67,17 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.68.1"
|
||||
version = "0.69.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
|
||||
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -230,9 +230,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
|||
|
||||
[[package]]
|
||||
name = "dlopen2"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03"
|
||||
checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6"
|
||||
dependencies = [
|
||||
"dlopen2_derive",
|
||||
"libc",
|
||||
|
@ -967,6 +967,15 @@ version = "2.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
|
@ -1068,7 +1077,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libmonado-rs"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/technobaboo/libmonado-rs#d79d5bf11586b8010d8aa016097ebdb07f683c64"
|
||||
source = "git+https://github.com/technobaboo/libmonado-rs?rev=e32e78c79ce9ec4a5a5de9eff30661c6c4307347#e32e78c79ce9ec4a5a5de9eff30661c6c4307347"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cmake",
|
||||
|
@ -1378,12 +1387,6 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
|
|
|
@ -18,7 +18,7 @@ lazy_static = "1.4.0"
|
|||
libadwaita = { version = "0.6.0", features = [
|
||||
"v1_4"
|
||||
] }
|
||||
libmonado-rs = { git = "https://github.com/technobaboo/libmonado-rs", version = "0.1.0" }
|
||||
libmonado-rs = { git = "https://github.com/technobaboo/libmonado-rs", rev = "e32e78c79ce9ec4a5a5de9eff30661c6c4307347" }
|
||||
rusb = "0.9.4"
|
||||
nix = { version = "0.29.0", features = [
|
||||
"fs",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
pub mod active_runtime_json;
|
||||
pub mod monado_autorun;
|
||||
pub mod monado_config_v0;
|
||||
pub mod openvrpaths_vrpath;
|
||||
pub mod wivrn_config;
|
||||
|
|
|
@ -1,259 +0,0 @@
|
|||
use crate::{
|
||||
file_utils::{deserialize_file, get_writer_legacy},
|
||||
paths::get_xdg_config_dir,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::slice::Iter;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum XrtInputName {
|
||||
#[serde(rename = "XRT_INPUT_GENERIC_TRACKER_POSE")]
|
||||
XrtInputGenericTrackerPose,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum XrtTrackerRole {
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/waist")]
|
||||
ViveTrackerHtcxWaist,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/left_foot")]
|
||||
ViveTrackerHtcxLeftFoot,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/right_foot")]
|
||||
ViveTrackerHtcxRightFoot,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/handheld_object")]
|
||||
ViveTrackerHtcxHandheldObject,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/left_shoulder")]
|
||||
ViveTrackerHtcxLeftShoulder,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/right_shoulder")]
|
||||
ViveTrackerHtcxRightShoulder,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/left_elbow")]
|
||||
ViveTrackerHtcxLeftElbow,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/right_elbow")]
|
||||
ViveTrackerHtcxRightElbow,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/left_knee")]
|
||||
ViveTrackerHtcxLeftKnee,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/right_knee")]
|
||||
ViveTrackerHtcxRightKnee,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/chest")]
|
||||
ViveTrackerHtcxChest,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/camera")]
|
||||
ViveTrackerHtcxCamera,
|
||||
#[serde(rename = "/user/vive_tracker_htcx/role/keyboard")]
|
||||
ViveTrackerHtcxKeyboard,
|
||||
}
|
||||
|
||||
impl XrtTrackerRole {
|
||||
pub fn to_picker_string(&self) -> &str {
|
||||
match self {
|
||||
Self::ViveTrackerHtcxWaist => "Waist",
|
||||
Self::ViveTrackerHtcxLeftFoot => "Left foot",
|
||||
Self::ViveTrackerHtcxRightFoot => "Right foot",
|
||||
Self::ViveTrackerHtcxHandheldObject => "Handheld object",
|
||||
Self::ViveTrackerHtcxLeftShoulder => "Left shoulder",
|
||||
Self::ViveTrackerHtcxRightShoulder => "Right shoulder",
|
||||
Self::ViveTrackerHtcxLeftElbow => "Left elbow",
|
||||
Self::ViveTrackerHtcxRightElbow => "Right elbow",
|
||||
Self::ViveTrackerHtcxLeftKnee => "Left knee",
|
||||
Self::ViveTrackerHtcxRightKnee => "Right knee",
|
||||
Self::ViveTrackerHtcxChest => "Chest",
|
||||
Self::ViveTrackerHtcxCamera => "Camera",
|
||||
Self::ViveTrackerHtcxKeyboard => "Keyboard",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_picker_string(s: &str) -> Self {
|
||||
match s.to_lowercase().trim() {
|
||||
"waist" => Self::ViveTrackerHtcxWaist,
|
||||
"left foot" => Self::ViveTrackerHtcxLeftFoot,
|
||||
"right foot" => Self::ViveTrackerHtcxRightFoot,
|
||||
"handheld object" => Self::ViveTrackerHtcxHandheldObject,
|
||||
"left shoulder" => Self::ViveTrackerHtcxLeftShoulder,
|
||||
"right shoulder" => Self::ViveTrackerHtcxRightShoulder,
|
||||
"left elbow" => Self::ViveTrackerHtcxLeftElbow,
|
||||
"right elbow" => Self::ViveTrackerHtcxRightElbow,
|
||||
"left knee" => Self::ViveTrackerHtcxLeftKnee,
|
||||
"right knee" => Self::ViveTrackerHtcxRightKnee,
|
||||
"chest" => Self::ViveTrackerHtcxChest,
|
||||
"camera" => Self::ViveTrackerHtcxCamera,
|
||||
"keyboard" => Self::ViveTrackerHtcxKeyboard,
|
||||
_ => Self::ViveTrackerHtcxWaist,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter() -> Iter<'static, Self> {
|
||||
[
|
||||
Self::ViveTrackerHtcxWaist,
|
||||
Self::ViveTrackerHtcxLeftFoot,
|
||||
Self::ViveTrackerHtcxRightFoot,
|
||||
Self::ViveTrackerHtcxHandheldObject,
|
||||
Self::ViveTrackerHtcxLeftShoulder,
|
||||
Self::ViveTrackerHtcxRightShoulder,
|
||||
Self::ViveTrackerHtcxLeftElbow,
|
||||
Self::ViveTrackerHtcxRightElbow,
|
||||
Self::ViveTrackerHtcxLeftKnee,
|
||||
Self::ViveTrackerHtcxRightKnee,
|
||||
Self::ViveTrackerHtcxChest,
|
||||
Self::ViveTrackerHtcxCamera,
|
||||
Self::ViveTrackerHtcxKeyboard,
|
||||
]
|
||||
.iter()
|
||||
}
|
||||
|
||||
pub fn to_number(&self) -> u32 {
|
||||
match self {
|
||||
Self::ViveTrackerHtcxWaist => 0,
|
||||
Self::ViveTrackerHtcxLeftFoot => 1,
|
||||
Self::ViveTrackerHtcxRightFoot => 2,
|
||||
Self::ViveTrackerHtcxHandheldObject => 3,
|
||||
Self::ViveTrackerHtcxLeftShoulder => 4,
|
||||
Self::ViveTrackerHtcxRightShoulder => 5,
|
||||
Self::ViveTrackerHtcxLeftElbow => 6,
|
||||
Self::ViveTrackerHtcxRightElbow => 7,
|
||||
Self::ViveTrackerHtcxLeftKnee => 8,
|
||||
Self::ViveTrackerHtcxRightKnee => 9,
|
||||
Self::ViveTrackerHtcxChest => 10,
|
||||
Self::ViveTrackerHtcxCamera => 11,
|
||||
Self::ViveTrackerHtcxKeyboard => 12,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_number(n: &u32) -> Self {
|
||||
match n {
|
||||
0 => Self::ViveTrackerHtcxWaist,
|
||||
1 => Self::ViveTrackerHtcxLeftFoot,
|
||||
2 => Self::ViveTrackerHtcxRightFoot,
|
||||
3 => Self::ViveTrackerHtcxHandheldObject,
|
||||
4 => Self::ViveTrackerHtcxLeftShoulder,
|
||||
5 => Self::ViveTrackerHtcxRightShoulder,
|
||||
6 => Self::ViveTrackerHtcxLeftElbow,
|
||||
7 => Self::ViveTrackerHtcxRightElbow,
|
||||
8 => Self::ViveTrackerHtcxLeftKnee,
|
||||
9 => Self::ViveTrackerHtcxRightKnee,
|
||||
10 => Self::ViveTrackerHtcxChest,
|
||||
11 => Self::ViveTrackerHtcxCamera,
|
||||
12 => Self::ViveTrackerHtcxKeyboard,
|
||||
_ => Self::ViveTrackerHtcxWaist,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TrackerRole {
|
||||
pub device_serial: String,
|
||||
pub role: XrtTrackerRole,
|
||||
pub xrt_input_name: XrtInputName,
|
||||
}
|
||||
|
||||
impl Default for TrackerRole {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
device_serial: "".into(),
|
||||
role: XrtTrackerRole::ViveTrackerHtcxWaist,
|
||||
xrt_input_name: XrtInputName::XrtInputGenericTrackerPose,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MonadoConfigV0 {
|
||||
#[serde(skip_serializing_if = "Option::is_none", rename = "$schema")]
|
||||
_schema: Option<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub tracker_roles: Vec<TrackerRole>,
|
||||
}
|
||||
|
||||
impl Default for MonadoConfigV0 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
_schema: Some(
|
||||
"https://monado.pages.freedesktop.org/monado/config_v0.schema.json".to_string(),
|
||||
),
|
||||
tracker_roles: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MonadoConfigV0 {
|
||||
pub fn has_tracker_serial(&self, serial: &str) -> bool {
|
||||
self.tracker_roles.iter().any(|t| t.device_serial == serial)
|
||||
}
|
||||
|
||||
pub fn get_next_free_xrt_tracker_role(&self) -> XrtTrackerRole {
|
||||
XrtTrackerRole::iter()
|
||||
.find(|role| !self.tracker_roles.iter().any(|et| et.role == **role))
|
||||
.unwrap_or(&XrtTrackerRole::ViveTrackerHtcxHandheldObject)
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_monado_config_v0_path() -> String {
|
||||
format!(
|
||||
"{config}/monado/config_v0.json",
|
||||
config = get_xdg_config_dir()
|
||||
)
|
||||
}
|
||||
|
||||
fn get_monado_config_v0_from_path(path_s: &String) -> Option<MonadoConfigV0> {
|
||||
deserialize_file(path_s)
|
||||
}
|
||||
|
||||
pub fn get_monado_config_v0() -> MonadoConfigV0 {
|
||||
get_monado_config_v0_from_path(&get_monado_config_v0_path())
|
||||
.unwrap_or(MonadoConfigV0::default())
|
||||
}
|
||||
|
||||
fn dump_monado_config_v0_to_path(config: &MonadoConfigV0, path_s: &String) {
|
||||
let writer = get_writer_legacy(path_s);
|
||||
serde_json::to_writer_pretty(writer, config).expect("Unable to save Monado config V0");
|
||||
}
|
||||
|
||||
pub fn dump_monado_config_v0(config: &MonadoConfigV0) {
|
||||
dump_monado_config_v0_to_path(config, &get_monado_config_v0_path());
|
||||
}
|
||||
|
||||
pub fn dump_generic_trackers(trackers: &[String]) -> usize {
|
||||
let mut conf = get_monado_config_v0();
|
||||
let mut added: usize = 0;
|
||||
trackers.iter().for_each(|serial| {
|
||||
if !conf.has_tracker_serial(serial) {
|
||||
conf.tracker_roles.push(TrackerRole {
|
||||
device_serial: serial.to_string(),
|
||||
role: conf.get_next_free_xrt_tracker_role(),
|
||||
..TrackerRole::default()
|
||||
});
|
||||
added += 1;
|
||||
}
|
||||
});
|
||||
|
||||
if added > 0 {
|
||||
dump_monado_config_v0(&conf);
|
||||
}
|
||||
|
||||
added
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::get_monado_config_v0_from_path;
|
||||
use crate::file_builders::monado_config_v0::{XrtInputName, XrtTrackerRole};
|
||||
|
||||
#[test]
|
||||
fn can_read_monado_config_v0() {
|
||||
let conf = get_monado_config_v0_from_path(&"./test/files/monado_config_v0.json".into())
|
||||
.expect("Couldn't find monado config v0");
|
||||
assert_eq!(conf.tracker_roles.len(), 3);
|
||||
assert_eq!(
|
||||
conf.tracker_roles
|
||||
.get(0)
|
||||
.expect("could not get tracker role zero")
|
||||
.role,
|
||||
XrtTrackerRole::ViveTrackerHtcxWaist
|
||||
);
|
||||
assert_eq!(
|
||||
conf.tracker_roles
|
||||
.get(0)
|
||||
.expect("could not get tracker role zero")
|
||||
.xrt_input_name,
|
||||
XrtInputName::XrtInputGenericTrackerPose
|
||||
);
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ impl LinuxDistro {
|
|||
let mut buf = String::new();
|
||||
if reader.read_to_string(&mut buf).is_ok() {
|
||||
buf = buf.trim().to_lowercase();
|
||||
return Self::name_matcher(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,7 @@ use crate::{
|
|||
profile::Profile,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use std::{
|
||||
fs::read_to_string,
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
use std::{fs::read_to_string, io::Write, path::Path};
|
||||
|
||||
fn get_runtime_entrypoint_path() -> Option<String> {
|
||||
let mut out = format!(
|
||||
|
|
|
@ -3,7 +3,6 @@ use super::alert::{alert, alert_w_widget};
|
|||
use super::build_window::{BuildStatus, BuildWindow};
|
||||
use super::cmdline_opts::CmdLineOpts;
|
||||
use super::debug_view::{DebugView, DebugViewMsg};
|
||||
use super::fbt_config_editor::{FbtConfigEditor, FbtConfigEditorInit, FbtConfigEditorMsg};
|
||||
use super::job_worker::internal_worker::JobWorkerOut;
|
||||
use super::job_worker::job::WorkerJob;
|
||||
use super::job_worker::JobWorker;
|
||||
|
@ -35,7 +34,6 @@ use crate::file_builders::openvrpaths_vrpath::{
|
|||
};
|
||||
use crate::file_utils::setcap_cap_sys_nice_eip;
|
||||
use crate::linux_distro::LinuxDistro;
|
||||
use crate::log_parser::MonadoLog;
|
||||
use crate::paths::{get_data_dir, get_ipc_file_path};
|
||||
use crate::profile::{Profile, XRServiceType};
|
||||
use crate::stateless_action;
|
||||
|
@ -100,8 +98,6 @@ pub struct App {
|
|||
#[tracker::do_not_track]
|
||||
xr_devices: Vec<XRDevice>,
|
||||
#[tracker::do_not_track]
|
||||
fbt_config_editor: Option<Controller<FbtConfigEditor>>,
|
||||
#[tracker::do_not_track]
|
||||
libmonado: Option<libmonado_rs::Monado>,
|
||||
|
||||
#[tracker::do_not_track]
|
||||
|
@ -132,8 +128,6 @@ pub enum Msg {
|
|||
OpenLibsurviveSetup,
|
||||
SaveWinSize(i32, i32),
|
||||
Quit,
|
||||
ParseLog(Vec<String>),
|
||||
ConfigFbt,
|
||||
DebugOpenPrefix,
|
||||
DebugOpenData,
|
||||
OpenWivrnConfig,
|
||||
|
@ -331,7 +325,6 @@ impl SimpleComponent for App {
|
|||
match message {
|
||||
Msg::OnServiceLog(rows) => {
|
||||
if !rows.is_empty() {
|
||||
sender.input(Msg::ParseLog(rows.clone()));
|
||||
self.debug_view
|
||||
.sender()
|
||||
.emit(DebugViewMsg::LogUpdated(rows));
|
||||
|
@ -387,20 +380,6 @@ impl SimpleComponent for App {
|
|||
}
|
||||
}
|
||||
}
|
||||
Msg::ParseLog(rows) => {
|
||||
for row in rows {
|
||||
match MonadoLog::new_from_str(row.as_str()) {
|
||||
None => {}
|
||||
Some(parsed) => {
|
||||
if let Some(tracker) =
|
||||
XRDevice::generic_tracker_from_log_row(parsed.message.as_str())
|
||||
{
|
||||
self.xr_devices.push(tracker);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Msg::EnableDebugViewChanged(val) => {
|
||||
self.set_enable_debug_view(val);
|
||||
self.config.debug_view_enabled = val;
|
||||
|
@ -685,19 +664,6 @@ impl SimpleComponent for App {
|
|||
))
|
||||
.expect("Failed to present Libsurvive Setup Window");
|
||||
}
|
||||
Msg::ConfigFbt => {
|
||||
self.fbt_config_editor = Some(
|
||||
FbtConfigEditor::builder()
|
||||
.launch(FbtConfigEditorInit {
|
||||
root_win: self.app_win.clone().upcast::<gtk::Window>(),
|
||||
})
|
||||
.detach(),
|
||||
);
|
||||
self.fbt_config_editor
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.emit(FbtConfigEditorMsg::Present);
|
||||
}
|
||||
Msg::SaveWinSize(w, h) => {
|
||||
self.config.win_size = [w, h];
|
||||
self.config.save();
|
||||
|
@ -829,7 +795,6 @@ impl SimpleComponent for App {
|
|||
autostart_worker: None,
|
||||
build_worker: None,
|
||||
xr_devices: vec![],
|
||||
fbt_config_editor: None,
|
||||
restart_xrservice: false,
|
||||
libmonado: None,
|
||||
wivrn_conf_editor: None,
|
||||
|
@ -853,13 +818,6 @@ impl SimpleComponent for App {
|
|||
sender.input_sender().emit(Msg::BuildProfile(true));
|
||||
})
|
||||
);
|
||||
stateless_action!(
|
||||
actions,
|
||||
ConfigFbtAction,
|
||||
clone!(@strong sender => move |_| {
|
||||
sender.input_sender().emit(Msg::ConfigFbt);
|
||||
})
|
||||
);
|
||||
{
|
||||
let abd_sender = model.about_dialog.sender().clone();
|
||||
stateless_action!(actions, AboutAction, move |_| {
|
||||
|
@ -928,7 +886,6 @@ new_action_group!(pub AppActionGroup, "win");
|
|||
new_stateless_action!(pub AboutAction, AppActionGroup, "about");
|
||||
new_stateless_action!(pub BuildProfileAction, AppActionGroup, "buildprofile");
|
||||
new_stateless_action!(pub BuildProfileCleanAction, AppActionGroup, "buildprofileclean");
|
||||
new_stateless_action!(pub ConfigFbtAction, AppActionGroup, "configfbt");
|
||||
new_stateless_action!(pub QuitAction, AppActionGroup, "quit");
|
||||
new_stateful_action!(pub DebugViewToggleAction, AppActionGroup, "debugviewtoggle", (), bool);
|
||||
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
use super::{
|
||||
alert::alert,
|
||||
factories::device_row_factory::{DeviceRowModel, DeviceRowModelInit, DeviceRowState},
|
||||
};
|
||||
use crate::{
|
||||
file_builders::monado_config_v0::dump_generic_trackers,
|
||||
xr_devices::{XRDevice, XRDeviceRole},
|
||||
};
|
||||
use super::factories::device_row_factory::{DeviceRowModel, DeviceRowModelInit, DeviceRowState};
|
||||
use crate::xr_devices::{XRDevice, XRDeviceRole};
|
||||
use adw::prelude::*;
|
||||
use relm4::{factory::AsyncFactoryVecDeque, prelude::*, Sender};
|
||||
|
||||
|
@ -20,25 +14,6 @@ pub struct DevicesBox {
|
|||
#[derive(Debug)]
|
||||
pub enum DevicesBoxMsg {
|
||||
UpdateDevices(Vec<XRDevice>),
|
||||
DumpGenericTrackers,
|
||||
}
|
||||
|
||||
impl DevicesBox {
|
||||
fn create_save_trackers_btn(sender: Sender<DevicesBoxMsg>) -> gtk::Button {
|
||||
let btn = gtk::Button::builder()
|
||||
.halign(gtk::Align::Center)
|
||||
.valign(gtk::Align::Center)
|
||||
.icon_name("document-save-symbolic")
|
||||
.tooltip_text("Save current trackers")
|
||||
.css_classes(["circular", "flat"])
|
||||
.build();
|
||||
|
||||
btn.connect_clicked(move |_| {
|
||||
sender.emit(DevicesBoxMsg::DumpGenericTrackers);
|
||||
});
|
||||
|
||||
btn
|
||||
}
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
|
@ -106,13 +81,9 @@ impl SimpleComponent for DevicesBox {
|
|||
subtitle: Some(
|
||||
generic
|
||||
.iter()
|
||||
.map(|d| d.id.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(", "),
|
||||
),
|
||||
suffix: Some(
|
||||
Self::create_save_trackers_btn(sender.input_sender().clone())
|
||||
.upcast::<gtk::Widget>(),
|
||||
.map(|d| format!("{} ({})", d.name, d.index))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n"),
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
|
@ -142,41 +113,6 @@ impl SimpleComponent for DevicesBox {
|
|||
}
|
||||
}
|
||||
}
|
||||
Self::Input::DumpGenericTrackers => {
|
||||
let added = dump_generic_trackers(
|
||||
&self
|
||||
.devices
|
||||
.iter()
|
||||
.filter(|d| d.dev_type == XRDeviceRole::GenericTracker)
|
||||
.map(|d| d.id.clone())
|
||||
.collect::<Vec<String>>(),
|
||||
);
|
||||
let multi_title = format!("Added {} new trackers", added);
|
||||
let (title, msg) = match added {
|
||||
0 => (
|
||||
"No new trackers found",
|
||||
concat!(
|
||||
"All the currently connected trackers ",
|
||||
"are already present in your configuration"
|
||||
),
|
||||
),
|
||||
1 => (
|
||||
"Added 1 new tracker",
|
||||
concat!(
|
||||
"Edit your configuration to make sure that ",
|
||||
"all the trackers have the appropriate roles assigned"
|
||||
),
|
||||
),
|
||||
_ => (
|
||||
multi_title.as_str(),
|
||||
concat!(
|
||||
"Edit your configuration to make sure that ",
|
||||
"all the trackers have the appropriate roles assigned"
|
||||
),
|
||||
),
|
||||
};
|
||||
alert(title, Some(msg), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub mod device_row_factory;
|
||||
pub mod env_var_row_factory;
|
||||
pub mod tracker_role_group_factory;
|
||||
pub mod wivrn_encoder_group_factory;
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
use crate::{
|
||||
file_builders::monado_config_v0::{TrackerRole, XrtTrackerRole},
|
||||
ui::fbt_config_editor::FbtConfigEditorMsg,
|
||||
ui::preference_rows::{combo_row, entry_row},
|
||||
};
|
||||
use adw::prelude::*;
|
||||
use gtk::glib::clone;
|
||||
use relm4::{factory::AsyncFactoryComponent, prelude::*, AsyncFactorySender};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TrackerRoleModel {
|
||||
index: usize,
|
||||
tracker_role: TrackerRole,
|
||||
}
|
||||
|
||||
pub struct TrackerRoleModelInit {
|
||||
pub index: usize,
|
||||
pub tracker_role: Option<TrackerRole>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TrackerRoleModelMsg {
|
||||
Changed(TrackerRole),
|
||||
Delete,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TrackerRoleModelOutMsg {
|
||||
Changed(usize, TrackerRole),
|
||||
Delete(usize),
|
||||
}
|
||||
|
||||
#[relm4::factory(async pub)]
|
||||
impl AsyncFactoryComponent for TrackerRoleModel {
|
||||
type Init = TrackerRoleModelInit;
|
||||
type Input = TrackerRoleModelMsg;
|
||||
type Output = TrackerRoleModelOutMsg;
|
||||
type CommandOutput = ();
|
||||
type ParentWidget = adw::PreferencesPage;
|
||||
|
||||
view! {
|
||||
root = adw::PreferencesGroup {
|
||||
set_title: "Tracker",
|
||||
#[wrap(Some)]
|
||||
set_header_suffix: del_btn = >k::Button {
|
||||
set_icon_name: "edit-delete-symbolic",
|
||||
set_tooltip_text: Some("Delete Tracker"),
|
||||
set_valign: gtk::Align::Center,
|
||||
add_css_class: "flat",
|
||||
add_css_class: "circular",
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(Self::Input::Delete);
|
||||
}
|
||||
},
|
||||
add: {
|
||||
let tr = self.tracker_role.clone();
|
||||
&entry_row(
|
||||
"Device serial",
|
||||
self.tracker_role.device_serial.as_str(),
|
||||
clone!(@strong sender => move |row| {
|
||||
let mut ntr = tr.clone();
|
||||
ntr.device_serial = row.text().to_string();
|
||||
sender.input(Self::Input::Changed(ntr));
|
||||
})
|
||||
)
|
||||
},
|
||||
add: {
|
||||
let tr = self.tracker_role.clone();
|
||||
&combo_row("Tracker role", None, &tr.role.clone().to_picker_string(),
|
||||
XrtTrackerRole::iter()
|
||||
.map(XrtTrackerRole::to_picker_string)
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>(),
|
||||
clone!(@strong sender => move |row| {
|
||||
let mut ntr = tr.clone();
|
||||
ntr.role = XrtTrackerRole::from_number(&row.selected());
|
||||
sender.input(Self::Input::Changed(ntr));
|
||||
})
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(&mut self, message: Self::Input, sender: AsyncFactorySender<Self>) {
|
||||
match message {
|
||||
Self::Input::Changed(r) => {
|
||||
self.tracker_role = r;
|
||||
sender.output(Self::Output::Changed(self.index, self.tracker_role.clone()));
|
||||
}
|
||||
Self::Input::Delete => {
|
||||
sender.output(Self::Output::Delete(self.index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn init_model(
|
||||
init: Self::Init,
|
||||
_index: &DynamicIndex,
|
||||
_sender: AsyncFactorySender<Self>,
|
||||
) -> Self {
|
||||
Self {
|
||||
index: init.index,
|
||||
tracker_role: init.tracker_role.unwrap_or_else(|| TrackerRole::default()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
use super::factories::tracker_role_group_factory::{TrackerRoleModel, TrackerRoleModelOutMsg};
|
||||
use crate::{
|
||||
file_builders::monado_config_v0::{
|
||||
dump_monado_config_v0, get_monado_config_v0, MonadoConfigV0, TrackerRole,
|
||||
},
|
||||
ui::factories::tracker_role_group_factory::TrackerRoleModelInit,
|
||||
};
|
||||
use adw::prelude::*;
|
||||
use gtk::glib::clone;
|
||||
use relm4::{factory::AsyncFactoryVecDeque, prelude::*};
|
||||
|
||||
#[tracker::track]
|
||||
pub struct FbtConfigEditor {
|
||||
monado_config_v0: MonadoConfigV0,
|
||||
|
||||
#[tracker::do_not_track]
|
||||
win: Option<adw::Window>,
|
||||
|
||||
#[tracker::do_not_track]
|
||||
tracker_role_groups: AsyncFactoryVecDeque<TrackerRoleModel>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FbtConfigEditorMsg {
|
||||
Present,
|
||||
Save,
|
||||
TrackerRoleNew,
|
||||
TrackerRoleChanged(usize, TrackerRole),
|
||||
TrackerRoleDeleted(usize),
|
||||
Repopulate,
|
||||
}
|
||||
|
||||
pub struct FbtConfigEditorInit {
|
||||
pub root_win: gtk::Window,
|
||||
}
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for FbtConfigEditor {
|
||||
type Init = FbtConfigEditorInit;
|
||||
type Input = FbtConfigEditorMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
#[name(win)]
|
||||
adw::Window {
|
||||
set_title: Some("Full Body Trackers"),
|
||||
set_modal: true,
|
||||
set_transient_for: Some(&init.root_win),
|
||||
set_default_height: 500,
|
||||
set_default_width: 600,
|
||||
adw::ToolbarView {
|
||||
set_top_bar_style: adw::ToolbarStyle::Flat,
|
||||
add_top_bar: headerbar = &adw::HeaderBar {
|
||||
set_vexpand: false,
|
||||
set_hexpand: true,
|
||||
add_css_class: "flat",
|
||||
pack_start: &add_btn,
|
||||
pack_end: &save_btn,
|
||||
},
|
||||
set_content: Some(&model.tracker_role_groups.widget().clone().upcast::<gtk::Widget>()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||
self.reset();
|
||||
|
||||
match message {
|
||||
Self::Input::Present => {
|
||||
self.win.as_ref().unwrap().present();
|
||||
}
|
||||
Self::Input::Save => {
|
||||
dump_monado_config_v0(&self.monado_config_v0);
|
||||
self.win.as_ref().unwrap().close();
|
||||
}
|
||||
Self::Input::TrackerRoleChanged(index, n_role) => {
|
||||
let role = self.monado_config_v0.tracker_roles.get_mut(index).unwrap();
|
||||
role.device_serial = n_role.device_serial;
|
||||
role.role = n_role.role;
|
||||
role.xrt_input_name = n_role.xrt_input_name;
|
||||
}
|
||||
Self::Input::TrackerRoleDeleted(index) => {
|
||||
self.monado_config_v0.tracker_roles.remove(index);
|
||||
sender.input(Self::Input::Repopulate);
|
||||
}
|
||||
Self::Input::TrackerRoleNew => {
|
||||
self.monado_config_v0
|
||||
.tracker_roles
|
||||
.push(TrackerRole::default());
|
||||
self.tracker_role_groups
|
||||
.guard()
|
||||
.push_back(TrackerRoleModelInit {
|
||||
index: self.monado_config_v0.tracker_roles.len() - 1,
|
||||
tracker_role: None,
|
||||
});
|
||||
}
|
||||
Self::Input::Repopulate => {
|
||||
self.populate_tracker_roles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
init: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let page = adw::PreferencesPage::builder().build();
|
||||
let add_btn = gtk::Button::builder()
|
||||
.tooltip_text("Add Tracker")
|
||||
.icon_name("list-add-symbolic")
|
||||
.build();
|
||||
let save_btn = gtk::Button::builder()
|
||||
.label("Save")
|
||||
.css_classes(["suggested-action"])
|
||||
.build();
|
||||
add_btn.connect_clicked(clone!(@strong sender => move |_| {
|
||||
sender.input(Self::Input::TrackerRoleNew);
|
||||
}));
|
||||
save_btn.connect_clicked(clone!(@strong sender => move |_| {
|
||||
sender.input(Self::Input::Save);
|
||||
}));
|
||||
|
||||
let mut model = Self {
|
||||
win: None,
|
||||
tracker: 0,
|
||||
monado_config_v0: get_monado_config_v0(),
|
||||
tracker_role_groups: AsyncFactoryVecDeque::builder().launch(page).forward(
|
||||
sender.input_sender(),
|
||||
|msg| match msg {
|
||||
TrackerRoleModelOutMsg::Changed(index, tracker_role) => {
|
||||
Self::Input::TrackerRoleChanged(index, tracker_role.clone())
|
||||
}
|
||||
TrackerRoleModelOutMsg::Delete(index) => Self::Input::TrackerRoleDeleted(index),
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
model.populate_tracker_roles();
|
||||
|
||||
let widgets = view_output!();
|
||||
model.win = Some(widgets.win.clone());
|
||||
|
||||
widgets.headerbar.pack_start(&add_btn);
|
||||
widgets.headerbar.pack_end(&save_btn);
|
||||
{
|
||||
let win = widgets.win.clone();
|
||||
let sc = gtk::ShortcutController::new();
|
||||
sc.add_shortcut(gtk::Shortcut::new(
|
||||
gtk::ShortcutTrigger::parse_string("Escape"),
|
||||
Some(gtk::CallbackAction::new(move |_, _| {
|
||||
win.close();
|
||||
gtk::glib::Propagation::Proceed
|
||||
})),
|
||||
));
|
||||
widgets.win.add_controller(sc);
|
||||
}
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
}
|
||||
|
||||
impl FbtConfigEditor {
|
||||
fn populate_tracker_roles(&mut self) {
|
||||
let mut guard = self.tracker_role_groups.guard();
|
||||
guard.clear();
|
||||
for (i, v) in self.monado_config_v0.tracker_roles.iter().enumerate() {
|
||||
guard.push_back(TrackerRoleModelInit {
|
||||
index: i,
|
||||
tracker_role: Some(v.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,7 @@ use crate::gpu_profile::{get_amd_gpu_power_profile, GpuPowerProfile};
|
|||
use crate::profile::{LighthouseDriver, Profile, XRServiceType};
|
||||
use crate::steamvr_utils::chaperone_info_exists;
|
||||
use crate::ui::app::{
|
||||
AboutAction, BuildProfileAction, BuildProfileCleanAction, ConfigFbtAction,
|
||||
DebugViewToggleAction,
|
||||
AboutAction, BuildProfileAction, BuildProfileCleanAction, DebugViewToggleAction,
|
||||
};
|
||||
use crate::ui::profile_editor::ProfileEditorInit;
|
||||
use crate::ui::steamvr_calibration_box::SteamVrCalibrationBoxMsg;
|
||||
|
@ -114,7 +113,6 @@ impl SimpleComponent for MainView {
|
|||
"_Debug View" => DebugViewToggleAction,
|
||||
"_Build Profile" => BuildProfileAction,
|
||||
"C_lean Build Profile" => BuildProfileCleanAction,
|
||||
"Configure Full Body _Tracking" => ConfigFbtAction,
|
||||
},
|
||||
section! {
|
||||
"_About" => AboutAction,
|
||||
|
|
|
@ -7,7 +7,6 @@ pub mod cmdline_opts;
|
|||
mod debug_view;
|
||||
mod devices_box;
|
||||
mod factories;
|
||||
mod fbt_config_editor;
|
||||
mod install_wivrn_box;
|
||||
pub mod job_worker;
|
||||
mod libsurvive_setup_window;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use libmonado_rs;
|
||||
use std::{fmt::Display, slice::Iter};
|
||||
|
||||
const GENERIC_TRACKER_PREFIX: &str = "Found generic tracker device: ";
|
||||
|
@ -105,7 +106,6 @@ impl XRDeviceRole {
|
|||
Self::Chest,
|
||||
Self::Camera,
|
||||
Self::Keyboard,
|
||||
Self::GenericTracker,
|
||||
]
|
||||
.iter()
|
||||
}
|
||||
|
@ -228,7 +228,8 @@ impl XRDeviceRole {
|
|||
pub struct XRDevice {
|
||||
pub dev_type: XRDeviceRole,
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
pub index: String,
|
||||
pub serial: Option<String>,
|
||||
pub battery: Option<f32>, // battery percentage, from 0 to 1 maybe
|
||||
// still need to implement it in monado
|
||||
}
|
||||
|
@ -238,19 +239,21 @@ impl Default for XRDevice {
|
|||
Self {
|
||||
dev_type: XRDeviceRole::GenericTracker,
|
||||
name: String::default(),
|
||||
id: String::default(),
|
||||
index: String::default(),
|
||||
serial: None,
|
||||
battery: Option::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XRDevice {
|
||||
#[deprecated]
|
||||
pub fn generic_tracker_from_log_row(s: &str) -> Option<Self> {
|
||||
if s.starts_with(GENERIC_TRACKER_PREFIX) {
|
||||
let n_tracker = s.trim_start_matches(GENERIC_TRACKER_PREFIX);
|
||||
return Some(Self {
|
||||
dev_type: XRDeviceRole::GenericTracker,
|
||||
id: n_tracker.into(),
|
||||
index: n_tracker.into(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
@ -274,6 +277,7 @@ impl XRDevice {
|
|||
|
||||
pub fn from_libmonado(monado: &libmonado_rs::Monado) -> Vec<Self> {
|
||||
let mut res = vec![];
|
||||
let mut devs_with_role = vec![];
|
||||
[
|
||||
XRDeviceRole::Head,
|
||||
XRDeviceRole::Left,
|
||||
|
@ -299,17 +303,48 @@ impl XRDevice {
|
|||
.iter()
|
||||
.for_each(|xrd| {
|
||||
if let Ok(dev) = monado.device_from_role(xrd.to_monado_str()) {
|
||||
devs_with_role.push(dev.id);
|
||||
// let serial = match dev.serial() {
|
||||
// Ok(s) => {
|
||||
// serials.push(s.clone());
|
||||
// Some(s)
|
||||
// }
|
||||
// Err(e) => {
|
||||
// eprintln!(
|
||||
// "Warning: could not get serial for monado device {} ({}): {:#?}",
|
||||
// dev.name, dev.id, e
|
||||
// );
|
||||
// None
|
||||
// }
|
||||
// };
|
||||
res.push(Self {
|
||||
name: dev.name,
|
||||
id: dev.id.to_string(),
|
||||
index: dev.id.to_string(),
|
||||
// serial,
|
||||
serial: None,
|
||||
dev_type: xrd.clone(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
});
|
||||
if let Ok(all_devs) = monado.devices() {
|
||||
all_devs
|
||||
.into_iter()
|
||||
.filter(|dev| !devs_with_role.contains(&dev.id))
|
||||
.for_each(|dev_gt| {
|
||||
res.push(Self {
|
||||
name: dev_gt.name.clone(),
|
||||
index: dev_gt.id.to_string(),
|
||||
serial: dev_gt.serial().ok(),
|
||||
dev_type: XRDeviceRole::GenericTracker,
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn from_log_message(s: &str) -> Vec<Self> {
|
||||
let mut res = vec![];
|
||||
let rows = s.split('\n');
|
||||
|
@ -359,19 +394,21 @@ impl XRDevice {
|
|||
.filter(|d| !new_dev_types.contains(&d.dev_type))
|
||||
.map(Self::clone)
|
||||
.collect::<Vec<Self>>();
|
||||
let old_tracker_ids = old
|
||||
let old_tracker_serials = old
|
||||
.iter()
|
||||
.filter_map(|d| {
|
||||
if d.dev_type == XRDeviceRole::GenericTracker {
|
||||
return Some(d.id.clone());
|
||||
return d.serial.clone();
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
for n_dev in new {
|
||||
if n_dev.dev_type == XRDeviceRole::GenericTracker {
|
||||
if !old_tracker_ids.contains(&n_dev.id) {
|
||||
res.push(n_dev.clone());
|
||||
if let Some(n_serial) = n_dev.serial.as_ref() {
|
||||
if !old_tracker_serials.contains(n_serial) {
|
||||
res.push(n_dev.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res.push(n_dev.clone());
|
||||
|
|
Loading…
Add table
Reference in a new issue