diff --git a/gi/src/graphics/mod.rs b/gi/src/graphics/mod.rs index 8bd323e..efe6626 100644 --- a/gi/src/graphics/mod.rs +++ b/gi/src/graphics/mod.rs @@ -143,5 +143,5 @@ pub enum MouseState { #[derive(Debug, Clone)] pub struct MouseKeyboardState { pub mouse_state: MouseState, - pub keyboard_state: [bool; 652], + pub keyboard_state: [bool; 4], } diff --git a/gi/src/graphics/transforms/plane.rs b/gi/src/graphics/transforms/plane.rs index 9a2da0c..069f86e 100644 --- a/gi/src/graphics/transforms/plane.rs +++ b/gi/src/graphics/transforms/plane.rs @@ -56,11 +56,8 @@ impl AttachWithIO for PlaneTrans { viewport: &ViewPort, ) -> bool { let viewport_size = viewport.size(); - // let shift_key = state.keyboard_state[imgui::Key::LeftShift as usize]; - // let ctrl_key = state.keyboard_state[imgui::Key::LeftCtrl as usize]; - - let shift_key = false; - let ctrl_key = false; + let shift_key = state.keyboard_state[1]; + let ctrl_key = state.keyboard_state[0]; match &state.mouse_state { MouseState::Drag { from, delta } => { diff --git a/gi/src/pg/mod.rs b/gi/src/pg/mod.rs index 8d6c008..5747bf6 100644 --- a/gi/src/pg/mod.rs +++ b/gi/src/pg/mod.rs @@ -38,7 +38,8 @@ static MODULE_PACKAGE_ID: AtomicUsize = AtomicUsize::new(0); #[derive(Debug)] pub enum SideBarInputMsg { - Package(Rc>), + Packages(Vec<(String, Rc>)>), + SwitchTo(gtk::glib::GString), Refresh, None, } diff --git a/gi/src/pg/modules/ppi.rs b/gi/src/pg/modules/ppi.rs index 4f6dd3c..3884e77 100644 --- a/gi/src/pg/modules/ppi.rs +++ b/gi/src/pg/modules/ppi.rs @@ -573,7 +573,7 @@ impl SimpleComponent for PPIModuleConfigComponent { set_adjustment=>k::Adjustment::new( init_config.layer as f64 + 1.0, 1.0, - init_config.max_layer as f64, + init_config.max_layer as f64 + 1.0, 1.0, 1.0, 1.0 diff --git a/gi/src/ui/io.rs b/gi/src/ui/io.rs index f6e936f..4dc5a03 100644 --- a/gi/src/ui/io.rs +++ b/gi/src/ui/io.rs @@ -11,12 +11,12 @@ pub struct MouseIO { #[derive(Debug)] pub struct KeyboardIO { - pub keys: [bool; 652], // 键盘按键状态 + pub keys: [bool; 4], // 键盘按键状态 } impl Default for KeyboardIO { fn default() -> Self { - Self { keys: [false; 652] } + Self { keys: [false; 4] } } } diff --git a/radar-g/src/components/app.rs b/radar-g/src/components/app.rs index 250cbd7..622920c 100644 --- a/radar-g/src/components/app.rs +++ b/radar-g/src/components/app.rs @@ -62,7 +62,9 @@ pub enum FileIOType { pub enum AppMsg { Refresh, FileIO { typ: FileIOType }, + IO { key: u32, pressed: bool }, OpenDialog { widget: Widget }, + OpenFile(PathBuf), CloseDialog, OpenAlert { body: String, title: String }, CloseAlert, @@ -232,7 +234,7 @@ impl Component for AppModel { sidebar_sender, move |model_message| match model_message { MonitorOutputMsg::Attached(new_module) => { - sidebar_sender.emit(SideBarInputMsg::Package(new_module)); + sidebar_sender.emit(SideBarInputMsg::Packages(new_module)); AppMsg::CloseDialog } MonitorOutputMsg::Dialog(widget) => { @@ -272,21 +274,7 @@ impl Component for AppModel { move |response| match response { OpenDialogResponse::Accept(path) => { info!("path: {:?}", path); - match data_pool.borrow_mut().get_or_load(path) { - Ok(data) => { - info!("data: {}", data); - AppMsg::FileIO { - typ: FileIOType::Open(data), - } - } - Err(e) => { - error!("Failed to load data, cause: {:?}", e); - AppMsg::OpenAlert { - body: format!("Failed to load data, cause: {:?}", e), - title: "Error".to_string(), - } - } - } + AppMsg::OpenFile(path) } _ => AppMsg::Close, } @@ -294,6 +282,22 @@ impl Component for AppModel { ) }; + // Drop Target + + let drop_target = + gtk::DropTarget::new(gtk::gio::File::static_type(), gtk::gdk::DragAction::COPY); + + let drop_sender = sender.clone(); + + drop_target.connect_drop(move |_drop_target, value, _x, _y| { + if let Ok(file) = value.get::() { + if let Some(path) = file.path() { + drop_sender.input(AppMsg::OpenFile(path)); + } + } + true + }); + let model = AppModel { render, setting, @@ -307,6 +311,35 @@ impl Component for AppModel { let render = model.render.widget(); let sidebar = model.sidebar.widget(); let widgets = view_output!(); + + // Key Detector + let key_detector = gtk::EventControllerKey::new(); + + key_detector.connect_key_pressed(clone!( + #[strong] + sender, + move |_, key, code, modifier| { + sender.input(AppMsg::IO { + key: key.to_value().get_owned().unwrap(), + pressed: true, + }); + gtk::glib::Propagation::Proceed + } + )); + + key_detector.connect_key_released(clone!( + #[strong] + sender, + move |_, key, code, modifier| { + sender.input(AppMsg::IO { + key: key.to_value().get_owned().unwrap(), + pressed: false, + }); + } + )); + + widgets.main_window.add_controller(key_detector); + widgets.main_window.add_controller(drop_target); let mut group = RelmActionGroup::::new(); relm4::main_application().set_accelerators_for_action::(&["O"]); let action: RelmAction = { @@ -343,6 +376,18 @@ impl Component for AppModel { AppMsg::CloseDialog => { widgets.dialog.close(); } + + AppMsg::IO { key, pressed } => { + // Skip the key event if it is the ESC key + if key == 16777215 { + return; + } + if pressed { + self.render.emit(MonitorInputMsg::KeyPress(key)); + } else { + self.render.emit(MonitorInputMsg::KeyRelease(key)); + } + } AppMsg::OpenAlert { body, title } => { widgets.alert_dialog.set_body(&body); widgets.alert_dialog.set_title(&title); @@ -354,6 +399,25 @@ impl Component for AppModel { widgets.alert_dialog.present(Some(root)); } + + AppMsg::OpenFile(path) => { + let mut datapool = self.file_pool.borrow_mut(); + match datapool.get_or_load(path) { + Ok(data) => { + info!("data: {}", data); + _sender.input(AppMsg::FileIO { + typ: FileIOType::Open(data), + }); + } + Err(e) => { + error!("Failed to load data, cause: {:?}", e); + _sender.input(AppMsg::OpenAlert { + body: format!("Failed to load data, cause: {:?}", e), + title: "Error".to_string(), + }); + } + } + } AppMsg::FileIO { typ: FileIOType::Open(data), } => self.render.emit(MonitorInputMsg::PushData(data)), diff --git a/radar-g/src/components/monitor/dialog_widget.rs b/radar-g/src/components/monitor/dialog_widget.rs index bf21f54..e0c1d70 100644 --- a/radar-g/src/components/monitor/dialog_widget.rs +++ b/radar-g/src/components/monitor/dialog_widget.rs @@ -1,6 +1,6 @@ use epoxy::S; use gi::pg::ModuleRefs; -use gtk::Widget; +use gtk::{SingleSelection, Widget}; use radarg_core::Data; use std::collections::HashMap; @@ -9,7 +9,7 @@ use relm4::{ factory::FactoryVecDeque, gtk::{ self, - glib::{clone, *}, + glib::{self, clone, *}, prelude::*, }, prelude::*, @@ -31,17 +31,26 @@ pub struct ItemInfo { #[derive(Debug)] pub enum DialogOutput { Cancel, - Open(usize), + Open(Vec), } +#[tracker::track] pub struct Dialog { - list_view_wrapper: TypedColumnView, + #[do_not_track] + list_view_wrapper: TypedColumnView, + selected: Vec, +} + +#[derive(Debug)] +pub enum DialogInput { + Selected(Vec), + Open, } #[relm4::component(pub)] impl SimpleComponent for Dialog { type Widgets = DialogWidgets; type Init = HashMap<(usize, String), Vec>; - type Input = (); + type Input = DialogInput; type Output = DialogOutput; view! { @@ -84,6 +93,11 @@ impl SimpleComponent for Dialog { }, gtk::Button{ set_label:"Open", + #[track = "model.changed(Dialog::selected())"] + set_sensitive: !model.selected.is_empty(), + connect_clicked[sender] => move |_| { + sender.input(DialogInput::Open); + }, }, }, } @@ -115,25 +129,71 @@ impl SimpleComponent for Dialog { let model = Self { list_view_wrapper: list_view, + selected: Vec::with_capacity(10), + tracker: 0, }; let list = &model.list_view_wrapper.view; - let selection = list.model().unwrap(); - selection.connect_selection_changed(|a, b, c| { - println!("Selection changed"); - println!(" b: {}, c: {}", b, c); - }); let widgets = view_output!(); + selection.connect_selection_changed(clone!( + #[strong] + sender, + move |this, from, num| { + let selection = this.selection(); + let iter = gtk::BitsetIter::init_first(&selection); + if let Some((iter, first)) = iter { + if !iter.is_valid() { + return; + } else { + let mut selected = vec![first]; + selected.extend(iter.map(|i| i)); + + sender.input(DialogInput::Selected(selected)); + } + } + + // this.selected().map(|selected| { + // sender.input(DialogInput::Selected(Some(selected))); + // }); + // let selection: >k::MultiSelection = this.downcast_ref().unwrap(); + // let selected = selection. + // let selected = selection.selected(); + // sender.input(DialogInput::Selected(Some(selected))); + } + )); ComponentParts { model: model, widgets, } } - fn update(&mut self, message: Self::Input, sender: ComponentSender) {} + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + self.reset(); + match message { + DialogInput::Selected(selected) => { + let s = selected + .into_iter() + .map(|s| { + let item = self.list_view_wrapper.get(s); + item + }) + .filter(|item| item.is_some()) + .map(|item| item.unwrap().borrow().id) + .collect::>(); + + self.update_selected(|_s| { + _s.clear(); + _s.extend(s); + }); + } + DialogInput::Open => { + sender.output(DialogOutput::Open(self.selected.clone())); + } + } + } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] diff --git a/radar-g/src/components/monitor/messages.rs b/radar-g/src/components/monitor/messages.rs index 500f19b..5f3ff41 100644 --- a/radar-g/src/components/monitor/messages.rs +++ b/radar-g/src/components/monitor/messages.rs @@ -7,6 +7,9 @@ use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; pub enum MonitorInputMsg { PushData(Value), Draw(Arc), + Prepare(Vec>), + KeyPress(u32), + KeyRelease(u32), QueueDraw, None, } @@ -18,6 +21,11 @@ impl Debug for MonitorInputMsg { MonitorInputMsg::Draw(data) => { write!(f, "MonitorInputMsg::Draw({:?})", data) } + MonitorInputMsg::Prepare(data) => { + write!(f, "MonitorInputMsg::Prepare({:?})", data) + } + MonitorInputMsg::KeyPress(key) => write!(f, "MonitorInputMsg::Key({:?})", key), + MonitorInputMsg::KeyRelease(key) => write!(f, "MonitorInputMsg::KeyRelease({:?})", key), MonitorInputMsg::PushData(data) => write!(f, "MonitorInputMsg::PushData({:?})", data), MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"), } @@ -26,7 +34,7 @@ impl Debug for MonitorInputMsg { #[derive(Debug)] pub enum MonitorOutputMsg { - Attached(Rc>), + Attached(Vec<(String, Rc>)>), Dialog(Widget), DialogClose, Alert(String, String), diff --git a/radar-g/src/components/monitor/monitor.rs b/radar-g/src/components/monitor/monitor.rs index d2b6bce..225ffd5 100644 --- a/radar-g/src/components/monitor/monitor.rs +++ b/radar-g/src/components/monitor/monitor.rs @@ -39,7 +39,9 @@ pub struct MonitorModel { render_cfg: RenderConfig, sidebar_open: bool, sidebar_width: i32, - module_packages: Vec>>, + #[do_not_track] + controller: Option>, + module_packages: Vec<(String, Rc>)>, #[do_not_track] mainload: MainLoadAttach, } @@ -73,7 +75,7 @@ impl Component for MonitorModel { let scale = r.scale(); }, #[track = "model.changed(MonitorModel::module_packages())"] - draw: &model.module_packages, + draw: &model.module_packages.iter().map(|m| m.1.clone()).collect(), }, add_overlay=>k::Button{ @@ -121,8 +123,11 @@ impl Component for MonitorModel { sender.input_sender(), move |msg| match msg { DialogOutput::Open(index) => { - let data = data.iter().find(|d| *d.0 == index).unwrap(); - MonitorInputMsg::Draw(data.1.clone()) + let prepare_datas = index.into_iter().map(|i| { + let data = data.iter().find(|d| *d.0 == i).unwrap(); + data.1.clone() + }); + MonitorInputMsg::Prepare(prepare_datas.collect()) } DialogOutput::Cancel => { new_sender.output(MonitorOutputMsg::DialogClose); @@ -132,7 +137,15 @@ impl Component for MonitorModel { }, ); - let widget = dialog.widget().to_owned().upcast(); + self.controller.replace(dialog); + + let widget = self + .controller + .as_ref() + .unwrap() + .widget() + .to_owned() + .upcast(); sender.output(MonitorOutputMsg::Dialog(widget)); } @@ -141,25 +154,65 @@ impl Component for MonitorModel { MonitorInputMsg::QueueDraw => { widgets.renderer.queue_draw(); } - MonitorInputMsg::Draw(ref data) => { - widgets.renderer.get_gi(|gi| { - let data: &Data = &*data; + // MonitorInputMsg::KeyPress(key) => { + // widgets.renderer.set_key_pressed(key); + // } + + // MonitorInputMsg::KeyRelease(key) => { + // widgets.renderer.set_key_released(key); + // } + MonitorInputMsg::Prepare(datas) => widgets.renderer.get_gi(|gi| { + let mut packages: Vec<(String, Rc>)> = vec![]; + for data in datas { + let data = &*data; match gi.program().ppi().load_data(data.into(), &SETTING) { Ok(package) => { let package = Rc::new(RefCell::new(package.into())); - self.set_module_packages(vec![package.clone()]); - sender.output(MonitorOutputMsg::Attached(package)); + packages.push((data.description.clone(), package)); } Err(e) => { error!("Error loading data: {:?}", e); sender.output(MonitorOutputMsg::Alert(e.to_string(), format!("Close"))); + break; } } + } - sender.input(MonitorInputMsg::QueueDraw); + self.update_module_packages(|p| { + p.clear(); + p.extend(packages); }); + + sender.output(MonitorOutputMsg::Attached(self.module_packages.clone())); sender.output(MonitorOutputMsg::DialogClose); + }), + MonitorInputMsg::Draw(ref data) => { + // widgets.renderer.get_gi(|gi| { + // let data: &Data = &*data; + + // match gi.program().ppi().load_data(data.into(), &SETTING) { + // Ok(package) => { + // let package = Rc::new(RefCell::new(package.into())); + // self.set_module_packages(vec![package.clone()]); + // sender.output(MonitorOutputMsg::Attached(package)); + // } + // Err(e) => { + // error!("Error loading data: {:?}", e); + // sender.output(MonitorOutputMsg::Alert(e.to_string(), format!("Close"))); + // } + // } + + // sender.input(MonitorInputMsg::QueueDraw); + // }); + // sender.output(MonitorOutputMsg::DialogClose); + } + MonitorInputMsg::KeyPress(key) => { + widgets.renderer.set_key_pressed(key); + } + + MonitorInputMsg::KeyRelease(key) => { + widgets.renderer.set_key_released(key); } MonitorInputMsg::None => {} _ => {} @@ -186,6 +239,7 @@ impl Component for MonitorModel { module_packages: vec![], sidebar_open: true, sidebar_width: 400, + controller: None, tracker: 0, }; diff --git a/radar-g/src/components/sidebar/sidebar.rs b/radar-g/src/components/sidebar/sidebar.rs index e407a33..b2c3ff0 100644 --- a/radar-g/src/components/sidebar/sidebar.rs +++ b/radar-g/src/components/sidebar/sidebar.rs @@ -32,7 +32,7 @@ use super::{ }; pub struct SideBarModel { - components: Option, + components: Vec, } #[derive(Debug)] @@ -51,49 +51,31 @@ impl Component for SideBarModel { view! { #[root] gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_spacing: 5, - set_margin_all: 5, - + set_orientation: gtk::Orientation::Vertical, #[name="container"] gtk::Box { - gtk::Button { - set_hexpand:true, - set_label: "Refresh", - connect_clicked[sender] => move |_| { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_end:10, + set_margin_top:5, - view! { - widget=adw::BreakpointBin{ - set_width_request: 800, - set_height_request:600, - - #[wrap(Some)] - set_child=&adw::ToolbarView{ - set_hexpand:true, - set_vexpand:true, - - add_top_bar=&adw::HeaderBar{ - #[wrap(Some)] - set_title_widget=>k::Label{ - set_label: "Header", - }, - }, - - #[wrap(Some)] - set_content=>k::Box{ - gtk::Button{ - set_label:"Expanders", - }, - gtk::Button{ - set_label:"Expanders", - } - } - - } - } - }; - sender.output(SideBarOutputMsg::Dialog(widget.upcast())); + #[name="dropdown"] + gtk::DropDown { + connect_selected_item_notify[sender] => move |this| { + let item = this.selected_item(); + item.map(|item| { + let item:gtk::StringObject = item.downcast().unwrap(); + let name = item.string(); + sender.input(SideBarInputMsg::SwitchTo(name)); + }); } + }, + + #[name="stack"] + gtk::Stack{ + set_transition_type:gtk::StackTransitionType::SlideLeftRight, + set_transition_duration:200, + set_hexpand:true, } } }, @@ -105,8 +87,9 @@ impl Component for SideBarModel { root: Self::Root, sender: ComponentSender, ) -> ComponentParts { - let app = relm4::main_application(); - let mut model = SideBarModel { components: None }; + let mut model = SideBarModel { + components: Vec::with_capacity(10), + }; let widgets = view_output!(); ComponentParts { model, widgets } } @@ -119,19 +102,31 @@ impl Component for SideBarModel { root: &Self::Root, ) { match message { - SideBarInputMsg::Package(package) => { - let package = package.borrow(); - let input_sender = sender.input_sender(); - let components = package - .component_builder() - .build(&package, root, input_sender); + SideBarInputMsg::Packages(package) => { + let names = package.iter().map(|v| v.0.as_str()).collect::>(); + let model = gtk::StringList::new(&names); + widgets.dropdown.set_model(Some(&model)); - self.components = Some(components); + for (name, package) in package { + let package = package.borrow(); - widgets.container.remove_all(); - widgets - .container - .append(&self.components.as_ref().unwrap().widget()); + let input_sender = sender.input_sender(); + let components = + package + .component_builder() + .build(&package, root, input_sender); + self.components.push(components); + + widgets.stack.add_titled( + &self.components.last().unwrap().widget(), + Some(&name), + &name, + ); + } + } + + SideBarInputMsg::SwitchTo(name) => { + widgets.stack.set_visible_child_name(&name); } SideBarInputMsg::Refresh => { diff --git a/radar-g/src/widgets/render/imp.rs b/radar-g/src/widgets/render/imp.rs index f8a9ac8..7b4057f 100644 --- a/radar-g/src/widgets/render/imp.rs +++ b/radar-g/src/widgets/render/imp.rs @@ -167,6 +167,9 @@ impl GLAreaImpl for Render { unsafe { gl.clear_color(0.0, 0.0, 0.0, 1.0); gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT); + gl.enable(glow::DEPTH_TEST); + // gl.enable(glow::BLEND); + // gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); } if let Some(gi) = gi.as_mut() { diff --git a/radar-g/src/widgets/render/mod.rs b/radar-g/src/widgets/render/mod.rs index 98fa37b..31821f2 100644 --- a/radar-g/src/widgets/render/mod.rs +++ b/radar-g/src/widgets/render/mod.rs @@ -42,6 +42,8 @@ impl Render { let scale_acc = Arc::new(Mutex::new(0.0)); let dpi = this.scale_factor() as f32; + this.set_has_depth_buffer(true); + let pointer_location_detecture = gtk::EventControllerMotion::new(); let dpi = this.scale_factor() as f32; @@ -166,6 +168,30 @@ impl Render { self.imp().window_size().unwrap() } + pub fn set_key_pressed(&self, key: u32) { + let io = &self.imp().io; + let mut io_mut = io.borrow_mut(); + match key { + 65507 => io_mut.keyboard.keys[0] = true, + 65505 => io_mut.keyboard.keys[1] = true, + 65506 => io_mut.keyboard.keys[2] = true, + 65508 => io_mut.keyboard.keys[3] = true, + _ => {} + } + } + + pub fn set_key_released(&self, key: u32) { + let io = &self.imp().io; + let mut io_mut = io.borrow_mut(); + match key { + 65507 => io_mut.keyboard.keys[0] = false, + 65505 => io_mut.keyboard.keys[1] = false, + 65506 => io_mut.keyboard.keys[2] = false, + 65508 => io_mut.keyboard.keys[3] = false, + _ => {} + } + } + pub fn draw(&self, packages: &Vec>>) { let mut modules = self.imp().modules.borrow_mut(); *(&mut *modules) = packages.clone();