From 3a9f0dcaa3ddbdc6121b7b7a431a492441a7f8c6 Mon Sep 17 00:00:00 2001 From: Tsuki Date: Sat, 31 Aug 2024 20:59:21 +0800 Subject: [PATCH] rebuild factor --- .dir-locals.el | 10 + Cargo.lock | 18 +- gi/Cargo.toml | 1 + gi/src/errors.rs | 4 +- gi/src/graphics/collections/agg_fast_path.rs | 4 +- gi/src/graphics/mod.rs | 4 +- gi/src/graphics/ppi.rs | 10 +- gi/src/pg/app.rs | 24 +- gi/src/pg/mod.rs | 91 ++++--- gi/src/pg/modules/mod.rs | 11 +- gi/src/pg/modules/ppi.rs | 227 +++++++++++++++--- gi/src/ui/io.rs | 6 + loaders/etws_loader/src/error.rs | 11 +- loaders/etws_loader/src/lib.rs | 2 +- loaders/etws_loader/src/raw.rs | 117 ++++++--- radar-g/src/components/app.rs | 86 ++++--- .../components/control_panel/control_panel.rs | 1 - .../src/components/monitor/dialog_widget.rs | 136 +++++++++++ radar-g/src/components/monitor/messages.rs | 14 +- radar-g/src/components/monitor/mod.rs | 1 + radar-g/src/components/monitor/monitor.rs | 71 ++++-- radar-g/src/components/sidebar/sidebar.rs | 47 +++- radar-g/src/datapool/mod.rs | 54 ----- radar-g/src/main.rs | 4 +- radar-g/src/widgets/render/imp.rs | 2 + radar-g/src/widgets/render/mod.rs | 9 +- radarg_core/Cargo.toml | 3 + radarg_core/src/datapool/mod.rs | 76 ++++++ radarg_core/src/lib.rs | 2 + .../src/plugin_system/mod.rs | 4 +- radarg_core/src/radarg_data/mod.rs | 115 +++++++-- 31 files changed, 905 insertions(+), 260 deletions(-) create mode 100644 .dir-locals.el create mode 100644 radar-g/src/components/monitor/dialog_widget.rs delete mode 100644 radar-g/src/datapool/mod.rs create mode 100644 radarg_core/src/datapool/mod.rs rename {radar-g => radarg_core}/src/plugin_system/mod.rs (98%) diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..6ae50ae --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,10 @@ +((nil . ((eval . (progn + ;; radar_g 调试配置 + (dap-register-debug-template + "radar_g::LLDB" + (list :type "lldb" + :request "launch" + :name "radar_g::LLDB" + :gdbpath "~/.cargo/bin/rust-lldb" + :program "${workspaceFolder}/target/debug/cinrad_g" + :cwd "${workspaceFolder}")) diff --git a/Cargo.lock b/Cargo.lock index 6f0218b..d4432b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -779,7 +779,7 @@ dependencies = [ "proj", "proj-sys", "quadtree_rs", - "quick_cache", + "quick_cache 0.4.3", "radarg_core", "radarg_plugin_interface", "rayon", @@ -1838,6 +1838,7 @@ dependencies = [ "nom", "nom-derive", "once_cell", + "paste 1.0.15", "pathfinder_geometry", "radarg_core", "raw-window-handle", @@ -4159,6 +4160,18 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "quick_cache" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a893a83255c587d31137bc7e350387b49267b0deac44120fd8fa8bd0d61645" +dependencies = [ + "ahash", + "equivalent", + "hashbrown", + "parking_lot", +] + [[package]] name = "quote" version = "0.6.13" @@ -4181,12 +4194,15 @@ dependencies = [ name = "radarg_core" version = "0.1.0" dependencies = [ + "abi_stable", "chrono", + "core_extensions", "dirs", "ndarray 0.16.1", "num-traits", "proj", "proj-sys", + "quick_cache 0.6.5", "radarg_plugin_interface", "relm4", "rust-embed", diff --git a/gi/Cargo.toml b/gi/Cargo.toml index db1a1cc..1c14970 100644 --- a/gi/Cargo.toml +++ b/gi/Cargo.toml @@ -43,6 +43,7 @@ femtovg = "0.9.2" rust-embed = "8.5.0" tempfile = "3.12.0" relm4 = { version = "0.9.0", features = ["libadwaita"] } +paste = "1.0.15" [features] default = ["sdf_font"] diff --git a/gi/src/errors.rs b/gi/src/errors.rs index 092b350..a685cd8 100644 --- a/gi/src/errors.rs +++ b/gi/src/errors.rs @@ -13,8 +13,8 @@ pub enum Error { #[error("Invalid Program {0}")] InvalidProgram(String), - #[error("Invalid CoordType")] - InvalidDataType, + #[error("Error: {0}")] + InvalidDataType(String), #[error("Init Error, cause of {0}")] InitError(anyhow::Error), diff --git a/gi/src/graphics/collections/agg_fast_path.rs b/gi/src/graphics/collections/agg_fast_path.rs index 286631f..c38a466 100644 --- a/gi/src/graphics/collections/agg_fast_path.rs +++ b/gi/src/graphics/collections/agg_fast_path.rs @@ -106,14 +106,14 @@ impl Graphics for AggFastPath { Ok(()) } - fn mount(&mut self, gl: &glow::Context) -> Result<()> { + fn mount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(self.program.native_program); } Ok(()) } - fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + fn unmount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(None); } diff --git a/gi/src/graphics/mod.rs b/gi/src/graphics/mod.rs index 3826d75..8bd323e 100644 --- a/gi/src/graphics/mod.rs +++ b/gi/src/graphics/mod.rs @@ -33,7 +33,7 @@ pub trait Graphics { fn program_mut(&mut self) -> &mut Program; - fn mount(&mut self, gl: &glow::Context) -> Result<()> { + fn mount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(self.program_ref().native_program.clone()); } @@ -41,7 +41,7 @@ pub trait Graphics { Ok(()) } - fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + fn unmount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(None); } diff --git a/gi/src/graphics/ppi.rs b/gi/src/graphics/ppi.rs index fc3f3fc..24a54c4 100644 --- a/gi/src/graphics/ppi.rs +++ b/gi/src/graphics/ppi.rs @@ -53,7 +53,7 @@ impl PPI { pub fn data_info(&self, data: &RadarGridData) -> Result<(f32, f32, ProbeDataType, usize, f32)> { if data.coord_type().is_none() { - return Err(Error::InvalidDataType); + return Err(Error::InvalidDataType(format!("Invalid CoordType"))); } match data.coord_type().unwrap() { CoordType::Polar { @@ -79,7 +79,7 @@ impl PPI { } _ => { - return Err(Error::InvalidDataType); + return Err(Error::InvalidDataType(format!("Invalid CoordType"))); } } } @@ -163,14 +163,14 @@ impl Graphics for PPI { Ok(()) } - fn mount(&mut self, gl: &glow::Context) -> Result<()> { + fn mount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(self.program.native_program); } Ok(()) } - fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + fn unmount(&self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(None); } @@ -216,7 +216,7 @@ impl AttaWithBuffer for PPI { return Ok((vertices, None, len)); } _ => { - return Err(Error::InvalidDataType); + return Err(Error::InvalidDataType(format!("Invalid CoordType"))); } } } diff --git a/gi/src/pg/app.rs b/gi/src/pg/app.rs index 04d1ff4..77e2b3a 100644 --- a/gi/src/pg/app.rs +++ b/gi/src/pg/app.rs @@ -1,6 +1,6 @@ use log::*; -use radarg_core::radarg_data::Data; -use std::{cell::RefCell, path::PathBuf, rc::Rc}; +use radarg_core::{datapool::Value, radarg_data::Data}; +use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc, sync::Arc}; use crate::{ errors::*, @@ -19,7 +19,10 @@ use crate::{ }; use glow::HasContext; -use super::layout_type::{self, ViewPort}; +use super::{ + layout_type::{self, ViewPort}, + ModuleRefs, +}; use super::{ModulePackage, Programs}; use crate::{font_manager::FontManager, graphics::font::Text}; @@ -61,17 +64,12 @@ impl App { &mut self.context.programs } - pub fn supported_modules(&mut self) -> Vec { - self.program().supported_modules() + pub fn supported_modules<'a>( + &mut self, + data: &'a Value, + ) -> HashMap<&'a Arc, Vec> { + self.program().supported_modules(data) } - - // pub fn load_data( - // &mut self, - // data: &Vec, - // setting: &radarg_core::config::Setting, - // ) -> Result { - // self.program().load_data(data, setting) - // } } pub struct Context { diff --git a/gi/src/pg/mod.rs b/gi/src/pg/mod.rs index 07c14b4..8d6c008 100644 --- a/gi/src/pg/mod.rs +++ b/gi/src/pg/mod.rs @@ -3,8 +3,11 @@ use femtovg::renderer::OpenGl; use femtovg::Canvas; use glow::HasContext; use layout_type::ViewPort; -use modules::PPIModuleConfigComponent; -use radarg_core::radarg_data::Data; +use modules::{PPIModuleConfigComponent, PPIModuleRef}; +use radarg_core::{datapool::Value, radarg_data::Data}; + +use paste::paste; + use relm4::{ gtk, gtk::prelude::{Cast, IsA}, @@ -14,22 +17,22 @@ use relm4::{ pub mod layout_type; mod modules; -use crate::font_manager::FontManager; -use crate::graphics::collections::agg_fast_path::AggFastPath; -use crate::graphics::font::Text; -use crate::graphics::ppi::PPI; -use crate::graphics::threed::Trackball; -use crate::graphics::transforms::plane::PlaneTrans; -use crate::graphics::{AttaWithProgram, AttachWithIO}; -use crate::ui::operation::Operation; -use crate::ui::typ::LayoutAttach; -use crate::utils::resources::GL; -use crate::{errors::*, graphics::Graphics}; +use crate::{ + errors::*, + font_manager::FontManager, + graphics::{ + collections::agg_fast_path::AggFastPath, font::Text, ppi::PPI, + transforms::plane::PlaneTrans, AttaWithProgram, AttachWithIO, Graphics, + }, + ui::{operation::Operation, typ::LayoutAttach}, + utils::resources::GL, +}; + pub use app::{App, Context}; pub use modules::{Module, ModuleCursor, PPIModule, PPIPackage}; -use std::cell::RefCell; -use std::rc::Rc; use std::sync::atomic::AtomicUsize; +use std::{cell::RefCell, collections::HashMap}; +use std::{rc::Rc, sync::Arc}; static MODULE_PACKAGE_ID: AtomicUsize = AtomicUsize::new(0); @@ -77,19 +80,22 @@ impl Programs { PPIModule::new(&self.gl, &mut self._ppi, &mut self._text, &mut self._line) } - pub fn supported_modules(&mut self) -> Vec { - vec![Modules::PPI(self.ppi())] + pub fn ppi_ref(&self) -> PPIModuleRef { + PPIModuleRef::new(&self.gl, &self._ppi, &self._text, &self._line) } - // pub fn load_data( - // &mut self, - // data: &Vec, - // setting: &radarg_core::config::Setting, - // ) -> Result> { - // data.iter() - // .map(|d| self.ppi().load_data(, setting).map(|v| v.into())) - // .collect() - // } + pub fn supported_modules<'a>( + &mut self, + data: &'a Value, + ) -> HashMap<&'a Arc, Vec> { + let mut result = HashMap::new(); + + for (k, d) in data.iter() { + result.insert(d, vec![ModuleRefs::PPI(self.ppi_ref())]); + } + + result + } pub fn draw_modules( &mut self, @@ -108,7 +114,7 @@ impl Programs { } macro_rules! impl_module_package { - ($({$t:ty => $b: tt | $module:tt | $c: ty}),+) => { + ($({$t:ty => $b: tt | $module:tt | $module_ref:tt | $c: ty}),+) => { pub enum Modules<'b, 'gl: 'b>{ $( @@ -116,6 +122,35 @@ macro_rules! impl_module_package { )+ } + pub enum ModuleRefs<'b, 'gl:'b>{ + $( + $b($module_ref<'b,'gl>) + )+ + } + + impl Modules<'_, '_> { + pub fn load_data(&self, data:&Data, setting: &radarg_core::config::Setting) -> Result { + match self { + $( + Modules::$b(m) => { + let cursor = m.load_data(data.into(), setting)?; + Ok(cursor.into()) + } + )+ + } + } + } + + impl ModuleRefs<'_, '_> { + pub fn name(&self) -> &'static str { + match self { + $( + ModuleRefs::$b(m) => m.name(), + )+ + } + } + } + #[derive(Debug)] pub enum _ModulePackage { $( @@ -209,7 +244,7 @@ macro_rules! impl_module_package { } impl_module_package!( - {PPIPackage => PPI | PPIModule | PPIModuleConfigComponent} + {PPIPackage => PPI | PPIModule | PPIModuleRef | PPIModuleConfigComponent} ); impl ModulePackage { diff --git a/gi/src/pg/modules/mod.rs b/gi/src/pg/modules/mod.rs index 82c653b..8e3314c 100644 --- a/gi/src/pg/modules/mod.rs +++ b/gi/src/pg/modules/mod.rs @@ -11,10 +11,13 @@ use crate::{ use femtovg::{renderer::OpenGl, Canvas}; use glow::{HasContext, NativeBuffer, NativeVertexArray}; use radarg_core::config::Setting; -use std::{cell::RefCell, path::Component, rc::Rc}; +use std::{cell::RefCell, path::Component, rc::Rc, sync::Arc}; mod ppi; use crate::errors::*; -pub use ppi::{PPIModule, PPIModuleConfigComponent, PPIModuleConfigComponentWidgets, PPIPackage}; +pub use ppi::{ + PPIModule, PPIModuleConfigComponent, PPIModuleConfigComponentWidgets, PPIModuleRef, PPIPackage, +}; + use relm4::Component as RComponent; use super::{layout_type::ViewPort, SideBarInputMsg}; @@ -95,6 +98,8 @@ pub trait Module: Sized { type Data; type Operation: AttachWithIO; + const NAME: &'static str; + fn render( &mut self, cursor: &mut Self::Cursor, @@ -102,7 +107,7 @@ pub trait Module: Sized { viewport: &ViewPort, ) -> Result<()>; - fn load_data<'dt>(&self, data: &Rc, setting: &Setting) -> Result; + fn load_data<'dt>(&self, data: &Arc, setting: &Setting) -> Result; } pub trait ModuleCursor { diff --git a/gi/src/pg/modules/ppi.rs b/gi/src/pg/modules/ppi.rs index 7a92c9b..231d0f6 100644 --- a/gi/src/pg/modules/ppi.rs +++ b/gi/src/pg/modules/ppi.rs @@ -21,6 +21,7 @@ use glow::HasContext; use std::{ cell::{RefCell, RefMut}, rc::Rc, + sync::Arc, }; use tracker::track; @@ -40,6 +41,125 @@ pub struct PPIModule<'b, 'gl: 'b> { text_program: &'b mut Text, } +pub struct PPIModuleRef<'b, 'gl: 'b> { + gl: &'gl GL, + ppi_program: &'b PPI, + line_program: &'b AggFastPath, + text_program: &'b Text, +} + +impl<'b, 'a: 'b> PPIModuleRef<'b, 'a> { + pub fn new(gl: &'a GL, ppi: &'b PPI, text: &'b Text, line: &'b AggFastPath) -> Self { + let config = PPIConfig::default(); + Self { + gl, + ppi_program: ppi, + text_program: text, + line_program: line, + } + } + + fn bind_ppi_pg( + &self, + attach: &mut Attach, + data: &RadarGridData, + config: &PPIModuleConfig, + ) -> Result<()> { + let (vbo, ebo, len) = self + .ppi_program + .bake(&self.gl, data, &config.to_ppi_config())?; + attach.bind_data(&vbo, ebo.as_ref(), len, glow::DYNAMIC_DRAW); + Ok(()) + } + + fn bind_line_pg( + &self, + attach: &mut Attach, + data: &RadarGridData, + config: &PPIModuleConfig, + ) -> Result<()> { + let raw_config = config.to_line_config(); + + // Will be changed in the future + let outskirt = 10.0; + + let mut paths = vec![]; + + let range_line_num = config.range_line_num; + let r = outskirt / range_line_num as f32; + let seg_num = 200; + let angle = 2f32 * f32::consts::PI / seg_num as f32; + + for range in 1..=range_line_num { + // Create the path + let mut path = Path::new(true); + let r = r * range as f32; + // Draw the circle + for seg in 0..seg_num { + let angle = angle * seg as f32; + let x = (angle.cos() * r) as f32; + let y = (angle.sin() * r) as f32; + path.push([x, y, 0.01]); + } + path.finish(); + paths.push(path); + } + + let ath_lin_num = config.ath_line_num; + + let a = 2.0 * f32::consts::PI / ath_lin_num as f32; + for _a in 0..=ath_lin_num { + let mut path = Path::new(false); + let x = (a * _a as f32).cos() * outskirt; + let y = (a * _a as f32).sin() * outskirt; + path.push([0.0, 0.0, 0.01]); + path.push([x, y, 0.01]); + path.finish(); + paths.push(path); + } + + if config.vertical_axis { + let mut path = Path::new(false); + path.push([0.0, 0.0, 0.0]); + path.push([0.0, 0.0, outskirt]); + path.finish(); + paths.push(path); + } + + let (vbo, ebo, len) = self.line_program.bake(&self.gl, &paths, &raw_config)?; + attach.bind_data(&vbo, ebo.as_ref(), len, glow::STATIC_DRAW); + Ok(()) + } + + fn bind_tick( + &self, + attach: &mut Attach, + data: &RadarGridData, + config: &PPIModuleConfig, + ) -> Result<()> { + let font_style = config.to_font_config(); + + match font_style { + FontConfig::Textline(line_style, font_style) => { + let new_text = TextLine::new("Hello,World", Some(font_style), None); + let position_text = + PositionText::new(new_text, [0.0, 0.0, 0.0], Anchor::BottomCenter); + let text_pg_config = config.to_font_config(); + let (vbo, ebo, len) = + self.text_program + .bake(&self.gl, &position_text, &text_pg_config)?; + attach.bind_data(&vbo, ebo.as_ref(), len, glow::STATIC_DRAW); + } + } + + Ok(()) + } + + pub fn name(&self) -> &'static str { + "PPI" + } +} + impl<'b, 'a: 'b> PPIModule<'b, 'a> { pub fn new( gl: &'a GL, @@ -158,6 +278,8 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> { type Data = RadarGridData; type Operation = PlaneTrans; + const NAME: &'static str = "PPI"; + fn render<'dt>( &mut self, cursor: &mut Self::Cursor, @@ -238,7 +360,7 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> { Ok(()) } - fn load_data<'dt>(&self, data: &Rc, setting: &Setting) -> Result { + fn load_data<'dt>(&self, data: &Arc, setting: &Setting) -> Result { // Init the memory let (vao, vbo, ebo) = self.ppi_program.init(&self.gl); let mut ppi_attach = Attach::new(self.gl.clone(), vao, vbo, ebo, None); @@ -246,12 +368,17 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> { // Get the data info let (r, a, t, max_layer, unvalid) = self.ppi_program.data_info(&data)?; + println!("name: {}", data.info.value_name); + // Find the color map let cmap = setting.find(&t); // Check if the color map is valid if cmap.is_none() { - return Err(Error::InvalidDataType); + return Err(Error::InvalidDataType(format!( + "{}'s colormap is not found", + data.info.value_name + ))); } let cmap = cmap.unwrap(); @@ -294,7 +421,7 @@ pub struct PPIPackage { ppi_attach: Attach, line_attach: Attach, tick_attach: Attach, - data: Rc, + data: Arc, } impl PPIPackage { @@ -303,7 +430,7 @@ impl PPIPackage { ppi_attach: Attach, line_attach: Attach, tick_attach: Attach, - data: Rc, + data: Arc, ) -> Self { Self { draw_helper: true, @@ -415,35 +542,71 @@ impl SimpleComponent for PPIModuleConfigComponent { type Output = OutputMsg; view! { - adw::PreferencesGroup { - set_title:"PPI Config", - set_hexpand:true, - set_vexpand:true, - adw::SwitchRow { - set_title:"Ticks", - set_active: init_config.ticks, - connect_active_notify[sender, config_ref] => move |this| { - let active = this.is_active(); - config_ref.borrow_mut().set_ticks(active); - } + adw::PreferencesPage { + adw::PreferencesGroup { + set_title:"PPI Config", + set_hexpand:true, + adw::SwitchRow { + set_title:"Ticks", + set_active: init_config.ticks, + connect_active_notify[sender, config_ref] => move |this| { + let active = this.is_active(); + config_ref.borrow_mut().set_ticks(active); + sender.output(OutputMsg::Refresh); + } + }, + adw::SwitchRow{ + set_title:"Three D", + set_active: init_config.is_three_d, + connect_active_notify[sender, config_ref] => move |this| { + let active = this.is_active(); + config_ref.borrow_mut().set_is_three_d(active); + sender.output(OutputMsg::Refresh); + } + }, + adw::SpinRow { + set_title: "Layer", + set_digits: 0, + set_numeric: true, + set_snap_to_ticks: true, + #[wrap(Some)] + set_adjustment=>k::Adjustment::new( + init_config.layer as f64 + 1.0, + 1.0, + init_config.max_layer as f64, + 1.0, + 1.0, + 1.0 + ), + connect_value_notify[sender, config_ref] => move |this| { + let layer = this.value() as usize - 1; + config_ref.borrow_mut().set_layer(layer); + sender.output(OutputMsg::Refresh); + }, + }, }, - adw::SpinRow { - set_title: "Layer", - set_value: init_config.layer as f64, - set_range: (0.0, init_config.max_layer as f64), - set_digits: 0, - set_numeric: true, - set_climb_rate: 1.0, - connect_value_notify[sender, config_ref] => move |this| { - let layer = this.value() as usize; - config_ref.borrow_mut().set_layer(layer); - } - }, - gtk::Button { - set_label: "Refresh", - connect_clicked[sender] => move |_| { - sender.output(OutputMsg::Refresh); - } + adw::PreferencesGroup { + set_title:"Show Config", + set_hexpand:true, + adw::PreferencesRow { + set_title:"Color Line", + #[wrap(Some)] + set_child=>k::Box{ + gtk::ColorDialogButton { + set_dialog=>k::ColorDialog {}, + set_rgba: >k::gdk::RGBA::new(init_config.line_color[0], init_config.line_color[1],init_config.line_color[2],init_config.line_color[3]), + connect_rgba_notify[sender, config_ref] => move |this| { + let rgba = this.rgba(); + let color = [rgba.red(), rgba.green(), rgba.blue(), rgba.alpha()]; + config_ref.borrow_mut().set_line_color(color); + sender.output(OutputMsg::Refresh); + } + } + + } + + }, + } } diff --git a/gi/src/ui/io.rs b/gi/src/ui/io.rs index 148aeb6..f6e936f 100644 --- a/gi/src/ui/io.rs +++ b/gi/src/ui/io.rs @@ -25,3 +25,9 @@ pub struct IO { pub mouse: MouseIO, pub keyboard: KeyboardIO, } + +impl IO { + pub fn reset(&mut self) { + self.mouse.wheel_delta = 0.0; + } +} diff --git a/loaders/etws_loader/src/error.rs b/loaders/etws_loader/src/error.rs index ed2f9b5..56759e6 100644 --- a/loaders/etws_loader/src/error.rs +++ b/loaders/etws_loader/src/error.rs @@ -1,3 +1,4 @@ +use nom::error::Error; use thiserror::Error; #[derive(Debug, Error)] pub enum ETWSError { @@ -6,9 +7,17 @@ pub enum ETWSError { #[from] source: std::io::Error, }, - #[error("Format Error")] + #[error("Unsupported Format")] FormatError { #[from] source: anyhow::Error, }, + #[error("Binary Error")] + NomError, +} + +impl<'a> From>> for ETWSError { + fn from(value: nom::Err>) -> Self { + ETWSError::NomError + } } diff --git a/loaders/etws_loader/src/lib.rs b/loaders/etws_loader/src/lib.rs index 178e685..8cadf98 100644 --- a/loaders/etws_loader/src/lib.rs +++ b/loaders/etws_loader/src/lib.rs @@ -168,7 +168,7 @@ impl DataLoaderPlugin for ETWSLoader { { "DBZ" | "CR" | "FR" | "R" => DBZ}, { "VIL" => VIL}, { "EB" => EB}, - { "V" => V}, + { "V" | "VEL" => V}, { "ZDR" => ZDR}, { "PHIDP" => PHIDP}, { "KDP" => KDP}, diff --git a/loaders/etws_loader/src/raw.rs b/loaders/etws_loader/src/raw.rs index ec6e5d0..d7978c6 100644 --- a/loaders/etws_loader/src/raw.rs +++ b/loaders/etws_loader/src/raw.rs @@ -1,3 +1,4 @@ +use crate::error::ETWSError; use abi_stable::std_types::vec; use bytemuck::cast_slice; use nom::{ @@ -244,34 +245,84 @@ fn parse_sub_pulse_config(input: &[u8]) -> IResult<&[u8], SubPulseConfig> { Ok((input, sub_pulse_config)) } -pub fn parse_raw_data>(path: P) -> io::Result { +pub fn parse_raw_data>(path: P) -> Result { let path = path.as_ref(); + if path.extension().is_none() { + if path.is_file() { + let mut file = File::open(path)?; + let mut buf = Vec::new(); + file.read_to_end(&mut buf).unwrap(); + if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" { + return get_radar_data(buf); + } else { + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); + } + } else { + return Err(ETWSError::IOError { + source: io::Error::new(io::ErrorKind::NotFound, "File not found"), + }); + } + } + if path.extension().unwrap() == "zip" { let file = File::open(path).unwrap(); let mut archive = ZipArchive::new(file).unwrap(); let mut file = archive.by_index(0).unwrap(); let mut buf = Vec::new(); - file.read_to_end(&mut buf).unwrap(); + file.read_to_end(&mut buf)?; + if buf.len() < 4 { + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); + } if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" { return get_radar_data(buf); } else { - panic!("Invalid file format"); + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); + } + } else if path.extension().unwrap() == ".gz" { + let file = File::open(path)?; + let mut archive = flate2::read::GzDecoder::new(file); + let mut buf = Vec::new(); + archive.read_to_end(&mut buf)?; + if buf.len() < 4 { + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); + } + if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" { + return get_radar_data(buf); + } else { + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); } } else { - let mut file = File::open(path).unwrap(); + let mut file = File::open(path)?; let mut buf = Vec::new(); - file.read_to_end(&mut buf).unwrap(); + file.read_to_end(&mut buf)?; + if buf.len() < 4 { + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); + } if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" { return get_radar_data(buf); } else { - panic!("Invalid file format"); + return Err(ETWSError::FormatError { + source: anyhow::anyhow!("Invalid file format"), + }); } } } -fn get_radar_data(data: Vec) -> io::Result { +fn get_radar_data(data: Vec) -> Result { let total_length = data.len() as u64; // 使用 Cursor 来处理 Vec let mut cursor = Cursor::new(data); @@ -279,24 +330,24 @@ fn get_radar_data(data: Vec) -> io::Result { // 读取 GENERIC_HEADER let mut buffer = vec![0u8; 32]; cursor.read_exact(&mut buffer)?; - let (_, generic_header) = parse_generic_header(&buffer).unwrap(); + let (_, generic_header) = parse_generic_header(&buffer)?; // 读取 SITE_CONFIG let mut buffer = vec![0u8; 128]; cursor.read_exact(&mut buffer)?; - let (_, site_config) = parse_site_config(&buffer).unwrap(); + let (_, site_config) = parse_site_config(&buffer)?; // 读取 TASK_CONFIG let mut buffer = vec![0u8; 256]; cursor.read_exact(&mut buffer)?; - let (_, task_config) = parse_task_config(&buffer).unwrap(); + let (_, task_config) = parse_task_config(&buffer)?; // 读取 SCAN_CONFIG let mut scan_configs = Vec::new(); for _ in 0..task_config.scan_beam_number { let mut buffer = vec![0u8; 640]; cursor.read_exact(&mut buffer)?; - let (_, scan_config) = parse_scan_config(&buffer).unwrap(); + let (_, scan_config) = parse_scan_config(&buffer)?; scan_configs.push(scan_config); } @@ -305,7 +356,7 @@ fn get_radar_data(data: Vec) -> io::Result { for _ in 0..task_config.cut_number { let mut buffer = vec![0u8; 256]; cursor.read_exact(&mut buffer)?; - let (_, beam_config) = parse_beam_config(&buffer).unwrap(); + let (_, beam_config) = parse_beam_config(&buffer)?; beam_configs.push(beam_config); } @@ -454,19 +505,22 @@ fn parse_final_data( all_length: u64, cut_number: usize, mut cursor: Cursor>, -) -> io::Result<( - HashMap<&'static str, Vec>, - Vec, - Vec, - Vec, -)> { +) -> Result< + ( + HashMap<&'static str, Vec>, + Vec, + Vec, + Vec, + ), + ETWSError, +> { let position = cursor.position(); let mut radial_buffer = vec![0u8; 128]; let mut header_buffer = vec![0u8; 32]; cursor.read_exact(&mut radial_buffer)?; // First Block - let (_, radial_data) = parse_radial_data(&radial_buffer).unwrap(); + let (_, radial_data) = parse_radial_data(&radial_buffer)?; // Radial_number: I don't know why not use it. // let radial_number = radial_data.radial_number as usize; @@ -480,7 +534,7 @@ fn parse_final_data( for idx in 0..type_number { cursor.read_exact(&mut header_buffer)?; - let (_, header) = parse_type_header(&header_buffer).unwrap(); + let (_, header) = parse_type_header(&header_buffer)?; let first_beam_block = beam_block_exact(&mut cursor, &header)?; let first_beam = single_beam_block(&first_beam_block, header.bin_length as usize)?; gate_len[idx] = first_beam.len(); @@ -516,31 +570,32 @@ fn parse_final_data( for e in 0..cut_number { for a in 0..azm_number { cursor.read_exact(&mut radial_buffer)?; - let (_, radial_data) = parse_radial_data(&radial_buffer).unwrap(); + let (_, radial_data) = parse_radial_data(&radial_buffer)?; els[e] = radial_data.elevation as f64; azs[a] = radial_data.azimuth as f64; let type_number = radial_data.moment_number as usize; for typ in 0..type_number { cursor.read_exact(&mut header_buffer)?; - let (_, header) = parse_type_header(&header_buffer).unwrap(); + let (_, header) = parse_type_header(&header_buffer)?; let beam_block = beam_block_exact(&mut cursor, &header)?; let mut beam = single_beam_block(&beam_block, header.bin_length as usize)?; beam.iter_mut() .for_each(|v| *v = (*v - header.offset as f64) / header.scale as f64); - let typ_name = types.get(typ).unwrap(); + if let Some(typ_name) = types.get(typ) { + if typ_name == &"Unknown" { + continue; + } + let e = radial_data.elevation_number as usize - 1; - if typ_name == &"Unknown" { + datas.get_mut(typ_name).unwrap()[e * (azm_number * gate_len[typ]) + + a * gate_len[typ] + ..e * (azm_number * gate_len[typ]) + (a + 1) * gate_len[typ]] + .copy_from_slice(&beam); + } else { continue; } - - let e = radial_data.elevation_number as usize - 1; - - datas.get_mut(typ_name).unwrap()[e * (azm_number * gate_len[typ]) - + a * gate_len[typ] - ..e * (azm_number * gate_len[typ]) + (a + 1) * gate_len[typ]] - .copy_from_slice(&beam); } } } diff --git a/radar-g/src/components/app.rs b/radar-g/src/components/app.rs index 1496501..250cbd7 100644 --- a/radar-g/src/components/app.rs +++ b/radar-g/src/components/app.rs @@ -7,12 +7,13 @@ use super::{ sidebar::{SideBarInputMsg, SideBarModel}, ControlPanelOutputMsg, TimelineMsg, }; -use crate::datapool::{DataPool, Value}; use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete}; use crate::widgets::{DynamicCol, ElementType}; -use crate::{plugin_system::init_plugin, widgets::render::Layer, PLUGIN_MANAGER}; +use crate::{widgets::render::Layer, PLUGIN_MANAGER}; use chrono::{prelude::*, Duration}; +use gtk::Widget; use once_cell::sync::Lazy; +use radarg_core::datapool::{DataPool, Value}; use radarg_core::Data; use relm4::{ actions::{AccelsPlus, RelmAction, RelmActionGroup}, @@ -61,15 +62,16 @@ pub enum FileIOType { pub enum AppMsg { Refresh, FileIO { typ: FileIOType }, - OpenDialog, + OpenDialog { widget: Widget }, + CloseDialog, + OpenAlert { body: String, title: String }, + CloseAlert, CloseRequest, Close, OpenFileDialog, } #[tracker::track] pub struct AppModel { - waiting_for: Option>, - // Components #[do_not_track] open_dialog: Controller, @@ -81,12 +83,6 @@ pub struct AppModel { sidebar: Controller, #[do_not_track] setting: Controller, - - // Data - selected_layer: Vec, - #[do_not_track] - layers: Share>, - // File Pool #[do_not_track] file_pool: Share, @@ -184,16 +180,10 @@ impl Component for AppModel { set_title: "Dialog", set_presentation_mode: adw::DialogPresentationMode::Floating, set_follows_content_size: true, - set_can_close: true, + set_can_close: true + }, + alert_dialog = adw::AlertDialog{ - #[wrap(Some)] - set_child=>k::Box{ - set_height_request: 200, - set_width_request: 200, - gtk::Label{ - set_text:"Dialog", - }, - } } } @@ -220,21 +210,14 @@ impl Component for AppModel { root: Self::Root, sender: ComponentSender, ) -> ComponentParts { - let layers = Rc::new(RefCell::new(vec![])); - // let control = ControlPanelModel::builder().launch(layers.clone()).forward( - // sender.input_sender(), - // |msg| match msg { - // ControlPanelOutputMsg::OpenFile((key, time)) => AppMsg::Close, - // }, - // ); - - let data_pool = DataPool::new(10); + let data_pool = DataPool::new(&PLUGIN_MANAGER, 10); let data_pool = Rc::new(RefCell::new(data_pool)); // SideBar Component let sidebar = SideBarModel::builder() .launch(None) .forward(sender.input_sender(), |msg| match msg { + SideBarOutputMsg::Dialog(widget) => AppMsg::OpenDialog { widget }, SideBarOutputMsg::QueueDraw => AppMsg::Refresh, _ => AppMsg::Close, }); @@ -242,7 +225,7 @@ impl Component for AppModel { let sidebar_sender = sidebar.sender(); // Monitor Component - let render = MonitorModel::builder().launch(layers.clone()).forward( + let render = MonitorModel::builder().launch(()).forward( sender.input_sender(), clone!( #[strong] @@ -250,11 +233,22 @@ impl Component for AppModel { move |model_message| match model_message { MonitorOutputMsg::Attached(new_module) => { sidebar_sender.emit(SideBarInputMsg::Package(new_module)); - AppMsg::OpenDialog - // AppMsg::Close + AppMsg::CloseDialog + } + MonitorOutputMsg::Dialog(widget) => { + AppMsg::OpenDialog { widget } + } + MonitorOutputMsg::DialogClose => { + AppMsg::CloseDialog + } + MonitorOutputMsg::Alert(content, title) => { + AppMsg::OpenAlert { + body: content, + title, + } } MonitorOutputMsg::Fc => { - AppMsg::OpenDialog + AppMsg::Close } _ => AppMsg::Close, } @@ -287,7 +281,10 @@ impl Component for AppModel { } Err(e) => { error!("Failed to load data, cause: {:?}", e); - AppMsg::Close + AppMsg::OpenAlert { + body: format!("Failed to load data, cause: {:?}", e), + title: "Error".to_string(), + } } } } @@ -298,15 +295,12 @@ impl Component for AppModel { }; let model = AppModel { - waiting_for: None, render, setting, open_dialog: dialog, - selected_layer: vec![], sidebar, file_pool: data_pool, // control, - layers, tracker: 0, }; @@ -315,7 +309,6 @@ impl Component for AppModel { let widgets = view_output!(); let mut group = RelmActionGroup::::new(); relm4::main_application().set_accelerators_for_action::(&["O"]); - // register_layer_actions(&widgets.main_window, sender.clone()); let action: RelmAction = { RelmAction::new_stateless(move |_| { sender.input(AppMsg::OpenFileDialog); @@ -343,9 +336,24 @@ impl Component for AppModel { AppMsg::OpenFileDialog => { self.open_dialog.emit(OpenDialogMsg::Open); } - AppMsg::OpenDialog => { + AppMsg::OpenDialog { widget } => { + widgets.dialog.set_child(Some(&widget)); widgets.dialog.present(Some(root)); } + AppMsg::CloseDialog => { + widgets.dialog.close(); + } + AppMsg::OpenAlert { body, title } => { + widgets.alert_dialog.set_body(&body); + widgets.alert_dialog.set_title(&title); + widgets.alert_dialog.add_responses(&[("Close", "Close")]); + + widgets + .alert_dialog + .set_response_appearance("Close", adw::ResponseAppearance::Destructive); + + widgets.alert_dialog.present(Some(root)); + } AppMsg::FileIO { typ: FileIOType::Open(data), } => self.render.emit(MonitorInputMsg::PushData(data)), diff --git a/radar-g/src/components/control_panel/control_panel.rs b/radar-g/src/components/control_panel/control_panel.rs index a58716a..b2d02fd 100644 --- a/radar-g/src/components/control_panel/control_panel.rs +++ b/radar-g/src/components/control_panel/control_panel.rs @@ -1,6 +1,5 @@ use super::messages::*; use super::thumbnail::{ImgItem, TypedListView}; -use crate::plugin_system::init_plugin; use crate::predefined::color_mapper::BoundaryNorm; use crate::widgets::render::Layer; use crate::widgets::timeline::{Selection, TimeLine}; diff --git a/radar-g/src/components/monitor/dialog_widget.rs b/radar-g/src/components/monitor/dialog_widget.rs new file mode 100644 index 0000000..6c34e24 --- /dev/null +++ b/radar-g/src/components/monitor/dialog_widget.rs @@ -0,0 +1,136 @@ +use epoxy::S; +use gi::pg::ModuleRefs; +use gtk::Widget; +use radarg_core::Data; +use std::collections::HashMap; + +use relm4::{ + adw::{self, prelude::*}, + factory::FactoryVecDeque, + gtk::{self, prelude::*}, + prelude::*, + view, ComponentParts, ComponentSender, SimpleComponent, +}; + +use crate::widgets; + +#[derive(Debug)] +pub struct ItemInfo { + pub module_name: &'static str, + pub module_icon: &'static str, +} + +#[derive(Debug)] +pub enum DialogOutput { + Cancel, + Open(usize), +} +pub struct Dialog {} + +#[relm4::component(pub)] +impl SimpleComponent for Dialog { + type Widgets = DialogWidgets; + type Init = HashMap<(usize, String), Vec>; + type Input = (); + type Output = DialogOutput; + + view! { + root=adw::BreakpointBin { + set_height_request:600, + set_width_request:800, + + #[wrap(Some)] + set_child=&adw::ToolbarView{ + set_hexpand:true, + set_vexpand:true, + add_top_bar=&adw::HeaderBar{ + set_hexpand:true, + #[wrap(Some)] + set_title_widget=>k::Label{ + set_label: "Header", + }, + }, + #[wrap(Some)] + set_content=&adw::Clamp{ + set_hexpand:true, + #[wrap(Some)] + #[name(content)] + set_child=>k::Box{ + set_orientation: gtk::Orientation::Vertical, + set_hexpand:true, + set_spacing: 10, + + + }, + } + } + + } + + } + + fn init( + init: Self::Init, + root: Self::Root, + sender: relm4::ComponentSender, + ) -> relm4::ComponentParts { + let widgets = view_output!(); + + if init.len() > 1 { + view! { + label=gtk::Label { + set_label: "The file you opened contains multiple data blocks; please select one to proceed to the next step.", + add_css_class: "h3", + } + } + + widgets.content.append(&label); + } + + for ((k, name), v) in init.iter() { + view! { + tile=gtk::Expander{ + set_label: Some(&format!("Data {}: {}", k, name)), + set_expanded: true, + set_hexpand: true, + #[name(content)] + #[wrap(Some)] + set_child=>k::FlowBox{ + set_homogeneous: true, + set_column_spacing: 10, + set_row_spacing: 10, + } + }, + + } + let data_id = *k; + + for values in v.iter() { + view! { + item=gtk::Button { + set_icon_name: &values.module_icon, + connect_clicked[sender] => move |_| { + sender.output(DialogOutput::Open(data_id)); + + } + } + } + content.append(&item); + } + + widgets.content.append(&tile); + } + + let model = Self {}; + + // let widgets = model.sequence.widget().clone(); + // let contour = model.counter.widget().clone(); + + ComponentParts { + model: model, + widgets, + } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) {} +} diff --git a/radar-g/src/components/monitor/messages.rs b/radar-g/src/components/monitor/messages.rs index 178603e..500f19b 100644 --- a/radar-g/src/components/monitor/messages.rs +++ b/radar-g/src/components/monitor/messages.rs @@ -1,10 +1,12 @@ -use crate::datapool::Value; -use gi::pg::ModulePackage; +use gi::pg::{ModulePackage, Modules}; +use gtk::Widget; +use radarg_core::datapool::Value; use radarg_core::Data; -use std::{cell::RefCell, fmt::Debug, rc::Rc}; +use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; pub enum MonitorInputMsg { PushData(Value), + Draw(Arc), QueueDraw, None, } @@ -13,6 +15,9 @@ impl Debug for MonitorInputMsg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MonitorInputMsg::QueueDraw => write!(f, "MonitorInputMsg::QueueDraw"), + MonitorInputMsg::Draw(data) => { + write!(f, "MonitorInputMsg::Draw({:?})", data) + } MonitorInputMsg::PushData(data) => write!(f, "MonitorInputMsg::PushData({:?})", data), MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"), } @@ -22,6 +27,9 @@ impl Debug for MonitorInputMsg { #[derive(Debug)] pub enum MonitorOutputMsg { Attached(Rc>), + Dialog(Widget), + DialogClose, + Alert(String, String), Fc, } diff --git a/radar-g/src/components/monitor/mod.rs b/radar-g/src/components/monitor/mod.rs index 6f38e95..fc39b13 100644 --- a/radar-g/src/components/monitor/mod.rs +++ b/radar-g/src/components/monitor/mod.rs @@ -1,3 +1,4 @@ +mod dialog_widget; pub mod messages; pub mod monitor; diff --git a/radar-g/src/components/monitor/monitor.rs b/radar-g/src/components/monitor/monitor.rs index 9d6eb16..ddd824d 100644 --- a/radar-g/src/components/monitor/monitor.rs +++ b/radar-g/src/components/monitor/monitor.rs @@ -1,3 +1,4 @@ +use super::dialog_widget::{Dialog, DialogOutput, ItemInfo}; use super::messages::{MonitorInputMsg, MonitorOutputMsg}; use crate::predefined::color_mapper::BoundaryNorm; use crate::widgets::render::RenderConfig; @@ -8,9 +9,10 @@ use crate::{ }; use geo::k_nearest_concave_hull; use gi::graphics::transforms::plane::PlaneTrans; -use gi::pg::ModulePackage; +use gi::pg::{Module, ModulePackage}; use gi::ui::operation::Operation; use gtk::glib::clone; + use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -21,6 +23,7 @@ use adw::prelude::*; use femtovg::ImageId; use fns::debounce; use gi::ui::typ::MainLoadAttach; +use radarg_core::Data; use relm4::{component::Component, *}; use slippy_map_tiles::Tile; use tokio::task; @@ -49,7 +52,7 @@ pub struct MonitorWidgets { impl Component for MonitorModel { type CommandOutput = MonitorCommand; type Input = MonitorInputMsg; - type Init = Rc>>; + type Init = (); type Output = MonitorOutputMsg; view! { @@ -95,24 +98,60 @@ impl Component for MonitorModel { self.reset(); match message { MonitorInputMsg::PushData(data) => { - sender.output(MonitorOutputMsg::Fc); - // widgets - // .renderer - // .get_gi(|gi| match gi.load_data(&data, &SETTING) { - // Ok(package) => { - // info!("data load success!"); - // let rc_package = Rc::new(RefCell::new(package)); - // self.set_module_packages(vec![rc_package.clone()]); - // sender.output(MonitorOutputMsg::Attached(rc_package)); - // } - // Err(err) => { - // error!("Load Error, cause of {}", err); - // } - // }) + widgets.renderer.get_gi(|gi| { + let supported_modules = gi.supported_modules(&data); + + let mut result = HashMap::new(); + for (data, modules) in supported_modules { + let mut module_packages = vec![]; + for module in modules { + module_packages.push(ItemInfo { + module_name: module.name(), + module_icon: "plus", + }); + } + result.insert((data.id, data.description.clone()), module_packages); + } + + let dialog = Dialog::builder().launch(result).forward( + 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()) + } + _ => MonitorInputMsg::None, + }, + ); + + let widget = dialog.widget().to_owned().upcast(); + + sender.output(MonitorOutputMsg::Dialog(widget)); + }); } MonitorInputMsg::QueueDraw => { widgets.renderer.queue_draw(); } + 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::None => {} _ => {} } diff --git a/radar-g/src/components/sidebar/sidebar.rs b/radar-g/src/components/sidebar/sidebar.rs index 2df6abd..e407a33 100644 --- a/radar-g/src/components/sidebar/sidebar.rs +++ b/radar-g/src/components/sidebar/sidebar.rs @@ -4,12 +4,13 @@ use chrono::{DateTime, Utc}; use gi::pg::SideBarInputMsg; use gi::pg::{Components, ModulePackage}; use glib_macros::clone; -use gtk::glib; use gtk::prelude::WidgetExt; use gtk::prelude::*; +use gtk::{glib, Widget}; use relm4::actions::{AccelsPlus, RelmAction}; use relm4::RelmRemoveAllExt; use relm4::{ + adw::{self, prelude::*}, binding::{Binding, U8Binding}, factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque}, gtk::gio, @@ -18,7 +19,7 @@ use relm4::{ column::TypedColumnView, list::{RelmListItem, TypedListView}, }, - RelmObjectExt, + view, RelmObjectExt, }; use std::{cell::RefCell, collections::HashMap, rc::Rc}; @@ -36,6 +37,7 @@ pub struct SideBarModel { #[derive(Debug)] pub enum SideBarOutputMsg { + Dialog(Widget), QueueDraw, } @@ -54,7 +56,46 @@ impl Component for SideBarModel { set_margin_all: 5, #[name="container"] - gtk::Box {} + gtk::Box { + gtk::Button { + set_hexpand:true, + set_label: "Refresh", + connect_clicked[sender] => move |_| { + + 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())); + } + } + } }, } diff --git a/radar-g/src/datapool/mod.rs b/radar-g/src/datapool/mod.rs deleted file mode 100644 index cb8c8d8..0000000 --- a/radar-g/src/datapool/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::PLUGIN_MANAGER; -use quick_cache::sync::Cache; -use radarg_core::errors::DataError; -use radarg_core::Data; -use std::fmt::Display; -use std::ops::Deref; -use std::path::PathBuf; -use std::sync::Arc; - -#[derive(Clone, Debug)] -pub struct Value(Arc>); - -impl Value { - pub fn new(data: Vec) -> Self { - Self(Arc::new(data)) - } -} - -impl Deref for Value { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for data in self.0.iter() { - writeln!(f, "{}", data)?; - } - - Ok(()) - } -} - -pub struct DataPool { - pool: Cache>, -} - -impl DataPool { - pub fn new(cap: usize) -> Self { - Self { - pool: Cache::new(cap), - } - } - - pub fn get_or_load(&self, path: impl Into) -> Result, DataError> { - let path = path.into(); - self.pool.get_or_insert_with(&path, || { - PLUGIN_MANAGER.try_load_data(&path).map(Value::new) - }) - } -} diff --git a/radar-g/src/main.rs b/radar-g/src/main.rs index e349b58..3be5ee4 100644 --- a/radar-g/src/main.rs +++ b/radar-g/src/main.rs @@ -3,15 +3,13 @@ #[macro_use] extern crate lazy_static; use gtk::{gio, prelude::SettingsExt}; -use plugin_system::{init_plugin, PluginManager}; +use radarg_core::plugin_system::{init_plugin, PluginManager}; use std::convert::TryInto; use std::sync::RwLock; use std::{ptr, sync::Mutex}; use tokio::runtime::Runtime; mod actions; mod components; -mod datapool; -mod plugin_system; use crate::components::app::AppMsg; use components::app::AppModel; use gi::{App as GI, Helper, GL}; diff --git a/radar-g/src/widgets/render/imp.rs b/radar-g/src/widgets/render/imp.rs index 0835e17..f8a9ac8 100644 --- a/radar-g/src/widgets/render/imp.rs +++ b/radar-g/src/widgets/render/imp.rs @@ -183,6 +183,8 @@ impl GLAreaImpl for Render { viewport.unbind(); + self.io.borrow_mut().reset(); + glib::Propagation::Proceed } } diff --git a/radar-g/src/widgets/render/mod.rs b/radar-g/src/widgets/render/mod.rs index 79163af..8f3dbd5 100644 --- a/radar-g/src/widgets/render/mod.rs +++ b/radar-g/src/widgets/render/mod.rs @@ -63,9 +63,12 @@ impl Render { this, move |_, x, y| { this.imp().set_io(|io| { - io.mouse.wheel_delta = y as f32; + io.mouse.wheel_delta = -y as f32; }); - this.queue_draw(); + + if y != 0.0 { + this.queue_draw(); + } glib::Propagation::Proceed } )); @@ -136,7 +139,7 @@ impl Render { f(&mut cfg); } - pub fn get_gi(&self, mut f: F) { + pub fn get_gi(&self, mut f: F) { let mut gi = self.imp().gi.borrow_mut(); f(&mut gi.as_mut().unwrap()); } diff --git a/radarg_core/Cargo.toml b/radarg_core/Cargo.toml index a8678ca..29e3b85 100644 --- a/radarg_core/Cargo.toml +++ b/radarg_core/Cargo.toml @@ -15,6 +15,9 @@ dirs = "5.0.1" num-traits = "0.2.19" serde = { version = "1.0.209", features = ["derive"] } relm4 = { version = "0.9.0", features = ["libadwaita"] } +abi_stable = "0.11.3" +core_extensions = "1.5.3" +quick_cache = "0.6.5" [dependencies.radarg_plugin_interface] version = "0.1" diff --git a/radarg_core/src/datapool/mod.rs b/radarg_core/src/datapool/mod.rs new file mode 100644 index 0000000..3f55261 --- /dev/null +++ b/radarg_core/src/datapool/mod.rs @@ -0,0 +1,76 @@ +use crate::errors::DataError; +use crate::plugin_system::PluginManager; +use crate::Data; +use quick_cache::sync::Cache; +use std::collections::HashMap; +use std::fmt::Display; +use std::ops::Deref; +use std::path::PathBuf; +use std::sync::Arc; + +#[derive(Clone, Debug)] +pub struct Value(Arc>>); + +impl Value { + pub fn new(data: Vec) -> Self { + let mut hashmap = HashMap::new(); + for data in data { + hashmap.insert(data.id, Arc::new(data)); + } + + Self(Arc::new(hashmap)) + } + + pub fn get(&self, key: usize) -> Option<&Arc> { + self.0.get(&key) + } + + pub fn iter(&self) -> std::collections::hash_map::Iter<'_, usize, Arc> { + self.0.iter() + } +} + +impl Value { + pub fn len(&self) -> usize { + self.0.len() + } +} + +impl Deref for Value { + type Target = HashMap>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for data in self.0.iter() { + writeln!(f, "{:?}", data)?; + } + + Ok(()) + } +} + +pub struct DataPool { + plugin_manager: &'static PluginManager, + pool: Cache>, +} + +impl DataPool { + pub fn new(plugin_manager: &'static PluginManager, cap: usize) -> Self { + Self { + plugin_manager, + pool: Cache::new(cap), + } + } + + pub fn get_or_load(&self, path: impl Into) -> Result, DataError> { + let path = path.into(); + self.pool.get_or_insert_with(&path, || { + self.plugin_manager.try_load_data(&path).map(Value::new) + }) + } +} diff --git a/radarg_core/src/lib.rs b/radarg_core/src/lib.rs index 79c879d..f7e1da4 100644 --- a/radarg_core/src/lib.rs +++ b/radarg_core/src/lib.rs @@ -2,6 +2,8 @@ pub mod config; pub mod errors; pub mod radarg_data; use rust_embed::RustEmbed; +pub mod datapool; +pub mod plugin_system; pub mod utils; pub mod widget_interface; diff --git a/radar-g/src/plugin_system/mod.rs b/radarg_core/src/plugin_system/mod.rs similarity index 98% rename from radar-g/src/plugin_system/mod.rs rename to radarg_core/src/plugin_system/mod.rs index c7b7efe..481c7ea 100644 --- a/radar-g/src/plugin_system/mod.rs +++ b/radarg_core/src/plugin_system/mod.rs @@ -1,3 +1,5 @@ +use crate::errors::DataError; +use crate::Data; use abi_stable::{ external_types::crossbeam_channel::{self, RReceiver, RSender}, library::{lib_header_from_path, LibraryError, LibrarySuffix, RawLibrary}, @@ -5,8 +7,6 @@ use abi_stable::{ std_types::{RBox, RErr, ROk, RResult, RSome, RStr, RString, RVec}, }; use core_extensions::*; -use radarg_core::errors::DataError; -use radarg_core::Data; use radarg_plugin_interface::{DataLoaderPlugin, DataLoaderPlugin_TO, PluginId, PluginMod_Ref}; use std::{ collections::{HashMap, VecDeque}, diff --git a/radarg_core/src/radarg_data/mod.rs b/radarg_core/src/radarg_data/mod.rs index 63b467b..dd064f2 100644 --- a/radarg_core/src/radarg_data/mod.rs +++ b/radarg_core/src/radarg_data/mod.rs @@ -1,25 +1,61 @@ -use std::{fmt::Display, rc::Rc}; +use std::{ + fmt::Display, + hash::Hash, + rc::Rc, + sync::{atomic::AtomicUsize, Arc}, +}; use chrono::Utc; use ndarray::ArrayD; use radarg_plugin_interface::{ - LoadedData, ProbeDataType as RPT, RadarGridData as RawRadarGridData, VecResult::*, + DataLoaderPlugin, LoadedData, ProbeDataType as RPT, RadarGridData as RawRadarGridData, + VecResult::*, }; + +static DATA_ID: AtomicUsize = AtomicUsize::new(0); + #[derive(Debug, Clone)] -pub enum Data { - RadarGridData(Rc), +pub struct Data { + pub id: usize, + pub description: String, + _data: _Data, +} + +impl PartialEq for Data { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Hash for Data { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl Eq for Data {} + +impl Display for Data { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self._data) + } +} + +#[derive(Debug, Clone)] +pub enum _Data { + RadarGridData(Arc), JsonData, PlainText(String), Binary(Vec), } -impl Display for Data { +impl Display for _Data { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Data::RadarGridData(info) => write!(f, "RadarGridData: {}", info), - Data::JsonData => write!(f, "JsonData"), - Data::PlainText(_) => write!(f, "PlainText"), - Data::Binary(_) => write!(f, "Binary"), + _Data::RadarGridData(info) => write!(f, "RadarGridData: {}", info), + _Data::JsonData => write!(f, "JsonData"), + _Data::PlainText(_) => write!(f, "PlainText"), + _Data::Binary(_) => write!(f, "Binary"), } } } @@ -113,7 +149,7 @@ impl Display for RadarGridData { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct GridDataInfo { pub shape: Vec, pub dimensions: Vec>, @@ -228,13 +264,62 @@ raw2new!( ) ); -impl From for Data { +impl From for _Data { fn from(value: LoadedData) -> Self { match value { - LoadedData::Binary(v) => Data::Binary(v.into_vec()), - LoadedData::JsonData => Data::JsonData, - LoadedData::PlainText(v) => Data::PlainText(v.into_string()), - LoadedData::RadarGridData(v) => Data::RadarGridData(Rc::new(v.into())), + LoadedData::Binary(v) => _Data::Binary(v.into_vec()), + LoadedData::JsonData => _Data::JsonData, + LoadedData::PlainText(v) => _Data::PlainText(v.into_string()), + LoadedData::RadarGridData(v) => _Data::RadarGridData(Arc::new(v.into())), } } } + +impl From for Data { + fn from(value: LoadedData) -> Self { + let description = match &value { + LoadedData::Binary(_) => "Binary".into(), + LoadedData::JsonData => "JsonData".into(), + LoadedData::PlainText(_) => "PlainText".into(), + LoadedData::RadarGridData(v) => format!("{}", v.info.value_name), + }; + Data { + id: DATA_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst), + description: description, + _data: value.into(), + } + } +} + +// impl<'a> From<&'a Data> for &'a Rc { +// fn from(data: &'a Data) -> Self { +// match &data._data { +// _Data::RadarGridData(v) => v, +// _ => panic!("Unsupported data type"), +// } +// } +// } + +impl<'a> From<&'a Data> for &'a Arc { + fn from(data: &'a Data) -> Self { + match &data._data { + _Data::RadarGridData(v) => v, + _ => panic!("Unsupported data type"), + } + } +} + +mod test { + use std::rc::Rc; + + use super::RadarGridData; + + use super::Data; + + fn test() { + let radar_data = RadarGridData { + data: ndarray::ArrayD::from_shape_vec(ndarray::IxDyn(&[1, 1]), vec![1.0]).unwrap(), + info: super::GridDataInfo::default(), + }; + } +}