diff --git a/src/ui/devices_box.rs b/src/ui/devices_box.rs index 3aba4aa..78b2abe 100644 --- a/src/ui/devices_box.rs +++ b/src/ui/devices_box.rs @@ -51,28 +51,21 @@ impl SimpleComponent for DevicesBox { let mut has_right = false; let mut models: Vec = Vec::new(); for dev in &self.devices { - match dev.dev_type { - XRDeviceRole::Head => { - has_head = true; - let mut init = DeviceRowModelInit::from(dev); - if dev.name == "Simulated HMD" || dev.name == "Qwerty HMD" { - init.state = Some(DeviceRowState::Warning); - init.subtitle = Some(format!("No HMD detected ({})", dev.name)); - } - models.push(init); + let mut row_model = DeviceRowModelInit::from(dev); + if !has_head && dev.roles.contains(&XRDeviceRole::Head) { + has_head = true; + if ["Simulated HMD", "Qwerty HMD"].contains(&dev.name.as_str()) { + row_model.state = Some(DeviceRowState::Warning); + row_model.subtitle = Some(format!("No HMD detected ({})", dev.name)); } - XRDeviceRole::Left => { - has_left = true; - models.push(DeviceRowModelInit::from(dev)); - } - XRDeviceRole::Right => { - has_right = true; - models.push(DeviceRowModelInit::from(dev)); - } - _ => { - models.push(DeviceRowModelInit::from(dev)); - } - }; + } + if !has_left && dev.roles.contains(&XRDeviceRole::Left) { + has_left = true; + } + if !has_right && dev.roles.contains(&XRDeviceRole::Right) { + has_right = true; + } + models.push(row_model); } if !has_right { models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Right)); @@ -84,13 +77,7 @@ impl SimpleComponent for DevicesBox { models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Head)); } - models.sort_by(|m1, m2| { - let dt1 = - XRDeviceRole::from_display_str(m1.title.as_deref().unwrap_or_default()); - let dt2 = - XRDeviceRole::from_display_str(m2.title.as_deref().unwrap_or_default()); - dt1.cmp(&dt2) - }); + models.sort_by(|m1, m2| m1.sort_index.cmp(&m2.sort_index)); for model in models { guard.push_back(model); diff --git a/src/ui/factories/device_row_factory.rs b/src/ui/factories/device_row_factory.rs index 5b772f0..73198c0 100644 --- a/src/ui/factories/device_row_factory.rs +++ b/src/ui/factories/device_row_factory.rs @@ -52,14 +52,29 @@ pub struct DeviceRowModelInit { pub state: Option, pub suffix: Option, pub battery_status: Option, + pub sort_index: u32, } impl From<&XRDevice> for DeviceRowModelInit { fn from(d: &XRDevice) -> Self { Self { - title: Some(d.dev_type.to_string()), + title: Some(if d.roles.is_empty() { + XRDeviceRole::GenericTracker.to_string() + } else { + d.roles + .iter() + .map(XRDeviceRole::to_string) + .collect::>() + .join("\n") + }), subtitle: Some(d.name.clone()), battery_status: d.battery.map(EnvisionBatteryStatus::from), + sort_index: d + .roles + .iter() + .min() + .unwrap_or(&XRDeviceRole::GenericTracker) + .as_number(), ..Default::default() } } diff --git a/src/xr_devices.rs b/src/xr_devices.rs index f1bdd7b..05d9904 100644 --- a/src/xr_devices.rs +++ b/src/xr_devices.rs @@ -1,7 +1,5 @@ use libmonado_rs::{self, BatteryStatus, DeviceRole}; -use std::{collections::HashSet, fmt::Display, slice::Iter}; - -const GENERIC_TRACKER_PREFIX: &str = "Found generic tracker device: "; +use std::{collections::HashMap, fmt::Display, slice::Iter}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum XRDeviceRole { @@ -132,7 +130,7 @@ impl XRDeviceRole { Self::Camera => "camera", Self::Keyboard => "keyboard", - Self::GenericTracker => "generic-tracker", // not actually in monado + Self::GenericTracker => "generic-tracker", } } @@ -235,96 +233,64 @@ impl From for XRDeviceRole { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct XRDevice { - pub dev_type: XRDeviceRole, + pub roles: Vec, pub name: String, - pub index: String, + pub id: String, pub serial: Option, pub battery: Option, } -impl Default for XRDevice { - fn default() -> Self { - Self { - dev_type: XRDeviceRole::GenericTracker, - name: String::default(), - index: String::default(), - serial: None, - battery: Option::default(), - } - } -} - impl XRDevice { - #[deprecated] - pub fn generic_tracker_from_log_row(s: &str) -> Option { - if s.starts_with(GENERIC_TRACKER_PREFIX) { - let n_tracker = s.trim_start_matches(GENERIC_TRACKER_PREFIX); - return Some(Self { - dev_type: XRDeviceRole::GenericTracker, - index: n_tracker.into(), - ..Default::default() - }); - } - None - } - pub fn from_libmonado(monado: &libmonado_rs::Monado) -> Vec { - let mut devs_with_role = HashSet::new(); - // only roles in src/xrt/targets/libmonado/monado.c:role_enum - let mut res = [ - DeviceRole::Head, - DeviceRole::Eyes, - DeviceRole::Left, - DeviceRole::Right, - DeviceRole::Gamepad, - DeviceRole::HandTrackingLeft, - DeviceRole::HandTrackingRight, - ] - .into_iter() - .filter_map(|role| { - if let Ok(dev) = monado.device_from_role(role) { - devs_with_role.insert(dev.id); - Some(Self { - index: dev.id.to_string(), - serial: dev.serial().ok(), - battery: dev.battery_status().ok().and_then(|bs| { - if bs.present { - Some(bs) - } else { - None - } - }), - name: dev.name, - dev_type: XRDeviceRole::from(role), + if let Ok(monado_devs) = monado.devices() { + let mut devs: HashMap = monado_devs + .into_iter() + .map(|dev| { + ( + dev.index, + Self { + id: dev.id.to_string(), + serial: dev.serial().ok(), + battery: dev.battery_status().ok().and_then(|bs| { + if bs.present { + Some(bs) + } else { + None + } + }), + name: dev.name, + roles: Vec::default(), + }, + ) }) - } else { - None - } - }) - .collect::>(); - if let Ok(all_devs) = monado.devices() { - res.extend(all_devs.into_iter().filter_map(|dev| { - if devs_with_role.contains(&dev.id) { - None - } else { - Some(Self { - index: dev.id.to_string(), - serial: dev.serial().ok(), - battery: dev.battery_status().ok().and_then(|bs| { - if bs.present { - Some(bs) - } else { - None - } - }), - name: dev.name, - dev_type: XRDeviceRole::GenericTracker, - }) + .collect(); + [ + DeviceRole::Head, + DeviceRole::Eyes, + DeviceRole::Left, + DeviceRole::Right, + DeviceRole::Gamepad, + DeviceRole::HandTrackingLeft, + DeviceRole::HandTrackingRight, + ] + .into_iter() + .for_each(|role| { + if let Ok(index) = monado.device_index_from_role(role) { + if let Some(target) = devs.get_mut(&index) { + target.roles.push(role.into()); + } else { + eprintln!( + "Could not find device index {index} for role {}", + XRDeviceRole::from(role) + ) + } } - })); + }); + devs.drain().map(|(_, d)| d).collect() + } else { + Vec::default() } - res } }