diff --git a/Cargo.lock b/Cargo.lock index 026fdcd..42b35fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -76,6 +85,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "bumpalo" version = "3.15.1" @@ -94,7 +109,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib", "libc", @@ -118,6 +133,9 @@ name = "cc" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +dependencies = [ + "libc", +] [[package]] name = "cfg-expr" @@ -203,6 +221,15 @@ dependencies = [ "spin", ] +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fragile" version = "2.0.0" @@ -304,7 +331,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -331,7 +358,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3abf96408a26e3eddf881a7f893a1e111767137136e347745e8ea6ed12731ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk4-sys", @@ -383,7 +410,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6973e92937cf98689b6a054a9e56c657ed4ff76de925e36fc331a15f0c5d30a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -410,13 +437,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "git2" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +dependencies = [ + "bitflags 2.4.2", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "glib" version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fad45ba8d4d2cea612b432717e834f48031cd8853c8aaf43b2c79fec8d144b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -504,7 +546,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f01ef44fa7cac15e2da9978529383e6bee03e570ba5bf7036b4c10a15cc3a3c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk4", "glib", @@ -536,7 +578,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b28a32a04cd75cef14a0983f8b0c669e0fe152a0a7725accdeb594e2c764c88b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -645,6 +687,32 @@ dependencies = [ "cc", ] +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + [[package]] name = "indexmap" version = "2.2.3" @@ -682,7 +750,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab9c0843f9f23ff25634df2743690c3a1faffe0a190e60c490878517eb81abf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf", "gdk4", "gio", @@ -715,6 +783,46 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libgit2-sys" +version = "0.16.2+1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -807,13 +915,31 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "pango" version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio", "glib", "libc", @@ -833,6 +959,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project" version = "1.1.4" @@ -933,6 +1065,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "relm4" version = "0.6.2" @@ -977,12 +1138,16 @@ name = "rsproject" version = "0.1.0" dependencies = [ "chrono", + "git2", "glib-build-tools", "gtk4", + "lazy_static", "libadwaita", + "regex", "relm4", "relm4-icons", "tracker", + "validator", ] [[package]] @@ -1164,6 +1329,21 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.36.0" @@ -1271,12 +1451,86 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + +[[package]] +name = "validator" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" +dependencies = [ + "idna 0.4.0", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" +dependencies = [ + "if_chain", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "validator_types", +] + +[[package]] +name = "validator_types" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 486c0bf..cc23d53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,10 @@ relm4 = { version = "0.6.2", features = ["libadwaita"]} relm4-icons = { version = "0.6.0", features = ["add-filled"] } chrono = "0.4.34" tracker = "0.2.1" +git2 = "0.18.2" +validator = { version = "0.16.1",features=['derive'] } +lazy_static = "1.4.0" +regex = "1.10.3" [build-dependencies] glib-build-tools = "0.17.0" \ No newline at end of file diff --git a/data/css/main.css b/data/css/main.css index ba92bd8..8d835f8 100644 --- a/data/css/main.css +++ b/data/css/main.css @@ -31,4 +31,8 @@ paned>separator { .lv { background: transparent; +} + +.error { + border: red; } \ No newline at end of file diff --git a/src/components/app.rs b/src/components/app.rs index e4626cc..81c7593 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -1,6 +1,7 @@ use crate::components::new_project::NewPageModel; use adw::prelude::*; use gtk::prelude::*; +use gtk::Widget; use relm4::actions::RelmActionGroup; use relm4::{actions::*, prelude::*, Component, ComponentParts, ComponentSender}; use std::{ @@ -12,7 +13,6 @@ use std::{ rc::Rc, sync::{Arc, Mutex}, }; -use gtk::Widget; relm4::new_action_group!(FileActionGroup, "file"); relm4::new_stateless_action!(OpenAction, FileActionGroup, "open"); @@ -20,7 +20,7 @@ pub type ElementKey = String; #[derive(Debug)] pub enum AppMsg { - NewProject + NewProject, } pub struct AppModel { new_page_model: Controller, @@ -42,8 +42,8 @@ impl Component for AppModel { view! { #[root] main_window=adw::ApplicationWindow { - set_default_width: 1200, - set_default_height: 900, + set_default_width: 900, + set_default_height: 600, set_focus_on_click:true, connect_close_request[sender] => move |_| { let app = relm4::main_application(); @@ -76,7 +76,6 @@ impl Component for AppModel { set_maximum_size: 1000, gtk::Box{ set_orientation: gtk::Orientation::Vertical, - set_hexpand: true, set_vexpand: true, set_valign: gtk::Align::Center, set_halign: gtk::Align::Center, @@ -85,11 +84,16 @@ impl Component for AppModel { add_css_class: "h1", set_text: "Rayshon Radar Project Tools" }, - gtk::Button { - set_icon_name: "add-filled", - connect_clicked[sender] => move |_| { - sender.input(AppMsg::NewProject); - }, + gtk::Box{ + set_halign: gtk::Align::Center, + gtk::Button { + set_icon_name: "add-filled", + set_hexpand: false, + set_size_request: (50, 50), + connect_clicked[sender] => move |_| { + sender.input(AppMsg::NewProject); + }, + } }, } } diff --git a/src/components/new_project.rs b/src/components/new_project.rs index 1e93745..b3e6d69 100644 --- a/src/components/new_project.rs +++ b/src/components/new_project.rs @@ -1,6 +1,9 @@ use crate::components::setting_item::{SettingItem, SettingType}; +use crate::components::NewPageMsg::RadarEdit; use crate::config::{CommonConfig, RadarConfig}; use adw::prelude::*; +use adw::{glib, PreferencesPage}; +use gtk::ffi::gtk_content_fit_get_type; use gtk::glib::clone; use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, ToggleButtonExt}; use gtk::ResponseType::No; @@ -10,8 +13,7 @@ use relm4::{prelude::*, view}; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; -use adw::PreferencesPage; -use crate::components::NewPageMsg::RadarEdit; +use validator::Validate; #[tracker::track] #[derive(Debug)] @@ -19,14 +21,16 @@ pub struct NewPageModel { project_name: String, radar_num: usize, current_idx: usize, - radar_configs: Vec, + radar_configs: Vec>>, } #[derive(Debug)] pub enum NewPageMsg { ChangeName(String), ChangeRadarNum(usize), - SwitchToRadar, + CheckRadarConfig, + SwitchToRadar(usize), + SwitchToAlgorithm, RadarEdit(usize), } @@ -86,18 +90,14 @@ impl Component for NewPageModel { add=&adw::EntryRow{ set_title: "Version", }, + #[name = "radar_num"] add=&adw::SpinRow{ set_title: "Project Name", // set_range: (0.0, 100.0), set_adjustment: Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0)), set_value: model.radar_num as f64, set_numeric: true, - connect_value_notify[sender] => move |s| { - sender.input(NewPageMsg::ChangeRadarNum(s.value() as usize)); - } }, - // #[iterate] - // add: model.common_setting.to_settings().iter_mut().map(|v| v.widget()).collect::>().iter() }, add=&adw::PreferencesGroup{ add=>k::Grid{ @@ -110,63 +110,30 @@ impl Component for NewPageModel { attach[1,0,1,1] = >k::Button { set_label: "Next", set_halign: gtk::Align::End, - connect_clicked[sender, stack] => move |_| { - sender.input(NewPageMsg::SwitchToRadar); - stack.set_visible_child_name("Radar"); + connect_clicked[sender, radar_num] => move |_| { + sender.input(NewPageMsg::ChangeRadarNum(radar_num.value() as usize)); + sender.input(NewPageMsg::SwitchToRadar(0)); } } }, - add=>k::Box{ - set_hexpand: true, - set_halign: gtk::Align::Center, - #[name="progress"] - gtk::Box{ - set_orientation: gtk::Orientation::Vertical, - gtk::ProgressBar{ - set_margin_top: 30, - set_fraction:0.0 - }, - gtk::Grid{ - set_margin_top: 10, - set_column_homogeneous: true, - add_css_class: "content", - attach[0,0,1,1] = >k::Label{ - set_halign: gtk::Align::Start, - set_text:"0%" - }, - attach[1,0,1,1] = >k::Label{ - set_text:"Radar Config" - }, - attach[2,0,1,1] = >k::Label{ - set_halign: gtk::Align::End, - set_text:"0%" - }, - } - - } - - } } } }, - algorithm_setting = gtk::Box{}, + algorithm_setting = gtk::Box{ + + }, radar_setting=gtk::Box{ set_orientation: gtk::Orientation::Vertical, set_valign: gtk::Align::Center, - gtk::Button{ - set_label: "Add Radar", - connect_clicked[sender] => move |_| { - sender.input(NewPageMsg::RadarEdit(0)); - } - }, #[name="radar_stack"] adw::ViewStack{ - } }, stack.add_titled(&common_setting, Some("Common"), "Common"), stack.add_titled(&radar_setting, Some("Radar"), "Radar"), - stack.add_titled(&algorithm_setting, Some("Algorithm"), "Algorithm"), + alg_page = stack.add_titled(&algorithm_setting, Some("Algorithm"), "Algorithm") -> gtk::StackPage{ + set_visible: false + }, } fn init( init: Self::Init, @@ -178,36 +145,151 @@ impl Component for NewPageModel { project_name: format!("Project {}", 0), radar_num: 1, radar_configs: Vec::new(), - current_idx:0, + current_idx: 0, // common_setting: config, tracker: 0, }; - - let widgets = view_output!(); ComponentParts { model, widgets } } - fn update(&mut self, msg: Self::Input, sender: ComponentSender, root: &Self::Root) { + fn update_with_view( + &mut self, + widgets: &mut Self::Widgets, + msg: Self::Input, + sender: ComponentSender, + root: &Self::Root, + ) { self.reset(); match msg { NewPageMsg::ChangeName(name) => { self.set_project_name(name); } NewPageMsg::ChangeRadarNum(num) => { - } - NewPageMsg::SwitchToRadar => { - let mut a = Vec::new(); - for _ in 0..self.radar_num { - a.push(RadarConfig::default()); + let stack = widgets.radar_stack.clone(); + let config_stack = widgets.stack.clone(); + + let mut radar_configs = Vec::with_capacity(num); + for i in 0..num { + let config = Rc::new(RefCell::new(RadarConfig::default())); + let config_group = RadarConfig::to_preferences_entrys(config.clone()); + relm4::view! { + page = adw::PreferencesPage{ + add=&adw::PreferencesGroup{ + add=>k::Grid{ + set_hexpand: true, + set_column_homogeneous: true, + #[name = "label"] + attach[0,0,1,1] = >k::Label{ + set_halign: gtk::Align::Start, + add_css_class: "h1", + set_text:"Radar", + }, + attach[1,0,1,1] = >k::Label{ + set_text: format!("{}/{}", i + 1, num).as_str(), + set_halign: gtk::Align::End, + add_css_class: "h3" + } + }, + }, + add=&adw::PreferencesGroup{ + #[iterate] + add:config_group.iter() + }, + add=&adw::PreferencesGroup{ + add=>k::Grid{ + set_hexpand: true, + set_column_homogeneous: true, + attach[0,0,1,1] = >k::Button { + set_label: "Prev", + set_halign: gtk::Align::Start, + set_sensitive: i != 0, + connect_clicked[sender] => move |_| { + sender.input(NewPageMsg::SwitchToRadar(i - 1)); + } + }, + attach[1,0,1,1] = >k::Button { + set_label: if i != num - 1 {"Next"}else{"Finish"}, + set_halign: gtk::Align::End, + connect_clicked[sender] => move |_| { + if i != num - 1 { + sender.input(NewPageMsg::CheckRadarConfig); + sender.input(NewPageMsg::SwitchToRadar(i + 1)); + } else { + sender.input(NewPageMsg::SwitchToAlgorithm); + } + } + } + } + } + } + } + + config_group + .first() + .unwrap() + .bind_property("text", &label, "label") + .flags(glib::BindingFlags::DEFAULT) + .build(); + widgets + .radar_stack + .add_titled(&page, Some(format!("{}", i).as_str()), "Radar"); + + radar_configs.push(config); } - self.set_radar_configs(a); + self.radar_configs = radar_configs; + self.set_radar_num(num); + } + NewPageMsg::SwitchToRadar(idx) => { + if widgets.stack.visible_child_name().unwrap() != "Radar" { + widgets.stack.set_visible_child_name("Radar"); + } + widgets + .radar_stack + .set_visible_child_name(format!("{}", idx).as_str()); } NewPageMsg::RadarEdit(index) => { let idx = self.get_current_idx(); self.set_current_idx(idx + 1); } + NewPageMsg::CheckRadarConfig => { + let (valid, _) = self.check_radar_config(); + if valid { + widgets.alg_page.set_visible(true); + } else { + widgets.alg_page.set_visible(false); + } + } + NewPageMsg::SwitchToAlgorithm => { + let (valid, un) = self.check_radar_config(); + if valid { + widgets.alg_page.set_visible(true); + widgets.stack.set_visible_child_name("Algorithm"); + } else { + widgets.alg_page.set_visible(false); + let idx = un.first().unwrap(); + widgets.radar_stack.set_visible_child_name(format!("{}", idx).as_str()); + } + } } + + self.update_view(widgets, sender); + } +} + +impl NewPageModel { + fn check_radar_config(&self) -> (bool, Vec) { + let mut unvalided = Vec::new(); + ( + self.radar_configs.iter().enumerate().all(|(idx, x)| { + let c = x.borrow().validate().is_ok(); + if !c { + unvalided.push(idx); + } + c + }), + unvalided, + ) } } diff --git a/src/components/setting_item/mod.rs b/src/components/setting_item/mod.rs index 0665cdf..b503fc5 100644 --- a/src/components/setting_item/mod.rs +++ b/src/components/setting_item/mod.rs @@ -1,8 +1,8 @@ -use std::cell::{Cell, RefCell}; use adw::prelude::*; use gtk::prelude::*; use gtk::{StringList, Widget}; use relm4::{factory::FactoryView, gtk, prelude::*, FactorySender, RelmObjectExt}; +use std::cell::{Cell, RefCell}; use std::rc::Rc; #[derive(Debug)] @@ -12,9 +12,13 @@ pub enum Msg {} pub enum OutputMsg {} pub enum SettingType { - Select(Vec, Option>>), + Select(Vec, Option>), Action, - Entry(Option, Option bool>>, Option>>), + Entry( + Option, + Option bool>>, + Option>, + ), Switch(bool, Option>>), Spin(f64, f64, f64, f64, Option>>), } @@ -32,9 +36,8 @@ impl SettingItem { (match &mut self._type { SettingType::Select(selects, selected) => { let w = adw::ComboRow::builder().title(&self.title).build(); - if let Some(selected) = selected { - let selected = selected.clone(); - w.connect_selected_item_notify(|s| { + if let Some(selected) = selected.take() { + w.connect_selected_item_notify(move |s| { // println!("{}", text); // selected.set(text.to_string()); }); @@ -60,18 +63,20 @@ impl SettingItem { w.set_text(text); } - let f = f.take(); - let buffer = buffer.clone(); - if let Some(buffer) = buffer { + if let Some(f) = f.take() { + let mut buffer = buffer.take(); w.connect_text_notify(move |s| { let text = s.text(); - if let Some(f) = f.as_ref(){ - if !f(&text) { - s.set_text(""); - return; - } + if !f(text.as_str()) { + s.add_css_class("error"); + return; + } else { + s.remove_css_class("error"); + } + + if let Some(buffer) = buffer.as_ref(){ + buffer(text.as_str()); } - *buffer.borrow_mut() = text.to_string(); }); } w.upcast::() diff --git a/src/config.rs b/src/config.rs index 99cb51e..4b7121d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,10 +1,21 @@ +use crate::components::{SettingItem, SettingType}; +use gtk::Widget; +use lazy_static::lazy_static; +use regex::Regex; use std::cell::{Cell, Ref, RefCell}; use std::collections::HashMap; use std::rc::Rc; -use crate::components::{SettingItem, SettingType}; +use validator::{Validate, ValidateArgs, ValidationError}; + +lazy_static! { + static ref LOC: Regex = Regex::new( + r"^\s*(0|[1-9]\d*)(\.\d+)?\s*,\s*(0|[1-9]\d*)(\.\d+)?\s*,\s*(0|[1-9]\d*)(\.\d+)?\s*$" + ) + .unwrap(); +} #[derive(Clone, Debug, Default, PartialOrd, PartialEq)] -pub struct CommonConfig{ +pub struct CommonConfig { pub name: Rc>, pub version: Rc>, radar_lens: Rc>, @@ -12,48 +23,140 @@ pub struct CommonConfig{ pub algorithms: Vec, } -#[derive( Clone, Debug, PartialOrd, PartialEq, Default)] -pub struct RadarConfig{ +#[derive(Clone, Debug, PartialOrd, PartialEq, Default)] +pub struct _RadarConfig { pub name: Rc>, pub _type: Rc>, - loc: Rc>, + loc: Rc>, az_beam_width: Rc>, el_beam_width: Rc>, azs_method: Rc>, els_method: Rc>, r_limit: Rc>, } +#[derive(Clone, Debug, PartialOrd, PartialEq, Default, Validate)] +pub struct RadarConfig { + pub name: String, + pub _type: String, + #[validate(regex = "LOC")] + pub loc: String, + pub az_beam_width: f64, + pub el_beam_width: f64, + pub azs_method: usize, + pub els_method: usize, + pub r_limit: f64, +} -#[derive( Clone, Debug, PartialOrd, PartialEq)] +#[derive(Clone, Debug, PartialOrd, PartialEq)] pub struct AlgorithmConfig { name: String, version: String, - // info: HashMap } +macro_rules! to_setting { + ($settings:ident,$config:ident, $(($branch:path, $name:literal, [$($check:expr);*], $func: expr)),+) => { + $( + let config = $config.clone(); + $settings.push(SettingItem::new( + $name.to_string(), + $branch( + $($check,)* + Some(Box::new(move |x| $func(x, config.clone()))), + ), + )); + )+ + }; +} impl RadarConfig { - pub fn to_settings(&self) -> Vec{ + pub fn to_settings(config: Rc>) -> Vec { let mut settings = Vec::new(); - settings.push(SettingItem::new("Name".to_string(), SettingType::Entry(None, None, None))); - settings.push(SettingItem::new("Type".to_string(), SettingType::Entry(None, None, None))); - settings.push(SettingItem::new("Location".to_string(), SettingType::Entry(None, None, None))); - settings.push(SettingItem::new("Azimuth Beam Width".to_string(), SettingType::Entry(None, None, None))); - settings.push(SettingItem::new("Elevation Beam Width".to_string(), SettingType::Entry(None,None,None))); - settings.push(SettingItem::new("Azimuth Method".to_string(), SettingType::Select(vec!["1".to_string(), "2".to_string(), "3".to_string()], None))); - settings.push(SettingItem::new("Elevation Method".to_string(), SettingType::Select(vec!["1".to_string(), "2".to_string(), "3".to_string()], None))); - settings.push(SettingItem::new("Range Limit".to_string(), SettingType::Entry(None,None,None))); + let a = vec!["a".to_string()]; + let b = vec!["b".to_string()]; + to_setting!( + settings, + config, + ( + SettingType::Entry, + "Name", + [None; None], + move |x: &str, config: Rc>| { + let mut config = config.borrow_mut(); + config.name = x.to_string(); + } + ), + ( + SettingType::Entry, + "Type", + [None; None], + move |x: &str, config: Rc>| { + let mut config = config.borrow_mut(); + config._type = x.to_string(); + } + ), + ( + SettingType::Entry, + "Location", + [None; Some(Box::new(|x| LOC.is_match(x)))], + move |x: &str, config: Rc>| { + let mut config = config.borrow_mut(); + config.loc = x.to_string(); + } + ), + ( + SettingType::Entry, + "Azimuth Beam Width", + [None; Some(Box::new(|x| x.parse::().is_ok()))], + move |x: &str, config: Rc>| { + let mut config = config.borrow_mut(); + config.az_beam_width = x.parse::().unwrap(); + } + ), + ( + SettingType::Entry, + "Elevation Beam Width", + [None; Some(Box::new(|x| x.parse::().is_ok()))], + move |x: &str, config: Rc>| { + let mut config = config.borrow_mut(); + config.el_beam_width = x.parse::().unwrap(); + } + ), + ( + SettingType::Select, + "Azimuth Method", + [a], + move |x, config: Rc>| { + // config.borrow_mut().name.replace(x); + } + ), + ( + SettingType::Select, + "Elevation Method", + [b], + move |x, config: Rc>| { + // config.borrow_mut().name.replace(x); + } + ), + ( + SettingType::Entry, + "Range Limit", + [None; None], + move |x, config: Rc>| { + // config.borrow_mut().name.replace(x); + } + ) + ); settings } - pub fn to_preferences_group(&self) -> adw::PreferencesGroup { + pub fn to_preferences_entrys(config: Rc>) -> Vec { use adw::prelude::*; - let group = adw::PreferencesGroup::default(); - let mut settings = self.to_settings(); - for setting in settings.iter_mut(){ - group.add(&setting.widget()); + let mut group = Vec::new(); + let mut settings = Self::to_settings(config); + for setting in settings.iter_mut() { + group.push(setting.widget()); } group } -} \ No newline at end of file +}