From eb7fdb2b08a48e8adcf7953b00e83107453520d6 Mon Sep 17 00:00:00 2001 From: Gabriele Musco Date: Wed, 6 Dec 2023 21:30:04 +0000 Subject: [PATCH] feat(stardust): start/stop & server settings --- src/ui/main_view.rs | 7 +- src/ui/stardust/stardust_view.rs | 219 +++++++++++++++++++++++++++++-- 2 files changed, 213 insertions(+), 13 deletions(-) diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 91b7fdf..90b1cf6 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -17,6 +17,7 @@ use crate::ui::app::{ BuildProfileDebugAction, ConfigFbtAction, DebugViewToggleAction, }; use crate::ui::profile_editor::ProfileEditorInit; +use crate::ui::stardust::stardust_view::StardustViewInit; use crate::ui::util::{limit_dropdown_width, warning_heading}; use crate::xr_devices::XRDevice; use gtk::prelude::*; @@ -49,7 +50,7 @@ pub struct MainView { #[tracker::do_not_track] root_win: gtk::Window, #[tracker::do_not_track] - stardust_view: Controller + stardust_view: Controller, } #[derive(Debug)] @@ -382,7 +383,7 @@ impl SimpleComponent for MainView { set_title: Some("XR"), set_icon_name: Some("org.gabmus.envision-symbolic"), }, - add_titled_with_icon: (model.stardust_view.widget(), Some("stardust_view"), "Stardust", "starred-symbolic"), + add_titled_with_icon: (model.stardust_view.widget(), Some("stardust_view"), "Stardust XR", "starred-symbolic"), }, add_bottom_bar: bottom_bar = >k::Box { set_orientation: gtk::Orientation::Horizontal, @@ -661,7 +662,7 @@ impl SimpleComponent for MainView { profile_delete_confirm_dialog, root_win: init.root_win.clone(), profile_editor: None, - stardust_view: StardustView::builder().launch(()).detach(), + stardust_view: StardustView::builder().launch(StardustViewInit {}).detach(), tracker: 0, }; let widgets = view_output!(); diff --git a/src/ui/stardust/stardust_view.rs b/src/ui/stardust/stardust_view.rs index cf27b80..0a6e151 100644 --- a/src/ui/stardust/stardust_view.rs +++ b/src/ui/stardust/stardust_view.rs @@ -1,34 +1,211 @@ -use relm4::prelude::*; +use crate::{stateless_action, withclones}; use gtk::prelude::*; +use adw::prelude::*; +use relm4::{ + actions::{ActionGroupName, RelmAction, RelmActionGroup}, + new_action_group, new_stateless_action, + prelude::*, +}; #[derive(Debug)] -pub enum StardustViewMsg {} +pub enum StardustViewMsg { + BuildStardust, + UpdateStardust, + StartClicked, + StopClicked, + RestartClicked, + + AutostartChanged(bool), + StartAsOvelayChanged(bool), + OverlayPriorityChanged(u32), + DisableControllerChanged(bool), + RepoChanged(String), +} #[derive(Debug)] pub enum StardustViewOutMsg {} +#[derive(Debug)] +pub struct StardustViewInit {} + #[tracker::track] -pub struct StardustView {} +pub struct StardustView { + stardust_service_active: bool, +} #[relm4::component(pub)] impl SimpleComponent for StardustView { - type Init = (); + type Init = StardustViewInit; type Input = StardustViewMsg; type Output = StardustViewOutMsg; + menu! { + stardust_menu: { + section! { + "_Build" => BuildStardustAction, + "_Update" => UpdateStardustAction, + } + } + } + view! { - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - gtk::Label { - set_label: "Stardust", - }, + #[root] + gtk::ScrolledWindow { + set_hscrollbar_policy: gtk::PolicyType::Never, + set_hexpand: true, + set_vexpand: true, + adw::Clamp { + set_maximum_size: 600, + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 12, + set_margin_all: 12, + // service inactive + gtk::Box { + add_css_class: "linked", + set_orientation: gtk::Orientation::Horizontal, + set_hexpand: true, + set_vexpand: false, + #[track = "model.changed(Self::stardust_service_active())"] + set_visible: !model.stardust_service_active, + gtk::Button { + add_css_class: "suggested-action", + set_label: "Start", + set_hexpand: true, + connect_clicked[sender] => move |_| { + sender.input(Self::Input::StartClicked); + }, + }, + gtk::MenuButton { + set_icon_name: "view-more-symbolic", + set_menu_model: Some(&stardust_menu), + }, + }, + // service active + gtk::Box { + add_css_class: "linked", + set_orientation: gtk::Orientation::Horizontal, + set_hexpand: true, + set_vexpand: false, + #[track = "model.changed(Self::stardust_service_active())"] + set_visible: model.stardust_service_active, + gtk::Button { + add_css_class: "destructive-action", + set_label: "Stop", + set_hexpand: true, + connect_clicked[sender] => move |_| { + sender.input(Self::Input::StopClicked); + }, + }, + gtk::Button { + set_icon_name: "view-refresh-symbolic", + set_tooltip_text: Some("Restart"), + connect_clicked[sender] => move |_| { + sender.input(Self::Input::RestartClicked); + }, + }, + }, + gtk::ListBox { + add_css_class: "boxed-list", + set_selection_mode: gtk::SelectionMode::None, + adw::SwitchRow { + set_title: "Autostart with XR Service", + // TODO: settings + // set_active: model.settings.autostart, + connect_active_notify[sender] => move |row| { + sender.input(Self::Input::AutostartChanged(row.is_active())); + } + }, + adw::SwitchRow { + set_title: "Start as an overlay", + // TODO: settings + // set_active: model.settings.overlay, + connect_active_notify[sender] => move |row| { + sender.input(Self::Input::StartAsOvelayChanged(row.is_active())); + } + }, + adw::SpinRow { + set_title: "Overlay priority", + set_digits: 0, + set_snap_to_ticks: true, + // TODO: settings -- here or in adj? + // set_value: model.settings.priority, + #[wrap(Some)] + set_adjustment: overlay_priority_adj = >k::Adjustment { + set_lower: 0.0, + set_upper: f64::from(u32::MAX), + set_value: 0.0, + set_page_increment: 10.0, + set_step_increment: 1.0, + // TODO: settings + // set_value: model.settings.priority, + }, + set_range: (0.0, f64::from(u32::MAX)), + connect_value_notify[sender] => move |row| { + sender.input(Self::Input::OverlayPriorityChanged(row.value() as u32)); + } + }, + // WARN: negative logic, maybe switch it to positive instead? + adw::SwitchRow { + set_title: "Disable controller", + set_subtitle_lines: 0, + set_subtitle: "Necessary if you plan on using hand tracking", + // TODO: settings + // set_active: model.settings.autostart, + connect_active_notify[sender] => move |row| { + sender.input(Self::Input::DisableControllerChanged(row.is_active())); + } + }, + adw::EntryRow { + set_title: "Repository#git ref", + // TODO: settings + // set_text: model.settings.repo, + set_text: "https://github.com/StardustXR/server#main", + connect_changed[sender] => move |row| { + sender.input(Self::Input::RepoChanged(row.text().into())); + } + }, + }, + } + } } } fn update(&mut self, message: Self::Input, sender: ComponentSender) { self.reset(); - match message {} + match message { + Self::Input::BuildStardust => { + println!("Build"); + }, + Self::Input::UpdateStardust => { + println!("Update"); + }, + Self::Input::StartClicked => { + println!("Start"); + }, + Self::Input::StopClicked => { + println!("Stop"); + }, + Self::Input::RestartClicked => { + println!("Restart"); + }, + Self::Input::AutostartChanged(val) => { + println!("Autostart: {}", val); + } + Self::Input::StartAsOvelayChanged(val) => { + println!("StartAsOvelayChanged: {}", val); + } + Self::Input::OverlayPriorityChanged(val) => { + println!("OverlayPriorityChanged: {}", val); + } + Self::Input::DisableControllerChanged(val) => { + println!("DisableControllerChanged: {}", val); + } + Self::Input::RepoChanged(val) => { + println!("RepoChanged: {}", val); + } + }; } fn init( @@ -37,11 +214,33 @@ impl SimpleComponent for StardustView { sender: ComponentSender, ) -> ComponentParts { let model = Self { + stardust_service_active: false, tracker: 0, }; let widgets = view_output!(); + let mut actions = RelmActionGroup::::new(); + + { + withclones![sender]; + stateless_action!(actions, BuildStardustAction, { + sender.input_sender().emit(Self::Input::BuildStardust); + }); + } + { + withclones![sender]; + stateless_action!(actions, UpdateStardustAction, { + sender.input_sender().emit(Self::Input::UpdateStardust); + }); + } + + root.insert_action_group(StardustActionGroup::NAME, Some(&actions.into_action_group())); + ComponentParts { model, widgets } } } + +new_action_group!(StardustActionGroup, "stardust"); +new_stateless_action!(BuildStardustAction, StardustActionGroup, "build"); +new_stateless_action!(UpdateStardustAction, StardustActionGroup, "update");