306 lines
9.4 KiB
Rust
306 lines
9.4 KiB
Rust
use crate::{
|
|
data::{self, CoordType, Radar2d},
|
|
plugin_system::init_plugin,
|
|
render::{predefined::color_mapper::BoundaryNorm, Layer},
|
|
PLUGIN_MANAGER,
|
|
};
|
|
|
|
use super::{
|
|
control_panel::{ControlPanelInputMsg, ControlPanelModel},
|
|
messages::MonitorInputMsg,
|
|
monitor::MonitorModel,
|
|
setting::SettingModel,
|
|
TimelineMsg,
|
|
};
|
|
use abi_stable::std_types::RStr;
|
|
use chrono::{DateTime, Duration, Utc};
|
|
use gtk::{
|
|
prelude::{ApplicationExt, BoxExt, GtkWindowExt, WidgetExt},
|
|
traits::OrientableExt,
|
|
};
|
|
use ndarray::{Array1, Array2, Array3};
|
|
use radarg_plugin_interface::{Block, DataShape, PluginId, VecResult};
|
|
use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
|
|
use relm4::*;
|
|
use relm4::{gtk, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent};
|
|
use relm4_components::open_dialog::{
|
|
OpenDialog, OpenDialogMsg, OpenDialogResponse, OpenDialogSettings,
|
|
};
|
|
|
|
relm4::new_action_group!(FileActionGroup, "file");
|
|
relm4::new_stateless_action!(OpenAction, FileActionGroup, "open");
|
|
|
|
#[derive(Debug)]
|
|
pub enum AppMsg {
|
|
CloseRequest,
|
|
Close,
|
|
OpenDialog,
|
|
OpenDialogMulti,
|
|
OpenFile((DateTime<Utc>, Layer)),
|
|
}
|
|
|
|
pub struct AppModel {
|
|
open_dialog: Controller<OpenDialog>,
|
|
control: Controller<ControlPanelModel>,
|
|
render: Controller<MonitorModel>,
|
|
setting: Controller<SettingModel>,
|
|
}
|
|
|
|
#[relm4::component(pub)]
|
|
impl SimpleComponent for AppModel {
|
|
type Init = ();
|
|
type Input = AppMsg;
|
|
type Output = ();
|
|
|
|
view! {
|
|
#[root]
|
|
main_window=adw::ApplicationWindow {
|
|
set_default_width: 1200,
|
|
set_default_height: 900,
|
|
set_focus_on_click:true,
|
|
connect_close_request[sender,app] => move |_| {
|
|
sender.input(AppMsg::CloseRequest);
|
|
app.quit();
|
|
gtk::Inhibit(true)
|
|
},
|
|
gtk::Box{
|
|
set_orientation: gtk::Orientation::Vertical,
|
|
set_valign:gtk::Align::Fill,
|
|
set_spacing:2,
|
|
gtk::HeaderBar{
|
|
pack_start=&adw::ViewSwitcher{
|
|
set_stack: Some(&view_stack),
|
|
}
|
|
},
|
|
|
|
#[name="view_stack"]
|
|
adw::ViewStack{
|
|
set_hexpand:true,
|
|
set_vexpand:true,
|
|
},
|
|
},
|
|
|
|
connect_close_request[sender] => move |_| {
|
|
sender.input(AppMsg::CloseRequest);
|
|
gtk::Inhibit(true)
|
|
}
|
|
},
|
|
popover_child = gtk::Spinner {
|
|
set_spinning: true,
|
|
},
|
|
}
|
|
|
|
menu! {
|
|
main_menu: {
|
|
"File" {
|
|
"Open" => OpenAction,
|
|
"Open Folder" => OpenAction,
|
|
},
|
|
"Edit" {
|
|
"New Layer" => OpenAction,
|
|
"Undo" => OpenAction,
|
|
"Redo" => OpenAction,
|
|
},
|
|
"Plugins" {
|
|
"Plugin1" => OpenAction,
|
|
"Plugin2" => OpenAction,
|
|
},
|
|
}
|
|
}
|
|
|
|
fn init(
|
|
params: Self::Init,
|
|
root: &Self::Root,
|
|
sender: ComponentSender<Self>,
|
|
) -> ComponentParts<Self> {
|
|
let control = ControlPanelModel::builder()
|
|
.launch(0)
|
|
.forward(sender.input_sender(), |msg| AppMsg::Close);
|
|
|
|
let render = MonitorModel::builder()
|
|
.launch(())
|
|
.forward(sender.input_sender(), |a| AppMsg::Close);
|
|
|
|
let setting = SettingModel::builder()
|
|
.launch(())
|
|
.forward(sender.input_sender(), |a| AppMsg::Close);
|
|
|
|
let dialog = OpenDialog::builder()
|
|
.transient_for_native(&root)
|
|
.launch(OpenDialogSettings::default())
|
|
.forward(sender.input_sender(), |response| match response {
|
|
OpenDialogResponse::Accept(path) => {
|
|
let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap();
|
|
let mut result = plugin.load(RStr::from_str(path.to_str().unwrap())).unwrap();
|
|
let mut block = result.blocks.pop().unwrap();
|
|
data_to_grid_layer(block)
|
|
}
|
|
OpenDialogResponse::Cancel => AppMsg::Close,
|
|
});
|
|
|
|
let app = relm4::main_application();
|
|
relm4_icons::initialize_icons();
|
|
|
|
let model = AppModel {
|
|
open_dialog: dialog,
|
|
control,
|
|
render,
|
|
setting,
|
|
};
|
|
|
|
let widgets = view_output!();
|
|
let mut group = RelmActionGroup::<FileActionGroup>::new();
|
|
|
|
let page_home = gtk::Box::builder()
|
|
.hexpand(true)
|
|
.vexpand(true)
|
|
.orientation(gtk::Orientation::Vertical)
|
|
.build();
|
|
|
|
let setting_bar = gtk::Box::builder()
|
|
.orientation(gtk::Orientation::Horizontal)
|
|
.margin_top(2)
|
|
.margin_start(10)
|
|
.margin_end(10)
|
|
.build();
|
|
let popover_menu_bar = gtk::PopoverMenuBar::from_model(Some(&main_menu));
|
|
popover_menu_bar.set_hexpand(true);
|
|
setting_bar.append(&popover_menu_bar);
|
|
page_home.append(&setting_bar);
|
|
page_home.append(model.control.widget());
|
|
page_home.append(model.render.widget());
|
|
|
|
let view_stack = widgets.view_stack.clone();
|
|
let page_home = view_stack.add_titled(&page_home, Some("renderer"), "Render");
|
|
page_home.set_icon_name(Some("home-filled"));
|
|
|
|
|
|
let page_setting = model.setting.widget();
|
|
|
|
let page_setting = view_stack.add_titled(page_setting, Some("setting"), "Setting");
|
|
page_setting.set_icon_name(Some("settings-filled"));
|
|
|
|
app.set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
|
|
let action: RelmAction<OpenAction> = {
|
|
RelmAction::new_stateless(move |_| {
|
|
sender.input(AppMsg::OpenDialog);
|
|
})
|
|
};
|
|
group.add_action(action);
|
|
group.register_for_widget(&widgets.main_window);
|
|
|
|
ComponentParts { model, widgets }
|
|
}
|
|
|
|
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
|
match msg {
|
|
AppMsg::OpenFile((time, layer)) => {
|
|
self.render.sender().emit(MonitorInputMsg::AddLayer(layer));
|
|
self.control
|
|
.sender()
|
|
.emit(ControlPanelInputMsg::Selection(Some(time)));
|
|
self.control
|
|
.sender()
|
|
.emit(ControlPanelInputMsg::TimeLine(TimelineMsg::SetStart(
|
|
time - Duration::minutes(30),
|
|
)));
|
|
}
|
|
AppMsg::CloseRequest => {}
|
|
AppMsg::Close => {}
|
|
AppMsg::OpenDialog => {
|
|
self.open_dialog.emit(OpenDialogMsg::Open);
|
|
}
|
|
AppMsg::OpenDialogMulti => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! match_in_macro {
|
|
($block:ident,$name:literal, $(($branch:path, $t:ty, $color:expr)),+) => {
|
|
{
|
|
match $block.data_type {
|
|
$(
|
|
$branch => {
|
|
let data: $t = $block.into();
|
|
let layer = Layer::grid_render_layer(data, format!($name), $color);
|
|
AppMsg::OpenFile((Utc::now() ,layer))
|
|
},
|
|
)+
|
|
_ => AppMsg::Close,
|
|
}
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
fn data_to_grid_layer(block: Block) -> AppMsg {
|
|
use crate::utils::*;
|
|
use radarg_plugin_interface::PluginResultType;
|
|
match block.shape {
|
|
DataShape::Matrix => match_in_macro!(
|
|
block,
|
|
"DBZ",
|
|
(
|
|
PluginResultType::DBZ,
|
|
Radar2d<i8>,
|
|
create_dbz_boundarynorm()
|
|
),
|
|
(PluginResultType::R, Radar2d<i8>, create_dbz_boundarynorm()),
|
|
(PluginResultType::V, Radar2d<f32>, create_vel_boundarynorm()),
|
|
(
|
|
PluginResultType::ZDR,
|
|
Radar2d<f32>,
|
|
create_zdr_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::PHIDP,
|
|
Radar2d<f32>,
|
|
create_phidp_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::KDP,
|
|
Radar2d<f32>,
|
|
create_kdp_boundarynorm()
|
|
),
|
|
(PluginResultType::CC, Radar2d<f32>, create_cc_boundarynorm()),
|
|
(
|
|
PluginResultType::HCA,
|
|
Radar2d<i8>,
|
|
create_cpc_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::QPE,
|
|
Radar2d<f32>,
|
|
create_vil_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::QPF,
|
|
Radar2d<f32>,
|
|
create_vil_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::VIL,
|
|
Radar2d<f32>,
|
|
create_vil_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::OHP,
|
|
Radar2d<f32>,
|
|
create_vil_boundarynorm()
|
|
),
|
|
(
|
|
PluginResultType::THP,
|
|
Radar2d<f32>,
|
|
create_vil_boundarynorm()
|
|
),
|
|
(PluginResultType::ET, Radar2d<f32>, create_et_boundarynorm()),
|
|
(
|
|
PluginResultType::EB,
|
|
Radar2d<f32>,
|
|
create_hgt_boundarynorm()
|
|
)
|
|
),
|
|
_ => AppMsg::Close,
|
|
}
|
|
}
|