mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-04 15:18:58 +00:00
feat: xr devices can have multiple roles and they will be displayed as only one row
This commit is contained in:
parent
932aa05fbf
commit
58ceb44984
3 changed files with 81 additions and 113 deletions
|
@ -51,28 +51,21 @@ impl SimpleComponent for DevicesBox {
|
||||||
let mut has_right = false;
|
let mut has_right = false;
|
||||||
let mut models: Vec<DeviceRowModelInit> = Vec::new();
|
let mut models: Vec<DeviceRowModelInit> = Vec::new();
|
||||||
for dev in &self.devices {
|
for dev in &self.devices {
|
||||||
match dev.dev_type {
|
let mut row_model = DeviceRowModelInit::from(dev);
|
||||||
XRDeviceRole::Head => {
|
if !has_head && dev.roles.contains(&XRDeviceRole::Head) {
|
||||||
has_head = true;
|
has_head = true;
|
||||||
let mut init = DeviceRowModelInit::from(dev);
|
if ["Simulated HMD", "Qwerty HMD"].contains(&dev.name.as_str()) {
|
||||||
if dev.name == "Simulated HMD" || dev.name == "Qwerty HMD" {
|
row_model.state = Some(DeviceRowState::Warning);
|
||||||
init.state = Some(DeviceRowState::Warning);
|
row_model.subtitle = Some(format!("No HMD detected ({})", dev.name));
|
||||||
init.subtitle = Some(format!("No HMD detected ({})", dev.name));
|
|
||||||
}
|
|
||||||
models.push(init);
|
|
||||||
}
|
}
|
||||||
XRDeviceRole::Left => {
|
}
|
||||||
has_left = true;
|
if !has_left && dev.roles.contains(&XRDeviceRole::Left) {
|
||||||
models.push(DeviceRowModelInit::from(dev));
|
has_left = true;
|
||||||
}
|
}
|
||||||
XRDeviceRole::Right => {
|
if !has_right && dev.roles.contains(&XRDeviceRole::Right) {
|
||||||
has_right = true;
|
has_right = true;
|
||||||
models.push(DeviceRowModelInit::from(dev));
|
}
|
||||||
}
|
models.push(row_model);
|
||||||
_ => {
|
|
||||||
models.push(DeviceRowModelInit::from(dev));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if !has_right {
|
if !has_right {
|
||||||
models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Right));
|
models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Right));
|
||||||
|
@ -84,13 +77,7 @@ impl SimpleComponent for DevicesBox {
|
||||||
models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Head));
|
models.push(DeviceRowModelInit::new_missing(XRDeviceRole::Head));
|
||||||
}
|
}
|
||||||
|
|
||||||
models.sort_by(|m1, m2| {
|
models.sort_by(|m1, m2| m1.sort_index.cmp(&m2.sort_index));
|
||||||
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)
|
|
||||||
});
|
|
||||||
|
|
||||||
for model in models {
|
for model in models {
|
||||||
guard.push_back(model);
|
guard.push_back(model);
|
||||||
|
|
|
@ -52,14 +52,29 @@ pub struct DeviceRowModelInit {
|
||||||
pub state: Option<DeviceRowState>,
|
pub state: Option<DeviceRowState>,
|
||||||
pub suffix: Option<gtk::Widget>,
|
pub suffix: Option<gtk::Widget>,
|
||||||
pub battery_status: Option<EnvisionBatteryStatus>,
|
pub battery_status: Option<EnvisionBatteryStatus>,
|
||||||
|
pub sort_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&XRDevice> for DeviceRowModelInit {
|
impl From<&XRDevice> for DeviceRowModelInit {
|
||||||
fn from(d: &XRDevice) -> Self {
|
fn from(d: &XRDevice) -> Self {
|
||||||
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::<Vec<String>>()
|
||||||
|
.join("\n")
|
||||||
|
}),
|
||||||
subtitle: Some(d.name.clone()),
|
subtitle: Some(d.name.clone()),
|
||||||
battery_status: d.battery.map(EnvisionBatteryStatus::from),
|
battery_status: d.battery.map(EnvisionBatteryStatus::from),
|
||||||
|
sort_index: d
|
||||||
|
.roles
|
||||||
|
.iter()
|
||||||
|
.min()
|
||||||
|
.unwrap_or(&XRDeviceRole::GenericTracker)
|
||||||
|
.as_number(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use libmonado_rs::{self, BatteryStatus, DeviceRole};
|
use libmonado_rs::{self, BatteryStatus, DeviceRole};
|
||||||
use std::{collections::HashSet, fmt::Display, slice::Iter};
|
use std::{collections::HashMap, fmt::Display, slice::Iter};
|
||||||
|
|
||||||
const GENERIC_TRACKER_PREFIX: &str = "Found generic tracker device: ";
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum XRDeviceRole {
|
pub enum XRDeviceRole {
|
||||||
|
@ -132,7 +130,7 @@ impl XRDeviceRole {
|
||||||
Self::Camera => "camera",
|
Self::Camera => "camera",
|
||||||
Self::Keyboard => "keyboard",
|
Self::Keyboard => "keyboard",
|
||||||
|
|
||||||
Self::GenericTracker => "generic-tracker", // not actually in monado
|
Self::GenericTracker => "generic-tracker",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,96 +233,64 @@ impl From<DeviceRole> for XRDeviceRole {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct XRDevice {
|
pub struct XRDevice {
|
||||||
pub dev_type: XRDeviceRole,
|
pub roles: Vec<XRDeviceRole>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub index: String,
|
pub id: String,
|
||||||
pub serial: Option<String>,
|
pub serial: Option<String>,
|
||||||
pub battery: Option<BatteryStatus>,
|
pub battery: Option<BatteryStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
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,
|
|
||||||
index: n_tracker.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_libmonado(monado: &libmonado_rs::Monado) -> Vec<Self> {
|
pub fn from_libmonado(monado: &libmonado_rs::Monado) -> Vec<Self> {
|
||||||
let mut devs_with_role = HashSet::new();
|
if let Ok(monado_devs) = monado.devices() {
|
||||||
// only roles in src/xrt/targets/libmonado/monado.c:role_enum
|
let mut devs: HashMap<u32, XRDevice> = monado_devs
|
||||||
let mut res = [
|
.into_iter()
|
||||||
DeviceRole::Head,
|
.map(|dev| {
|
||||||
DeviceRole::Eyes,
|
(
|
||||||
DeviceRole::Left,
|
dev.index,
|
||||||
DeviceRole::Right,
|
Self {
|
||||||
DeviceRole::Gamepad,
|
id: dev.id.to_string(),
|
||||||
DeviceRole::HandTrackingLeft,
|
serial: dev.serial().ok(),
|
||||||
DeviceRole::HandTrackingRight,
|
battery: dev.battery_status().ok().and_then(|bs| {
|
||||||
]
|
if bs.present {
|
||||||
.into_iter()
|
Some(bs)
|
||||||
.filter_map(|role| {
|
} else {
|
||||||
if let Ok(dev) = monado.device_from_role(role) {
|
None
|
||||||
devs_with_role.insert(dev.id);
|
}
|
||||||
Some(Self {
|
}),
|
||||||
index: dev.id.to_string(),
|
name: dev.name,
|
||||||
serial: dev.serial().ok(),
|
roles: Vec::default(),
|
||||||
battery: dev.battery_status().ok().and_then(|bs| {
|
},
|
||||||
if bs.present {
|
)
|
||||||
Some(bs)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
name: dev.name,
|
|
||||||
dev_type: XRDeviceRole::from(role),
|
|
||||||
})
|
})
|
||||||
} else {
|
.collect();
|
||||||
None
|
[
|
||||||
}
|
DeviceRole::Head,
|
||||||
})
|
DeviceRole::Eyes,
|
||||||
.collect::<Vec<Self>>();
|
DeviceRole::Left,
|
||||||
if let Ok(all_devs) = monado.devices() {
|
DeviceRole::Right,
|
||||||
res.extend(all_devs.into_iter().filter_map(|dev| {
|
DeviceRole::Gamepad,
|
||||||
if devs_with_role.contains(&dev.id) {
|
DeviceRole::HandTrackingLeft,
|
||||||
None
|
DeviceRole::HandTrackingRight,
|
||||||
} else {
|
]
|
||||||
Some(Self {
|
.into_iter()
|
||||||
index: dev.id.to_string(),
|
.for_each(|role| {
|
||||||
serial: dev.serial().ok(),
|
if let Ok(index) = monado.device_index_from_role(role) {
|
||||||
battery: dev.battery_status().ok().and_then(|bs| {
|
if let Some(target) = devs.get_mut(&index) {
|
||||||
if bs.present {
|
target.roles.push(role.into());
|
||||||
Some(bs)
|
} else {
|
||||||
} else {
|
eprintln!(
|
||||||
None
|
"Could not find device index {index} for role {}",
|
||||||
}
|
XRDeviceRole::from(role)
|
||||||
}),
|
)
|
||||||
name: dev.name,
|
}
|
||||||
dev_type: XRDeviceRole::GenericTracker,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
devs.drain().map(|(_, d)| d).collect()
|
||||||
|
} else {
|
||||||
|
Vec::default()
|
||||||
}
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue