mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-19 19:14:53 +00:00
feat: extract devices from monado logs and represent them in ui
This commit is contained in:
parent
94932b0214
commit
b5ad5e0e80
5 changed files with 304 additions and 4 deletions
|
@ -90,9 +90,9 @@ impl Runner {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn xrservice_runner_from_profile(profile: Profile) -> Self {
|
||||
pub fn xrservice_runner_from_profile(profile: &Profile) -> Self {
|
||||
Self::new(
|
||||
Some(profile.environment),
|
||||
Some(profile.environment.clone()),
|
||||
match profile.xrservice_type {
|
||||
XRServiceType::Monado => format!("{pfx}/bin/monado-service", pfx = profile.prefix),
|
||||
XRServiceType::Wivrn => format!("{pfx}/bin/wivrn-server", pfx = profile.prefix),
|
||||
|
@ -253,7 +253,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn can_create_from_profile() {
|
||||
Runner::xrservice_runner_from_profile(Profile::load_profile(
|
||||
Runner::xrservice_runner_from_profile(&Profile::load_profile(
|
||||
&"./test/files/profile.json".to_string(),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::dependencies::monado_deps::get_missing_monado_deps;
|
|||
use crate::dependencies::pkexec_dep::pkexec_dep;
|
||||
use crate::dependencies::wivrn_deps::get_missing_wivrn_deps;
|
||||
use crate::file_utils::setcap_cap_sys_nice_eip;
|
||||
use crate::log_parser::MonadoLog;
|
||||
use crate::profile::{Profile, XRServiceType};
|
||||
use crate::profiles::system_valve_index::system_valve_index_profile;
|
||||
use crate::profiles::valve_index::valve_index_profile;
|
||||
|
@ -29,6 +30,7 @@ use crate::ui::build_window::BuildWindowMsg;
|
|||
use crate::ui::debug_view::DebugViewInit;
|
||||
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
|
||||
use crate::ui::main_view::{MainView, MainViewInit, MainViewOutMsg};
|
||||
use crate::xr_devices::XRDevices;
|
||||
use expect_dialog::ExpectDialog;
|
||||
use gtk::prelude::*;
|
||||
use relm4::actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup};
|
||||
|
@ -71,6 +73,8 @@ pub struct App {
|
|||
build_pipeline: Option<RunnerPipeline>,
|
||||
#[tracker::do_not_track]
|
||||
profiles: Vec<Profile>,
|
||||
#[tracker::do_not_track]
|
||||
devices_processed: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -85,6 +89,7 @@ pub enum Msg {
|
|||
RunSetCap,
|
||||
OpenLibsurviveSetup,
|
||||
Quit,
|
||||
ProcessDevicesLog(Vec<String>),
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -102,10 +107,15 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn start_xrservice(&mut self) {
|
||||
let prof = self.get_selected_profile();
|
||||
self.devices_processed = match prof.xrservice_type {
|
||||
XRServiceType::Monado => false,
|
||||
XRServiceType::Wivrn => true, // no device from log in wivrn
|
||||
};
|
||||
self.debug_view
|
||||
.sender()
|
||||
.emit(DebugViewMsg::ClearLog);
|
||||
let mut runner = Runner::xrservice_runner_from_profile(self.get_selected_profile().clone());
|
||||
let mut runner = Runner::xrservice_runner_from_profile(&prof);
|
||||
match runner.try_start() {
|
||||
Ok(_) => {
|
||||
self.xrservice_runner = Some(runner);
|
||||
|
@ -189,6 +199,9 @@ impl SimpleComponent for App {
|
|||
Some(runner) => {
|
||||
let n_rows = runner.consume_rows();
|
||||
if !n_rows.is_empty() {
|
||||
if !self.devices_processed {
|
||||
sender.input(Msg::ProcessDevicesLog(n_rows.clone()))
|
||||
}
|
||||
self.debug_view
|
||||
.sender()
|
||||
.emit(DebugViewMsg::LogUpdated(n_rows));
|
||||
|
@ -245,6 +258,25 @@ impl SimpleComponent for App {
|
|||
};
|
||||
self.main_view.sender().emit(MainViewMsg::ClockTicking);
|
||||
}
|
||||
Msg::ProcessDevicesLog(rows) => {
|
||||
for row in rows {
|
||||
match MonadoLog::from_str(row.as_str()) {
|
||||
None => {}
|
||||
Some(parsed) => {
|
||||
if parsed.func == "p_create_system" {
|
||||
match XRDevices::from_log_message(parsed.message) {
|
||||
None => {},
|
||||
Some(devices) => {
|
||||
self.devices_processed = true;
|
||||
self.main_view.sender().emit(MainViewMsg::UpdateDevices(Some(devices)));
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Msg::EnableDebugViewChanged(val) => {
|
||||
self.set_enable_debug_view(val);
|
||||
self.config.debug_view_enabled = val;
|
||||
|
@ -501,6 +533,7 @@ impl SimpleComponent for App {
|
|||
profiles,
|
||||
xrservice_runner: None,
|
||||
build_pipeline: None,
|
||||
devices_processed: false,
|
||||
};
|
||||
let widgets = view_output!();
|
||||
|
||||
|
|
253
src/ui/devices_box.rs
Normal file
253
src/ui/devices_box.rs
Normal file
|
@ -0,0 +1,253 @@
|
|||
use crate::xr_devices::{XRDevice, XRDevices};
|
||||
use gtk::prelude::*;
|
||||
use relm4::prelude::*;
|
||||
|
||||
#[tracker::track]
|
||||
pub struct DevicesBox {
|
||||
devices: Option<XRDevices>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DevicesBoxMsg {
|
||||
UpdateDevices(Option<XRDevices>),
|
||||
}
|
||||
|
||||
impl DevicesBox {
|
||||
fn get_dev(&self, key: XRDevice) -> Option<String> {
|
||||
match &self.devices {
|
||||
None => None,
|
||||
Some(devs) => match key {
|
||||
XRDevice::Head => devs.head.clone(),
|
||||
XRDevice::Left => devs.left.clone(),
|
||||
XRDevice::Right => devs.right.clone(),
|
||||
XRDevice::Gamepad => devs.gamepad.clone(),
|
||||
XRDevice::Eyes => devs.eyes.clone(),
|
||||
XRDevice::HandTrackingLeft => devs.hand_tracking_left.clone(),
|
||||
XRDevice::HandTrackingRight => devs.hand_tracking_right.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for DevicesBox {
|
||||
type Init = ();
|
||||
type Input = DevicesBoxMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_hexpand: true,
|
||||
set_vexpand: false,
|
||||
set_spacing: 12,
|
||||
set_margin_top: 12,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_visible: model.devices.is_some(),
|
||||
gtk::Separator {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
},
|
||||
// Head
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
gtk::Image {
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_icon_name: Some(match model.get_dev(XRDevice::Head) {
|
||||
Some(_) => "emblem-ok-symbolic",
|
||||
None => "dialog-question-symbolic",
|
||||
}),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Head).is_none()),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Head: {}", match model.get_dev(XRDevice::Head) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Head).is_none()),
|
||||
// TODO: status icon with popover
|
||||
},
|
||||
},
|
||||
// Left
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
gtk::Image {
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_icon_name: Some(match model.get_dev(XRDevice::Left) {
|
||||
Some(_) => "emblem-ok-symbolic",
|
||||
None => "dialog-question-symbolic",
|
||||
}),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Left).is_none()),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Left: {}", match model.get_dev(XRDevice::Left) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Left).is_none()),
|
||||
// TODO: status icon with popover
|
||||
},
|
||||
},
|
||||
// Right
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
gtk::Image {
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_icon_name: Some(match model.get_dev(XRDevice::Right) {
|
||||
Some(_) => "emblem-ok-symbolic",
|
||||
None => "dialog-question-symbolic",
|
||||
}),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Right).is_none()),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Right: {}", match model.get_dev(XRDevice::Right) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_class_active: ("error", model.get_dev(XRDevice::Right).is_none()),
|
||||
// TODO: status icon with popover
|
||||
},
|
||||
},
|
||||
// Gamepad
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_visible: model.get_dev(XRDevice::Gamepad).is_some(),
|
||||
gtk::Image {
|
||||
set_icon_name: Some("emblem-ok-symbolic"),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Gamepad: {}", match model.get_dev(XRDevice::Gamepad) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
},
|
||||
},
|
||||
// Eyes
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_visible: model.get_dev(XRDevice::Eyes).is_some(),
|
||||
gtk::Image {
|
||||
set_icon_name: Some("emblem-ok-symbolic"),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Eye Tracking: {}", match model.get_dev(XRDevice::Eyes) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
},
|
||||
},
|
||||
// Hand Tracking Left
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_visible: model.get_dev(XRDevice::HandTrackingLeft).is_some(),
|
||||
gtk::Image {
|
||||
set_icon_name: Some("emblem-ok-symbolic"),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Hand Tracking Left: {}", match model.get_dev(XRDevice::HandTrackingLeft) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
},
|
||||
},
|
||||
// Hand Tracking Right
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_visible: model.get_dev(XRDevice::HandTrackingRight).is_some(),
|
||||
gtk::Image {
|
||||
set_icon_name: Some("emblem-ok-symbolic"),
|
||||
},
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
set_hexpand: true,
|
||||
#[track = "model.changed(Self::devices())"]
|
||||
set_label: format!("Hand Tracking Left: {}", match model.get_dev(XRDevice::HandTrackingRight) {
|
||||
Some(v) => v.clone(),
|
||||
None => "None".to_string(),
|
||||
}).as_str(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||
self.reset();
|
||||
|
||||
match message {
|
||||
Self::Input::UpdateDevices(devs) => {
|
||||
self.set_devices(devs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
init: Self::Init,
|
||||
root: &Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let model = Self {
|
||||
tracker: 0,
|
||||
devices: None,
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
use super::devices_box::{DevicesBox, DevicesBoxMsg};
|
||||
use super::install_wivrn_box::{InstallWivrnBox, InstallWivrnBoxInit, InstallWivrnBoxMsg};
|
||||
use super::profile_editor::{ProfileEditor, ProfileEditorMsg, ProfileEditorOutMsg};
|
||||
use super::runtime_switcher_box::{
|
||||
|
@ -11,6 +12,7 @@ use crate::ui::app::{
|
|||
AboutAction, BuildProfileAction, DebugViewToggleAction, LibsurviveSetupAction,
|
||||
};
|
||||
use crate::ui::profile_editor::ProfileEditorInit;
|
||||
use crate::xr_devices::XRDevices;
|
||||
use gtk::prelude::*;
|
||||
use relm4::adw::traits::MessageDialogExt;
|
||||
use relm4::adw::ResponseAppearance;
|
||||
|
@ -32,6 +34,8 @@ pub struct MainView {
|
|||
#[tracker::do_not_track]
|
||||
runtime_switcher_box: Controller<RuntimeSwitcherBox>,
|
||||
#[tracker::do_not_track]
|
||||
devices_box: Controller<DevicesBox>,
|
||||
#[tracker::do_not_track]
|
||||
profile_editor: Controller<ProfileEditor>,
|
||||
#[tracker::do_not_track]
|
||||
profile_not_editable_dialog: adw::MessageDialog,
|
||||
|
@ -54,6 +58,7 @@ pub enum MainViewMsg {
|
|||
DeleteProfile,
|
||||
DuplicateProfile,
|
||||
SaveProfile(Profile),
|
||||
UpdateDevices(Option<XRDevices>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -141,6 +146,7 @@ impl SimpleComponent for MainView {
|
|||
sender.input(MainViewMsg::StartStopClicked)
|
||||
},
|
||||
},
|
||||
model.devices_box.widget(),
|
||||
model.runtime_switcher_box.widget(),
|
||||
model.steam_launch_options_box.widget(),
|
||||
model.install_wivrn_box.widget(),
|
||||
|
@ -221,6 +227,9 @@ impl SimpleComponent for MainView {
|
|||
}
|
||||
Self::Input::XRServiceActiveChanged(active, profile) => {
|
||||
self.set_xrservice_active(active);
|
||||
if !active {
|
||||
sender.input(Self::Input::UpdateDevices(None));
|
||||
}
|
||||
self.steam_launch_options_box
|
||||
.sender()
|
||||
.emit(SteamLaunchOptionsBoxMsg::UpdateXRServiceActive(active));
|
||||
|
@ -299,6 +308,9 @@ impl SimpleComponent for MainView {
|
|||
self.selected_profile.create_duplicate(),
|
||||
));
|
||||
}
|
||||
Self::Input::UpdateDevices(devs) => {
|
||||
self.devices_box.sender().emit(DevicesBoxMsg::UpdateDevices(devs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,6 +388,7 @@ impl SimpleComponent for MainView {
|
|||
.forward(sender.input_sender(), |message| match message {
|
||||
ProfileEditorOutMsg::SaveProfile(p) => Self::Input::SaveProfile(p),
|
||||
}),
|
||||
devices_box: DevicesBox::builder().launch(()).detach(),
|
||||
selected_profile: init.selected_profile.clone(),
|
||||
profile_not_editable_dialog,
|
||||
profile_delete_confirm_dialog,
|
||||
|
|
|
@ -10,3 +10,4 @@ pub mod runtime_switcher_box;
|
|||
pub mod profile_editor;
|
||||
pub mod factories;
|
||||
pub mod wivrn_conf_editor;
|
||||
pub mod devices_box;
|
||||
|
|
Loading…
Add table
Reference in a new issue