mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-02 22:29:01 +00:00
feat: initial ui prototype; valve index default profile; app config file
This commit is contained in:
parent
f44a25d679
commit
e6a839ae19
8 changed files with 2977 additions and 2 deletions
2715
Cargo.lock
generated
2715
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,10 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
iced = "0.9.0"
|
||||||
|
iced_aw = { version = "0.5.2", default-features = false, features = [
|
||||||
|
"tab_bar", "tabs"
|
||||||
|
] }
|
||||||
serde = { version = "1.0.163", features = [
|
serde = { version = "1.0.163", features = [
|
||||||
"derive"
|
"derive"
|
||||||
] }
|
] }
|
||||||
|
|
67
src/config.rs
Normal file
67
src/config.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::{
|
||||||
|
constants::CMD_NAME,
|
||||||
|
file_utils::{get_config_dir, get_writer},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub selected_profile_name: String,
|
||||||
|
pub debug_view_enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_file_path() -> String {
|
||||||
|
format!(
|
||||||
|
"{config}/{name}.json",
|
||||||
|
config = get_config_dir(),
|
||||||
|
name = CMD_NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_config() -> Config {
|
||||||
|
Config {
|
||||||
|
// TODO: handle first start with no profile selected
|
||||||
|
selected_profile_name: "Demo profile".to_string(),
|
||||||
|
debug_view_enabled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config_from_path(path_s: String) -> Config {
|
||||||
|
match File::open(path_s) {
|
||||||
|
Ok(file) => {
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
match serde_json::from_reader(reader) {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(_) => default_config(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => default_config(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config() -> Config {
|
||||||
|
get_config_from_path(config_file_path())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_config_to_path(config: &Config, path_s: &String) -> Result<(), serde_json::Error> {
|
||||||
|
let writer = get_writer(path_s);
|
||||||
|
serde_json::to_writer_pretty(writer, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config(config: &Config) -> Result<(), serde_json::Error> {
|
||||||
|
save_config_to_path(config, &config_file_path())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::get_config_from_path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn will_load_default_if_config_does_not_exist() {
|
||||||
|
assert_eq!(
|
||||||
|
get_config_from_path("/non/existing/file.json".into()).debug_view_enabled,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
10
src/main.rs
10
src/main.rs
|
@ -1,6 +1,14 @@
|
||||||
|
use iced::{Application, Settings};
|
||||||
|
use ui::main_win::MainWin;
|
||||||
|
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
pub mod runner;
|
pub mod runner;
|
||||||
|
pub mod ui;
|
||||||
|
pub mod config;
|
||||||
|
pub mod constants;
|
||||||
|
pub mod file_utils;
|
||||||
|
pub mod profiles;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
MainWin::run(Settings::default());
|
||||||
}
|
}
|
||||||
|
|
3
src/profiles/mod.rs
Normal file
3
src/profiles/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
pub mod valve_index;
|
||||||
|
|
23
src/profiles/valve_index.rs
Normal file
23
src/profiles/valve_index.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::{constants::APP_NAME, file_utils::get_data_dir, profile::Profile};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn valve_index_profile() -> Profile {
|
||||||
|
let data_dir = get_data_dir();
|
||||||
|
let mut environment: HashMap<String, String> = HashMap::new();
|
||||||
|
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());
|
||||||
|
environment.insert("XRT_COMPOSITOR_COMPUTE".into(), "1".into());
|
||||||
|
environment.insert("SURVIVE_GLOBALSCENESOLVER".into(), "0".into());
|
||||||
|
environment.insert("SURVIVE_TIMECODE_OFFSET_MS".into(), "-6.94".into());
|
||||||
|
Profile {
|
||||||
|
name: format!("Valve Index - {name} Default", name = APP_NAME),
|
||||||
|
monado_path: format!("{data}/monado", data = data_dir),
|
||||||
|
openovr_path: format!("{data}/openovr", data = data_dir),
|
||||||
|
libsurvive_path: Some(format!("{data}/libsurvive", data = data_dir)),
|
||||||
|
basalt_path: None,
|
||||||
|
mercury_path: None,
|
||||||
|
libsurvive_enabled: true,
|
||||||
|
basalt_enabled: false,
|
||||||
|
mercury_enabled: false,
|
||||||
|
environment,
|
||||||
|
}
|
||||||
|
}
|
154
src/ui/main_win.rs
Normal file
154
src/ui/main_win.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use crate::{
|
||||||
|
config::{get_config, save_config, Config},
|
||||||
|
constants::APP_NAME,
|
||||||
|
profile::{load_profile, Profile},
|
||||||
|
};
|
||||||
|
use iced::{
|
||||||
|
executor,
|
||||||
|
widget::{button, checkbox, column, pick_list, row, scrollable, text, text_input},
|
||||||
|
Alignment, Application, Command, Element, Length, Padding, Theme,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct MainWin {
|
||||||
|
profiles: Vec<Profile>,
|
||||||
|
monado_active: bool,
|
||||||
|
config: Config,
|
||||||
|
debug_search_term: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Message {
|
||||||
|
Start,
|
||||||
|
Stop,
|
||||||
|
Tick,
|
||||||
|
ProfileChanged(Profile),
|
||||||
|
EditProfile,
|
||||||
|
DebugViewChanged(bool),
|
||||||
|
LogLevelChanged(String),
|
||||||
|
DebugSearchChanged(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainWin {
|
||||||
|
fn get_profile_by_name(&self, name: &String) -> Option<&Profile> {
|
||||||
|
for profile in &self.profiles {
|
||||||
|
if &profile.name == name {
|
||||||
|
return Some(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_selected_profile(&self) -> Option<&Profile> {
|
||||||
|
self.get_profile_by_name(&self.config.selected_profile_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Application for MainWin {
|
||||||
|
type Message = Message;
|
||||||
|
type Flags = ();
|
||||||
|
type Executor = executor::Default;
|
||||||
|
type Theme = Theme;
|
||||||
|
|
||||||
|
fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
// TODO: load profiles from disk somehow
|
||||||
|
profiles: vec![load_profile(&"./test/files/profile.json".to_string()).unwrap()],
|
||||||
|
monado_active: false,
|
||||||
|
config: get_config(),
|
||||||
|
debug_search_term: "".into(),
|
||||||
|
},
|
||||||
|
Command::none(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn title(&self) -> String {
|
||||||
|
return APP_NAME.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Message) -> Command<Message> {
|
||||||
|
match msg {
|
||||||
|
Message::Start => self.monado_active = true,
|
||||||
|
Message::Stop => self.monado_active = false,
|
||||||
|
Message::ProfileChanged(profile) => {
|
||||||
|
if self.config.selected_profile_name != profile.name {
|
||||||
|
self.config.selected_profile_name = profile.name;
|
||||||
|
save_config(&self.config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::EditProfile => {
|
||||||
|
println!("Edit {}", self.get_selected_profile().unwrap())
|
||||||
|
}
|
||||||
|
Message::DebugViewChanged(nval) => {
|
||||||
|
self.config.debug_view_enabled = nval;
|
||||||
|
save_config(&self.config);
|
||||||
|
}
|
||||||
|
Message::DebugSearchChanged(term) => self.debug_search_term = term,
|
||||||
|
_ => println!("unhandled"),
|
||||||
|
};
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Element<Message> {
|
||||||
|
row![
|
||||||
|
column![
|
||||||
|
column![match self.monado_active {
|
||||||
|
true => button("Stop").on_press(Message::Stop),
|
||||||
|
false => button("Start").on_press(Message::Start),
|
||||||
|
}
|
||||||
|
.padding(Padding::from([6, 24])),]
|
||||||
|
.height(Length::Fill),
|
||||||
|
row![
|
||||||
|
pick_list(
|
||||||
|
self.profiles.to_vec(),
|
||||||
|
self.get_selected_profile().cloned(),
|
||||||
|
Message::ProfileChanged
|
||||||
|
),
|
||||||
|
button("Edit").on_press(Message::EditProfile),
|
||||||
|
row![].width(Length::Fill),
|
||||||
|
checkbox(
|
||||||
|
"Debug View",
|
||||||
|
self.config.debug_view_enabled,
|
||||||
|
Message::DebugViewChanged
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.width(Length::Fill),
|
||||||
|
]
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.padding(12)
|
||||||
|
.align_items(Alignment::Center),
|
||||||
|
match self.config.debug_view_enabled {
|
||||||
|
true => column![
|
||||||
|
// TODO: tab bar
|
||||||
|
scrollable(text("Foo bar baz"))
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill),
|
||||||
|
row![
|
||||||
|
pick_list(
|
||||||
|
vec![
|
||||||
|
"Debug".to_string(),
|
||||||
|
"Info".into(),
|
||||||
|
"Warning".into(),
|
||||||
|
"Error".into(),
|
||||||
|
],
|
||||||
|
Some("Debug".into()),
|
||||||
|
Message::LogLevelChanged
|
||||||
|
),
|
||||||
|
row![].width(Length::Fill),
|
||||||
|
text_input("Search...", self.debug_search_term.as_str())
|
||||||
|
.on_input(Message::DebugSearchChanged),
|
||||||
|
]
|
||||||
|
.padding(12)
|
||||||
|
]
|
||||||
|
.width(Length::Fill),
|
||||||
|
false => column![],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn theme(&self) -> Self::Theme {
|
||||||
|
Theme::Dark
|
||||||
|
}
|
||||||
|
}
|
3
src/ui/mod.rs
Normal file
3
src/ui/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
pub mod main_win;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue