rebuild factor

This commit is contained in:
Tsuki 2024-08-31 20:59:21 +08:00
parent 6ceebdd7f4
commit 3a9f0dcaa3
31 changed files with 905 additions and 260 deletions

10
.dir-locals.el Normal file
View File

@ -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}"))

18
Cargo.lock generated
View File

@ -779,7 +779,7 @@ dependencies = [
"proj", "proj",
"proj-sys", "proj-sys",
"quadtree_rs", "quadtree_rs",
"quick_cache", "quick_cache 0.4.3",
"radarg_core", "radarg_core",
"radarg_plugin_interface", "radarg_plugin_interface",
"rayon", "rayon",
@ -1838,6 +1838,7 @@ dependencies = [
"nom", "nom",
"nom-derive", "nom-derive",
"once_cell", "once_cell",
"paste 1.0.15",
"pathfinder_geometry", "pathfinder_geometry",
"radarg_core", "radarg_core",
"raw-window-handle", "raw-window-handle",
@ -4159,6 +4160,18 @@ dependencies = [
"parking_lot", "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]] [[package]]
name = "quote" name = "quote"
version = "0.6.13" version = "0.6.13"
@ -4181,12 +4194,15 @@ dependencies = [
name = "radarg_core" name = "radarg_core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"abi_stable",
"chrono", "chrono",
"core_extensions",
"dirs", "dirs",
"ndarray 0.16.1", "ndarray 0.16.1",
"num-traits", "num-traits",
"proj", "proj",
"proj-sys", "proj-sys",
"quick_cache 0.6.5",
"radarg_plugin_interface", "radarg_plugin_interface",
"relm4", "relm4",
"rust-embed", "rust-embed",

View File

@ -43,6 +43,7 @@ femtovg = "0.9.2"
rust-embed = "8.5.0" rust-embed = "8.5.0"
tempfile = "3.12.0" tempfile = "3.12.0"
relm4 = { version = "0.9.0", features = ["libadwaita"] } relm4 = { version = "0.9.0", features = ["libadwaita"] }
paste = "1.0.15"
[features] [features]
default = ["sdf_font"] default = ["sdf_font"]

View File

@ -13,8 +13,8 @@ pub enum Error {
#[error("Invalid Program {0}")] #[error("Invalid Program {0}")]
InvalidProgram(String), InvalidProgram(String),
#[error("Invalid CoordType")] #[error("Error: {0}")]
InvalidDataType, InvalidDataType(String),
#[error("Init Error, cause of {0}")] #[error("Init Error, cause of {0}")]
InitError(anyhow::Error), InitError(anyhow::Error),

View File

@ -106,14 +106,14 @@ impl Graphics for AggFastPath {
Ok(()) Ok(())
} }
fn mount(&mut self, gl: &glow::Context) -> Result<()> { fn mount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(self.program.native_program); gl.use_program(self.program.native_program);
} }
Ok(()) Ok(())
} }
fn unmount(&mut self, gl: &glow::Context) -> Result<()> { fn unmount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(None); gl.use_program(None);
} }

View File

@ -33,7 +33,7 @@ pub trait Graphics {
fn program_mut(&mut self) -> &mut Program; fn program_mut(&mut self) -> &mut Program;
fn mount(&mut self, gl: &glow::Context) -> Result<()> { fn mount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(self.program_ref().native_program.clone()); gl.use_program(self.program_ref().native_program.clone());
} }
@ -41,7 +41,7 @@ pub trait Graphics {
Ok(()) Ok(())
} }
fn unmount(&mut self, gl: &glow::Context) -> Result<()> { fn unmount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(None); gl.use_program(None);
} }

View File

@ -53,7 +53,7 @@ impl PPI {
pub fn data_info(&self, data: &RadarGridData) -> Result<(f32, f32, ProbeDataType, usize, f32)> { pub fn data_info(&self, data: &RadarGridData) -> Result<(f32, f32, ProbeDataType, usize, f32)> {
if data.coord_type().is_none() { if data.coord_type().is_none() {
return Err(Error::InvalidDataType); return Err(Error::InvalidDataType(format!("Invalid CoordType")));
} }
match data.coord_type().unwrap() { match data.coord_type().unwrap() {
CoordType::Polar { 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(()) Ok(())
} }
fn mount(&mut self, gl: &glow::Context) -> Result<()> { fn mount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(self.program.native_program); gl.use_program(self.program.native_program);
} }
Ok(()) Ok(())
} }
fn unmount(&mut self, gl: &glow::Context) -> Result<()> { fn unmount(&self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(None); gl.use_program(None);
} }
@ -216,7 +216,7 @@ impl AttaWithBuffer for PPI {
return Ok((vertices, None, len)); return Ok((vertices, None, len));
} }
_ => { _ => {
return Err(Error::InvalidDataType); return Err(Error::InvalidDataType(format!("Invalid CoordType")));
} }
} }
} }

View File

