radar-g/src/components/app.rs
2024-01-30 00:35:21 +08:00

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,
}
}