@ -1,6 +1,6 @@
use log::*; use log::*;
use radarg_core::radarg_data::Data; use radarg_core::{datapool::Value, radarg_data::Data};
use std::{cell::RefCell, path::PathBuf, rc::Rc}; use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc, sync::Arc};
use crate::{ use crate::{
errors::*, errors::*,
@ -19,7 +19,10 @@ use crate::{
}; };
use glow::HasContext; use glow::HasContext;
use super::layout_type::{self, ViewPort}; use super::{
layout_type::{self, ViewPort},
ModuleRefs,
};
use super::{ModulePackage, Programs}; use super::{ModulePackage, Programs};
use crate::{font_manager::FontManager, graphics::font::Text}; use crate::{font_manager::FontManager, graphics::font::Text};
@ -61,17 +64,12 @@ impl App {
&mut self.context.programs &mut self.context.programs
} }
pub fn supported_modules(&mut self) -> Vec<super::Modules> { pub fn supported_modules<'a>(
self.program().supported_modules() &mut self,
data: &'a Value<Data>,
) -> HashMap<&'a Arc<Data>, Vec<ModuleRefs>> {
self.program().supported_modules(data)
} }
// pub fn load_data(
// &mut self,
// data: &Vec<Data>,
// setting: &radarg_core::config::Setting,
// ) -> Result<ModulePackage> {
// self.program().load_data(data, setting)
// }
} }
pub struct Context { pub struct Context {

View File

@ -3,8 +3,11 @@ use femtovg::renderer::OpenGl;
use femtovg::Canvas; use femtovg::Canvas;
use glow::HasContext; use glow::HasContext;
use layout_type::ViewPort; use layout_type::ViewPort;
use modules::PPIModuleConfigComponent; use modules::{PPIModuleConfigComponent, PPIModuleRef};
use radarg_core::radarg_data::Data; use radarg_core::{datapool::Value, radarg_data::Data};
use paste::paste;
use relm4::{ use relm4::{
gtk, gtk,
gtk::prelude::{Cast, IsA}, gtk::prelude::{Cast, IsA},
@ -14,22 +17,22 @@ use relm4::{
pub mod layout_type; pub mod layout_type;
mod modules; mod modules;
use crate::font_manager::FontManager; use crate::{
use crate::graphics::collections::agg_fast_path::AggFastPath; errors::*,
use crate::graphics::font::Text; font_manager::FontManager,
use crate::graphics::ppi::PPI; graphics::{
use crate::graphics::threed::Trackball; collections::agg_fast_path::AggFastPath, font::Text, ppi::PPI,
use crate::graphics::transforms::plane::PlaneTrans; transforms::plane::PlaneTrans, AttaWithProgram, AttachWithIO, Graphics,
use crate::graphics::{AttaWithProgram, AttachWithIO}; },
use crate::ui::operation::Operation; ui::{operation::Operation, typ::LayoutAttach},
use crate::ui::typ::LayoutAttach; utils::resources::GL,
use crate::utils::resources::GL; };
use crate::{errors::*, graphics::Graphics};
pub use app::{App, Context}; pub use app::{App, Context};
pub use modules::{Module, ModuleCursor, PPIModule, PPIPackage}; pub use modules::{Module, ModuleCursor, PPIModule, PPIPackage};
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize; 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); 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) PPIModule::new(&self.gl, &mut self._ppi, &mut self._text, &mut self._line)
} }
pub fn supported_modules(&mut self) -> Vec<Modules> { pub fn ppi_ref(&self) -> PPIModuleRef {
vec![Modules::PPI(self.ppi())] PPIModuleRef::new(&self.gl, &self._ppi, &self._text, &self._line)
} }
// pub fn load_data( pub fn supported_modules<'a>(
// &mut self, &mut self,
// data: &Vec<Data>, data: &'a Value<Data>,
// setting: &radarg_core::config::Setting, ) -> HashMap<&'a Arc<Data>, Vec<ModuleRefs>> {
// ) -> Result<Vec<ModulePackage>> { let mut result = HashMap::new();
// data.iter()
// .map(|d| self.ppi().load_data(, setting).map(|v| v.into())) for (k, d) in data.iter() {
// .collect() result.insert(d, vec![ModuleRefs::PPI(self.ppi_ref())]);
// } }
result
}
pub fn draw_modules( pub fn draw_modules(
&mut self, &mut self,
@ -108,7 +114,7 @@ impl Programs {
} }
macro_rules! impl_module_package { 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>{ 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<ModulePackage> {
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)] #[derive(Debug)]
pub enum _ModulePackage { pub enum _ModulePackage {
$( $(
@ -209,7 +244,7 @@ macro_rules! impl_module_package {
} }
impl_module_package!( impl_module_package!(
{PPIPackage => PPI | PPIModule | PPIModuleConfigComponent} {PPIPackage => PPI | PPIModule | PPIModuleRef | PPIModuleConfigComponent}
); );
impl ModulePackage { impl ModulePackage {

View File

@ -11,10 +11,13 @@ use crate::{
use femtovg::{renderer::OpenGl, Canvas}; use femtovg::{renderer::OpenGl, Canvas};
use glow::{HasContext, NativeBuffer, NativeVertexArray}; use glow::{HasContext, NativeBuffer, NativeVertexArray};
use radarg_core::config::Setting; 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; mod ppi;
use crate::errors::*; use crate::errors::*;
pub use ppi::{PPIModule, PPIModuleConfigComponent, PPIModuleConfigComponentWidgets, PPIPackage}; pub use ppi::{
PPIModule, PPIModuleConfigComponent, PPIModuleConfigComponentWidgets, PPIModuleRef, PPIPackage,
};
use relm4::Component as RComponent; use relm4::Component as RComponent;
use super::{layout_type::ViewPort, SideBarInputMsg}; use super::{layout_type::ViewPort, SideBarInputMsg};
@ -95,6 +98,8 @@ pub trait Module: Sized {
type Data; type Data;
type Operation: AttachWithIO; type Operation: AttachWithIO;
const NAME: &'static str;
fn render( fn render(
&mut self, &mut self,
cursor: &mut Self::Cursor, cursor: &mut Self::Cursor,
@ -102,7 +107,7 @@ pub trait Module: Sized {
viewport: &ViewPort, viewport: &ViewPort,
) -> Result<()>; ) -> Result<()>;
fn load_data<'dt>(&self, data: &Rc<Self::Data>, setting: &Setting) -> Result<Self::Cursor>; fn load_data<'dt>(&self, data: &Arc<Self::Data>, setting: &Setting) -> Result<Self::Cursor>;
} }
pub trait ModuleCursor { pub trait ModuleCursor {

View File

@ -21,6 +21,7 @@ use glow::HasContext;
use std::{ use std::{
cell::{RefCell, RefMut}, cell::{RefCell, RefMut},
rc::Rc, rc::Rc,
sync::Arc,
}; };
use tracker::track; use tracker::track;
@ -40,6 +41,125 @@ pub struct PPIModule<'b, 'gl: 'b> {
text_program: &'b mut Text, 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> { impl<'b, 'a: 'b> PPIModule<'b, 'a> {
pub fn new( pub fn new(
gl: &'a GL, gl: &'a GL,
@ -158,6 +278,8 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> {
type Data = RadarGridData; type Data = RadarGridData;
type Operation = PlaneTrans; type Operation = PlaneTrans;
const NAME: &'static str = "PPI";
fn render<'dt>( fn render<'dt>(
&mut self, &mut self,
cursor: &mut Self::Cursor, cursor: &mut Self::Cursor,
@ -238,7 +360,7 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> {
Ok(()) Ok(())
} }
fn load_data<'dt>(&self, data: &Rc<Self::Data>, setting: &Setting) -> Result<Self::Cursor> { fn load_data<'dt>(&self, data: &Arc<Self::Data>, setting: &Setting) -> Result<Self::Cursor> {
// Init the memory // Init the memory
let (vao, vbo, ebo) = self.ppi_program.init(&self.gl); let (vao, vbo, ebo) = self.ppi_program.init(&self.gl);
let mut ppi_attach = Attach::new(self.gl.clone(), vao, vbo, ebo, None); 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 // Get the data info
let (r, a, t, max_layer, unvalid) = self.ppi_program.data_info(&data)?; let (r, a, t, max_layer, unvalid) = self.ppi_program.data_info(&data)?;
println!("name: {}", data.info.value_name);
// Find the color map // Find the color map
let cmap = setting.find(&t); let cmap = setting.find(&t);
// Check if the color map is valid // Check if the color map is valid
if cmap.is_none() { 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(); let cmap = cmap.unwrap();
@ -294,7 +421,7 @@ pub struct PPIPackage {
ppi_attach: Attach, ppi_attach: Attach,
line_attach: Attach, line_attach: Attach,
tick_attach: Attach, tick_attach: Attach,
data: Rc<RadarGridData>, data: Arc<RadarGridData>,
} }
impl PPIPackage { impl PPIPackage {
@ -303,7 +430,7 @@ impl PPIPackage {
ppi_attach: Attach, ppi_attach: Attach,
line_attach: Attach, line_attach: Attach,
tick_attach: Attach, tick_attach: Attach,
data: Rc<RadarGridData>, data: Arc<RadarGridData>,
) -> Self { ) -> Self {
Self { Self {
draw_helper: true, draw_helper: true,
@ -415,38 +542,74 @@ impl SimpleComponent for PPIModuleConfigComponent {
type Output = OutputMsg; type Output = OutputMsg;
view! { view! {
adw::PreferencesPage {
adw::PreferencesGroup { adw::PreferencesGroup {
set_title:"PPI Config", set_title:"PPI Config",
set_hexpand:true, set_hexpand:true,
set_vexpand:true,
adw::SwitchRow { adw::SwitchRow {
set_title:"Ticks", set_title:"Ticks",
set_active: init_config.ticks, set_active: init_config.ticks,
connect_active_notify[sender, config_ref] => move |this| { connect_active_notify[sender, config_ref] => move |this| {
let active = this.is_active(); let active = this.is_active();
config_ref.borrow_mut().set_ticks(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 { adw::SpinRow {
set_title: "Layer", set_title: "Layer",
set_value: init_config.layer as f64,
set_range: (0.0, init_config.max_layer as f64),
set_digits: 0, set_digits: 0,
set_numeric: true, set_numeric: true,
set_climb_rate: 1.0, set_snap_to_ticks: true,
#[wrap(Some)]
set_adjustment=&gtk::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| { connect_value_notify[sender, config_ref] => move |this| {
let layer = this.value() as usize; let layer = this.value() as usize - 1;
config_ref.borrow_mut().set_layer(layer); config_ref.borrow_mut().set_layer(layer);
} sender.output(OutputMsg::Refresh);
}, },
gtk::Button { },
set_label: "Refresh", },
connect_clicked[sender] => move |_| { adw::PreferencesGroup {
set_title:"Show Config",
set_hexpand:true,
adw::PreferencesRow {
set_title:"Color Line",
#[wrap(Some)]
set_child=&gtk::Box{
gtk::ColorDialogButton {
set_dialog=&gtk::ColorDialog {},
set_rgba: &gtk::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); sender.output(OutputMsg::Refresh);
} }
} }
} }
},
}
}
} }
fn init( fn init(

View File

@ -25,3 +25,9 @@ pub struct IO {
pub mouse: MouseIO, pub mouse: MouseIO,
pub keyboard: KeyboardIO, pub keyboard: KeyboardIO,
} }
impl IO {
pub fn reset(&mut self) {
self.mouse.wheel_delta = 0.0;
}
}

View File

@ -1,3 +1,4 @@
use nom::error::Error;
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ETWSError { pub enum ETWSError {
@ -6,9 +7,17 @@ pub enum ETWSError {
#[from] #[from]
source: std::io::Error, source: std::io::Error,
}, },
#[error("Format Error")] #[error("Unsupported Format")]
FormatError { FormatError {
#[from] #[from]
source: anyhow::Error, source: anyhow::Error,
}, },
#[error("Binary Error")]
NomError,
}
impl<'a> From<nom::Err<nom::error::Error<&'a [u8]>>> for ETWSError {
fn from(value: nom::Err<nom::error::Error<&'a [u8]>>) -> Self {
ETWSError::NomError
}
} }

View File

@ -168,7 +168,7 @@ impl DataLoaderPlugin for ETWSLoader {
{ "DBZ" | "CR" | "FR" | "R" => DBZ}, { "DBZ" | "CR" | "FR" | "R" => DBZ},
{ "VIL" => VIL}, { "VIL" => VIL},
{ "EB" => EB}, { "EB" => EB},
{ "V" => V}, { "V" | "VEL" => V},
{ "ZDR" => ZDR}, { "ZDR" => ZDR},
{ "PHIDP" => PHIDP}, { "PHIDP" => PHIDP},
{ "KDP" => KDP}, { "KDP" => KDP},

View File

@ -1,3 +1,4 @@
use crate::error::ETWSError;
use abi_stable::std_types::vec; use abi_stable::std_types::vec;
use bytemuck::cast_slice; use bytemuck::cast_slice;
use nom::{ use nom::{
@ -244,34 +245,84 @@ fn parse_sub_pulse_config(input: &[u8]) -> IResult<&[u8], SubPulseConfig> {
Ok((input, sub_pulse_config)) Ok((input, sub_pulse_config))
} }
pub fn parse_raw_data<P: AsRef<Path>>(path: P) -> io::Result<RadarData> { pub fn parse_raw_data<P: AsRef<Path>>(path: P) -> Result<RadarData, ETWSError> {
let path = path.as_ref(); 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" { if path.extension().unwrap() == "zip" {
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
let mut archive = ZipArchive::new(file).unwrap(); let mut archive = ZipArchive::new(file).unwrap();
let mut file = archive.by_index(0).unwrap(); let mut file = archive.by_index(0).unwrap();
let mut buf = Vec::new(); 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" { if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" {
return get_radar_data(buf); return get_radar_data(buf);
} else { } 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 { } else {
let mut file = File::open(path).unwrap(); let mut file = File::open(path)?;
let mut buf = Vec::new(); 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" { if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" {
return get_radar_data(buf); return get_radar_data(buf);
} else { } else {
panic!("Invalid file format"); return Err(ETWSError::FormatError {
source: anyhow::anyhow!("Invalid file format"),
});
} }
} }
} }
fn get_radar_data(data: Vec<u8>) -> io::Result<RadarData> { fn get_radar_data(data: Vec<u8>) -> Result<RadarData, ETWSError> {
let total_length = data.len() as u64; let total_length = data.len() as u64;
// 使用 Cursor 来处理 Vec<u8> // 使用 Cursor 来处理 Vec<u8>
let mut cursor = Cursor::new(data); let mut cursor = Cursor::new(data);
@ -279,24 +330,24 @@ fn get_radar_data(data: Vec<u8>) -> io::Result<RadarData> {
// 读取 GENERIC_HEADER // 读取 GENERIC_HEADER
let mut buffer = vec![0u8; 32]; let mut buffer = vec![0u8; 32];
cursor.read_exact(&mut buffer)?; cursor.read_exact(&mut buffer)?;
let (_, generic_header) = parse_generic_header(&buffer).unwrap(); let (_, generic_header) = parse_generic_header(&buffer)?;
// 读取 SITE_CONFIG // 读取 SITE_CONFIG
let mut buffer = vec![0u8; 128]; let mut buffer = vec![0u8; 128];
cursor.read_exact(&mut buffer)?; cursor.read_exact(&mut buffer)?;
let (_, site_config) = parse_site_config(&buffer).unwrap(); let (_, site_config) = parse_site_config(&buffer)?;
// 读取 TASK_CONFIG // 读取 TASK_CONFIG
let mut buffer = vec![0u8; 256]; let mut buffer = vec![0u8; 256];
cursor.read_exact(&mut buffer)?; cursor.read_exact(&mut buffer)?;
let (_, task_config) = parse_task_config(&buffer).unwrap(); let (_, task_config) = parse_task_config(&buffer)?;
// 读取 SCAN_CONFIG // 读取 SCAN_CONFIG
let mut scan_configs = Vec::new(); let mut scan_configs = Vec::new();
for _ in 0..task_config.scan_beam_number { for _ in 0..task_config.scan_beam_number {
let mut buffer = vec![0u8; 640]; let mut buffer = vec![0u8; 640];
cursor.read_exact(&mut buffer)?; 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); scan_configs.push(scan_config);
} }
@ -305,7 +356,7 @@ fn get_radar_data(data: Vec<u8>) -> io::Result<RadarData> {
for _ in 0..task_config.cut_number { for _ in 0..task_config.cut_number {
let mut buffer = vec![0u8; 256]; let mut buffer = vec![0u8; 256];
cursor.read_exact(&mut buffer)?; 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); beam_configs.push(beam_config);
} }
@ -454,19 +505,22 @@ fn parse_final_data(
all_length: u64, all_length: u64,
cut_number: usize, cut_number: usize,
mut cursor: Cursor<Vec<u8>>, mut cursor: Cursor<Vec<u8>>,
) -> io::Result<( ) -> Result<
(
HashMap<&'static str, Vec<f64>>, HashMap<&'static str, Vec<f64>>,
Vec<f64>, Vec<f64>,
Vec<f64>, Vec<f64>,
Vec<f64>, Vec<f64>,
)> { ),
ETWSError,
> {
let position = cursor.position(); let position = cursor.position();
let mut radial_buffer = vec![0u8; 128]; let mut radial_buffer = vec![0u8; 128];
let mut header_buffer = vec![0u8; 32]; let mut header_buffer = vec![0u8; 32];
cursor.read_exact(&mut radial_buffer)?; cursor.read_exact(&mut radial_buffer)?;
// First Block // 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. // Radial_number: I don't know why not use it.
// let radial_number = radial_data.radial_number as usize; // let radial_number = radial_data.radial_number as usize;
@ -480,7 +534,7 @@ fn parse_final_data(
for idx in 0..type_number { for idx in 0..type_number {
cursor.read_exact(&mut header_buffer)?; 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_block = beam_block_exact(&mut cursor, &header)?;
let first_beam = single_beam_block(&first_beam_block, header.bin_length as usize)?; let first_beam = single_beam_block(&first_beam_block, header.bin_length as usize)?;
gate_len[idx] = first_beam.len(); gate_len[idx] = first_beam.len();
@ -516,31 +570,32 @@ fn parse_final_data(
for e in 0..cut_number { for e in 0..cut_number {
for a in 0..azm_number { for a in 0..azm_number {
cursor.read_exact(&mut radial_buffer)?; 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; els[e] = radial_data.elevation as f64;
azs[a] = radial_data.azimuth as f64; azs[a] = radial_data.azimuth as f64;
let type_number = radial_data.moment_number as usize; let type_number = radial_data.moment_number as usize;
for typ in 0..type_number { for typ in 0..type_number {
cursor.read_exact(&mut header_buffer)?; 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 beam_block = beam_block_exact(&mut cursor, &header)?;
let mut beam = single_beam_block(&beam_block, header.bin_length as usize)?; let mut beam = single_beam_block(&beam_block, header.bin_length as usize)?;
beam.iter_mut() beam.iter_mut()
.for_each(|v| *v = (*v - header.offset as f64) / header.scale as f64); .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" { if typ_name == &"Unknown" {
continue; continue;
} }
let e = radial_data.elevation_number as usize - 1; let e = radial_data.elevation_number as usize - 1;
datas.get_mut(typ_name).unwrap()[e * (azm_number * gate_len[typ]) datas.get_mut(typ_name).unwrap()[e * (azm_number * gate_len[typ])
+ a * gate_len[typ] + a * gate_len[typ]
..e * (azm_number * gate_len[typ]) + (a + 1) * gate_len[typ]] ..e * (azm_number * gate_len[typ]) + (a + 1) * gate_len[typ]]
.copy_from_slice(&beam); .copy_from_slice(&beam);
} else {
continue;
}
} }
} }
} }

View File

@ -7,12 +7,13 @@ use super::{
sidebar::{SideBarInputMsg, SideBarModel}, sidebar::{SideBarInputMsg, SideBarModel},
ControlPanelOutputMsg, TimelineMsg, ControlPanelOutputMsg, TimelineMsg,
}; };
use crate::datapool::{DataPool, Value};
use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete}; use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete};
use crate::widgets::{DynamicCol, ElementType}; 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 chrono::{prelude::*, Duration};
use gtk::Widget;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use radarg_core::datapool::{DataPool, Value};
use radarg_core::Data; use radarg_core::Data;
use relm4::{ use relm4::{
actions::{AccelsPlus, RelmAction, RelmActionGroup}, actions::{AccelsPlus, RelmAction, RelmActionGroup},
@ -61,15 +62,16 @@ pub enum FileIOType {
pub enum AppMsg { pub enum AppMsg {
Refresh, Refresh,
FileIO { typ: FileIOType }, FileIO { typ: FileIOType },
OpenDialog, OpenDialog { widget: Widget },
CloseDialog,
OpenAlert { body: String, title: String },
CloseAlert,
CloseRequest, CloseRequest,
Close, Close,
OpenFileDialog, OpenFileDialog,
} }
#[tracker::track] #[tracker::track]
pub struct AppModel { pub struct AppModel {
waiting_for: Option<DateTime<Utc>>,
// Components // Components
#[do_not_track] #[do_not_track]
open_dialog: Controller<OpenDialog>, open_dialog: Controller<OpenDialog>,
@ -81,12 +83,6 @@ pub struct AppModel {
sidebar: Controller<SideBarModel>, sidebar: Controller<SideBarModel>,
#[do_not_track] #[do_not_track]
setting: Controller<SettingModel>, setting: Controller<SettingModel>,
// Data
selected_layer: Vec<usize>,
#[do_not_track]
layers: Share<Vec<Layer>>,
// File Pool // File Pool
#[do_not_track] #[do_not_track]
file_pool: Share<DataPool>, file_pool: Share<DataPool>,
@ -184,16 +180,10 @@ impl Component for AppModel {
set_title: "Dialog", set_title: "Dialog",
set_presentation_mode: adw::DialogPresentationMode::Floating, set_presentation_mode: adw::DialogPresentationMode::Floating,
set_follows_content_size: true, set_follows_content_size: true,
set_can_close: true, set_can_close: true
#[wrap(Some)]
set_child=&gtk::Box{
set_height_request: 200,
set_width_request: 200,
gtk::Label{
set_text:"Dialog",
}, },
} alert_dialog = adw::AlertDialog{
} }
} }
@ -220,21 +210,14 @@ impl Component for AppModel {
root: Self::Root, root: Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let layers = Rc::new(RefCell::new(vec![])); let data_pool = DataPool::new(&PLUGIN_MANAGER, 10);
// 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 = Rc::new(RefCell::new(data_pool)); let data_pool = Rc::new(RefCell::new(data_pool));
// SideBar Component // SideBar Component
let sidebar = SideBarModel::builder() let sidebar = SideBarModel::builder()
.launch(None) .launch(None)
.forward(sender.input_sender(), |msg| match msg { .forward(sender.input_sender(), |msg| match msg {
SideBarOutputMsg::Dialog(widget) => AppMsg::OpenDialog { widget },
SideBarOutputMsg::QueueDraw => AppMsg::Refresh, SideBarOutputMsg::QueueDraw => AppMsg::Refresh,
_ => AppMsg::Close, _ => AppMsg::Close,
}); });
@ -242,7 +225,7 @@ impl Component for AppModel {
let sidebar_sender = sidebar.sender(); let sidebar_sender = sidebar.sender();
// Monitor Component // Monitor Component
let render = MonitorModel::builder().launch(layers.clone()).forward( let render = MonitorModel::builder().launch(()).forward(
sender.input_sender(), sender.input_sender(),
clone!( clone!(
#[strong] #[strong]
@ -250,11 +233,22 @@ impl Component for AppModel {
move |model_message| match model_message { move |model_message| match model_message {
MonitorOutputMsg::Attached(new_module) => { MonitorOutputMsg::Attached(new_module) => {
sidebar_sender.emit(SideBarInputMsg::Package(new_module)); sidebar_sender.emit(SideBarInputMsg::Package(new_module));
AppMsg::OpenDialog AppMsg::CloseDialog
// AppMsg::Close }
MonitorOutputMsg::Dialog(widget) => {
AppMsg::OpenDialog { widget }
}
MonitorOutputMsg::DialogClose => {
AppMsg::CloseDialog
}
MonitorOutputMsg::Alert(content, title) => {
AppMsg::OpenAlert {
body: content,
title,
}
} }
MonitorOutputMsg::Fc => { MonitorOutputMsg::Fc => {
AppMsg::OpenDialog AppMsg::Close
} }
_ => AppMsg::Close, _ => AppMsg::Close,
} }
@ -287,7 +281,10 @@ impl Component for AppModel {
} }
Err(e) => { Err(e) => {
error!("Failed to load data, cause: {:?}", 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 { let model = AppModel {
waiting_for: None,
render, render,
setting, setting,
open_dialog: dialog, open_dialog: dialog,
selected_layer: vec![],
sidebar, sidebar,
file_pool: data_pool, file_pool: data_pool,
// control, // control,
layers,
tracker: 0, tracker: 0,
}; };
@ -315,7 +309,6 @@ impl Component for AppModel {
let widgets = view_output!(); let widgets = view_output!();
let mut group = RelmActionGroup::<FileActionGroup>::new(); let mut group = RelmActionGroup::<FileActionGroup>::new();
relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]); relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
// register_layer_actions(&widgets.main_window, sender.clone());
let action: RelmAction<OpenAction> = { let action: RelmAction<OpenAction> = {
RelmAction::new_stateless(move |_| { RelmAction::new_stateless(move |_| {
sender.input(AppMsg::OpenFileDialog); sender.input(AppMsg::OpenFileDialog);
@ -343,9 +336,24 @@ impl Component for AppModel {
AppMsg::OpenFileDialog => { AppMsg::OpenFileDialog => {
self.open_dialog.emit(OpenDialogMsg::Open); self.open_dialog.emit(OpenDialogMsg::Open);
} }
AppMsg::OpenDialog => { AppMsg::OpenDialog { widget } => {
widgets.dialog.set_child(Some(&widget));
widgets.dialog.present(Some(root)); 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 { AppMsg::FileIO {
typ: FileIOType::Open(data), typ: FileIOType::Open(data),
} => self.render.emit(MonitorInputMsg::PushData(data)), } => self.render.emit(MonitorInputMsg::PushData(data)),

View File

@ -1,6 +1,5 @@
use super::messages::*; use super::messages::*;
use super::thumbnail::{ImgItem, TypedListView}; use super::thumbnail::{ImgItem, TypedListView};
use crate::plugin_system::init_plugin;
use crate::predefined::color_mapper::BoundaryNorm; use crate::predefined::color_mapper::BoundaryNorm;
use crate::widgets::render::Layer; use crate::widgets::render::Layer;
use crate::widgets::timeline::{Selection, TimeLine}; use crate::widgets::timeline::{Selection, TimeLine};

View File

@ -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<ItemInfo>>;
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=&gtk::Label{
set_label: "Header",
},
},
#[wrap(Some)]
set_content=&adw::Clamp{
set_hexpand:true,
#[wrap(Some)]
#[name(content)]
set_child=&gtk::Box{
set_orientation: gtk::Orientation::Vertical,
set_hexpand:true,
set_spacing: 10,
},
}
}
}
}
fn init(
init: Self::Init,
root: Self::Root,
sender: relm4::ComponentSender<Self>,
) -> relm4::ComponentParts<Self> {
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=&gtk::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<Self>) {}
}

View File

@ -1,10 +1,12 @@
use crate::datapool::Value; use gi::pg::{ModulePackage, Modules};
use gi::pg::ModulePackage; use gtk::Widget;
use radarg_core::datapool::Value;
use radarg_core::Data; 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 { pub enum MonitorInputMsg {
PushData(Value<Data>), PushData(Value<Data>),
Draw(Arc<Data>),
QueueDraw, QueueDraw,
None, None,
} }
@ -13,6 +15,9 @@ impl Debug for MonitorInputMsg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
MonitorInputMsg::QueueDraw => write!(f, "MonitorInputMsg::QueueDraw"), MonitorInputMsg::QueueDraw => write!(f, "MonitorInputMsg::QueueDraw"),
MonitorInputMsg::Draw(data) => {
write!(f, "MonitorInputMsg::Draw({:?})", data)
}
MonitorInputMsg::PushData(data) => write!(f, "MonitorInputMsg::PushData({:?})", data), MonitorInputMsg::PushData(data) => write!(f, "MonitorInputMsg::PushData({:?})", data),
MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"), MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"),
} }
@ -22,6 +27,9 @@ impl Debug for MonitorInputMsg {
#[derive(Debug)] #[derive(Debug)]
pub enum MonitorOutputMsg { pub enum MonitorOutputMsg {
Attached(Rc<RefCell<ModulePackage>>), Attached(Rc<RefCell<ModulePackage>>),
Dialog(Widget),
DialogClose,
Alert(String, String),
Fc, Fc,
} }

View File

@ -1,3 +1,4 @@
mod dialog_widget;
pub mod messages; pub mod messages;
pub mod monitor; pub mod monitor;

View File

@ -1,3 +1,4 @@
use super::dialog_widget::{Dialog, DialogOutput, ItemInfo};
use super::messages::{MonitorInputMsg, MonitorOutputMsg}; use super::messages::{MonitorInputMsg, MonitorOutputMsg};
use crate::predefined::color_mapper::BoundaryNorm; use crate::predefined::color_mapper::BoundaryNorm;
use crate::widgets::render::RenderConfig; use crate::widgets::render::RenderConfig;
@ -8,9 +9,10 @@ use crate::{
}; };
use geo::k_nearest_concave_hull; use geo::k_nearest_concave_hull;
use gi::graphics::transforms::plane::PlaneTrans; use gi::graphics::transforms::plane::PlaneTrans;
use gi::pg::ModulePackage; use gi::pg::{Module, ModulePackage};
use gi::ui::operation::Operation; use gi::ui::operation::Operation;
use gtk::glib::clone; use gtk::glib::clone;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
@ -21,6 +23,7 @@ use adw::prelude::*;
use femtovg::ImageId; use femtovg::ImageId;
use fns::debounce; use fns::debounce;
use gi::ui::typ::MainLoadAttach; use gi::ui::typ::MainLoadAttach;
use radarg_core::Data;
use relm4::{component::Component, *}; use relm4::{component::Component, *};
use slippy_map_tiles::Tile; use slippy_map_tiles::Tile;
use tokio::task; use tokio::task;
@ -49,7 +52,7 @@ pub struct MonitorWidgets {
impl Component for MonitorModel { impl Component for MonitorModel {
type CommandOutput = MonitorCommand; type CommandOutput = MonitorCommand;
type Input = MonitorInputMsg; type Input = MonitorInputMsg;
type Init = Rc<RefCell<Vec<Layer>>>; type Init = ();
type Output = MonitorOutputMsg; type Output = MonitorOutputMsg;
view! { view! {
@ -95,24 +98,60 @@ impl Component for MonitorModel {
self.reset(); self.reset();
match message { match message {
MonitorInputMsg::PushData(data) => { MonitorInputMsg::PushData(data) => {
sender.output(MonitorOutputMsg::Fc); widgets.renderer.get_gi(|gi| {
// widgets let supported_modules = gi.supported_modules(&data);
// .renderer
// .get_gi(|gi| match gi.load_data(&data, &SETTING) { let mut result = HashMap::new();
// Ok(package) => { for (data, modules) in supported_modules {
// info!("data load success!"); let mut module_packages = vec![];
// let rc_package = Rc::new(RefCell::new(package)); for module in modules {
// self.set_module_packages(vec![rc_package.clone()]); module_packages.push(ItemInfo {
// sender.output(MonitorOutputMsg::Attached(rc_package)); module_name: module.name(),
// } module_icon: "plus",
// Err(err) => { });
// error!("Load Error, cause of {}", err); }
// } 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 => { MonitorInputMsg::QueueDraw => {
widgets.renderer.queue_draw(); 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 => {} MonitorInputMsg::None => {}
_ => {} _ => {}
} }

View File

@ -4,12 +4,13 @@ use chrono::{DateTime, Utc};
use gi::pg::SideBarInputMsg; use gi::pg::SideBarInputMsg;
use gi::pg::{Components, ModulePackage}; use gi::pg::{Components, ModulePackage};
use glib_macros::clone; use glib_macros::clone;
use gtk::glib;
use gtk::prelude::WidgetExt; use gtk::prelude::WidgetExt;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{glib, Widget};
use relm4::actions::{AccelsPlus, RelmAction}; use relm4::actions::{AccelsPlus, RelmAction};
use relm4::RelmRemoveAllExt; use relm4::RelmRemoveAllExt;
use relm4::{ use relm4::{
adw::{self, prelude::*},
binding::{Binding, U8Binding}, binding::{Binding, U8Binding},
factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque}, factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque},
gtk::gio, gtk::gio,
@ -18,7 +19,7 @@ use relm4::{
column::TypedColumnView, column::TypedColumnView,
list::{RelmListItem, TypedListView}, list::{RelmListItem, TypedListView},
}, },
RelmObjectExt, view, RelmObjectExt,
}; };
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
@ -36,6 +37,7 @@ pub struct SideBarModel {
#[derive(Debug)] #[derive(Debug)]
pub enum SideBarOutputMsg { pub enum SideBarOutputMsg {
Dialog(Widget),
QueueDraw, QueueDraw,
} }
@ -54,7 +56,46 @@ impl Component for SideBarModel {
set_margin_all: 5, set_margin_all: 5,
#[name="container"] #[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=&gtk::Label{
set_label: "Header",
},
},
#[wrap(Some)]
set_content=&gtk::Box{
gtk::Button{
set_label:"Expanders",
},
gtk::Button{
set_label:"Expanders",
}
}
}
}
};
sender.output(SideBarOutputMsg::Dialog(widget.upcast()));
}
}
}
}, },
} }

View File

@ -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<T: Display>(Arc<Vec<T>>);
impl<T: Display> Value<T> {
pub fn new(data: Vec<T>) -> Self {
Self(Arc::new(data))
}
}
impl<T: Display> Deref for Value<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Value<Data> {
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<PathBuf, Value<Data>>,
}
impl DataPool {
pub fn new(cap: usize) -> Self {
Self {
pool: Cache::new(cap),
}
}
pub fn get_or_load(&self, path: impl Into<PathBuf>) -> Result<Value<Data>, DataError> {
let path = path.into();
self.pool.get_or_insert_with(&path, || {
PLUGIN_MANAGER.try_load_data(&path).map(Value::new)
})
}
}

View File

@ -3,15 +3,13 @@
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
use gtk::{gio, prelude::SettingsExt}; 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::convert::TryInto;
use std::sync::RwLock; use std::sync::RwLock;
use std::{ptr, sync::Mutex}; use std::{ptr, sync::Mutex};
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
mod actions; mod actions;
mod components; mod components;
mod datapool;
mod plugin_system;
use crate::components::app::AppMsg; use crate::components::app::AppMsg;
use components::app::AppModel; use components::app::AppModel;
use gi::{App as GI, Helper, GL}; use gi::{App as GI, Helper, GL};

View File

@ -183,6 +183,8 @@ impl GLAreaImpl for Render {
viewport.unbind(); viewport.unbind();
self.io.borrow_mut().reset();
glib::Propagation::Proceed glib::Propagation::Proceed
} }
} }

View File

@ -63,9 +63,12 @@ impl Render {
this, this,
move |_, x, y| { move |_, x, y| {
this.imp().set_io(|io| { this.imp().set_io(|io| {
io.mouse.wheel_delta = y as f32; io.mouse.wheel_delta = -y as f32;
}); });
if y != 0.0 {
this.queue_draw(); this.queue_draw();
}
glib::Propagation::Proceed glib::Propagation::Proceed
} }
)); ));
@ -136,7 +139,7 @@ impl Render {
f(&mut cfg); f(&mut cfg);
} }
pub fn get_gi<F: FnMut(&mut GI)>(&self, mut f: F) { pub fn get_gi<F: FnOnce(&mut GI)>(&self, mut f: F) {
let mut gi = self.imp().gi.borrow_mut(); let mut gi = self.imp().gi.borrow_mut();
f(&mut gi.as_mut().unwrap()); f(&mut gi.as_mut().unwrap());
} }

View File

@ -15,6 +15,9 @@ dirs = "5.0.1"
num-traits = "0.2.19" num-traits = "0.2.19"
serde = { version = "1.0.209", features = ["derive"] } serde = { version = "1.0.209", features = ["derive"] }
relm4 = { version = "0.9.0", features = ["libadwaita"] } 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] [dependencies.radarg_plugin_interface]
version = "0.1" version = "0.1"

View File

@ -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<T: Display>(Arc<HashMap<usize, Arc<T>>>);
impl Value<Data> {
pub fn new(data: Vec<Data>) -> 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<Data>> {
self.0.get(&key)
}
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, usize, Arc<Data>> {
self.0.iter()
}
}
impl<T: Display> Value<T> {
pub fn len(&self) -> usize {
self.0.len()
}
}
impl<T: Display> Deref for Value<T> {
type Target = HashMap<usize, Arc<T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Value<Data> {
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<PathBuf, Value<Data>>,
}
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<PathBuf>) -> Result<Value<Data>, DataError> {
let path = path.into();
self.pool.get_or_insert_with(&path, || {
self.plugin_manager.try_load_data(&path).map(Value::new)
})
}
}

View File

@ -2,6 +2,8 @@ pub mod config;
pub mod errors; pub mod errors;
pub mod radarg_data; pub mod radarg_data;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
pub mod datapool;
pub mod plugin_system;
pub mod utils; pub mod utils;
pub mod widget_interface; pub mod widget_interface;

View File

@ -1,3 +1,5 @@
use crate::errors::DataError;
use crate::Data;
use abi_stable::{ use abi_stable::{
external_types::crossbeam_channel::{self, RReceiver, RSender}, external_types::crossbeam_channel::{self, RReceiver, RSender},
library::{lib_header_from_path, LibraryError, LibrarySuffix, RawLibrary}, 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}, std_types::{RBox, RErr, ROk, RResult, RSome, RStr, RString, RVec},
}; };
use core_extensions::*; use core_extensions::*;
use radarg_core::errors::DataError;
use radarg_core::Data;
use radarg_plugin_interface::{DataLoaderPlugin, DataLoaderPlugin_TO, PluginId, PluginMod_Ref}; use radarg_plugin_interface::{DataLoaderPlugin, DataLoaderPlugin_TO, PluginId, PluginMod_Ref};
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},

View File

@ -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 chrono::Utc;
use ndarray::ArrayD; use ndarray::ArrayD;
use radarg_plugin_interface::{ 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)] #[derive(Debug, Clone)]
pub enum Data { pub struct Data {
RadarGridData(Rc<RadarGridData>), 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<H: std::hash::Hasher>(&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<RadarGridData>),
JsonData, JsonData,
PlainText(String), PlainText(String),
Binary(Vec<u8>), Binary(Vec<u8>),
} }
impl Display for Data { impl Display for _Data {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Data::RadarGridData(info) => write!(f, "RadarGridData: {}", info), _Data::RadarGridData(info) => write!(f, "RadarGridData: {}", info),
Data::JsonData => write!(f, "JsonData"), _Data::JsonData => write!(f, "JsonData"),
Data::PlainText(_) => write!(f, "PlainText"), _Data::PlainText(_) => write!(f, "PlainText"),
Data::Binary(_) => write!(f, "Binary"), _Data::Binary(_) => write!(f, "Binary"),
} }
} }
} }
@ -113,7 +149,7 @@ impl Display for RadarGridData {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Default)]
pub struct GridDataInfo { pub struct GridDataInfo {
pub shape: Vec<usize>, pub shape: Vec<usize>,
pub dimensions: Vec<Vec<f64>>, pub dimensions: Vec<Vec<f64>>,
@ -228,13 +264,62 @@ raw2new!(
) )
); );
impl From<LoadedData> for Data { impl From<LoadedData> for _Data {
fn from(value: LoadedData) -> Self { fn from(value: LoadedData) -> Self {
match value { match value {
LoadedData::Binary(v) => Data::Binary(v.into_vec()), LoadedData::Binary(v) => _Data::Binary(v.into_vec()),
LoadedData::JsonData => Data::JsonData, LoadedData::JsonData => _Data::JsonData,
LoadedData::PlainText(v) => Data::PlainText(v.into_string()), LoadedData::PlainText(v) => _Data::PlainText(v.into_string()),
LoadedData::RadarGridData(v) => Data::RadarGridData(Rc::new(v.into())), LoadedData::RadarGridData(v) => _Data::RadarGridData(Arc::new(v.into())),
} }
} }
} }
impl From<LoadedData> 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<RadarGridData> {
// 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<RadarGridData> {
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(),
};
}
}