end: system

This commit is contained in:
Tsuki 2024-03-07 18:08:16 +08:00
parent 558bc68d81
commit 53d5b6a57f
12 changed files with 330 additions and 151 deletions

View File

@ -32,3 +32,10 @@ paned>separator {
.lv { .lv {
background: transparent; background: transparent;
} }
row:selected {
background: #313131;
color: #fff;
border-radius: 5px;
}

View File

@ -5,8 +5,12 @@ use super::{
setting::SettingModel, setting::SettingModel,
ControlPanelOutputMsg, TimelineMsg, ControlPanelOutputMsg, TimelineMsg,
}; };
use crate::pipeline::element::{Element, InstantElement, InstantElementDrawerType};
use crate::data_utils::plugin_result_impl; use crate::data_utils::plugin_result_impl;
use crate::pipeline::element::{
Element, InstantElement, InstantElementDrawerType, TimeSeriesElement,
};
use crate::pipeline::{GridElementImpl, OffscreenRenderer};
use crate::widgets::AssoElement;
use crate::{ use crate::{
coords::{ coords::{
cms::CMS, cms::CMS,
@ -27,6 +31,7 @@ use futures::future::BoxFuture;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use radarg_plugin_interface::PluginResult;
use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup}; use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
use relm4::*; use relm4::*;
use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent}; use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent};
@ -34,6 +39,7 @@ use relm4_components::open_dialog::{
OpenDialog, OpenDialogMsg, OpenDialogResponse, OpenDialogSettings, OpenDialog, OpenDialogMsg, OpenDialogResponse, OpenDialogSettings,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::marker::PhantomData;
use std::{ use std::{
any::Any, any::Any,
borrow::{Borrow, BorrowMut}, borrow::{Borrow, BorrowMut},
@ -43,11 +49,9 @@ use std::{
rc::Rc, rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use radarg_plugin_interface::PluginResult;
use tokio::{sync::oneshot, task}; use tokio::{sync::oneshot, task};
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
use crate::pipeline::{GridElementImpl, OffscreenRenderer}; use tracing_subscriber::fmt::layer;
use crate::widgets::AssoElement;
relm4::new_action_group!(FileActionGroup, "file"); relm4::new_action_group!(FileActionGroup, "file");
relm4::new_stateless_action!(OpenAction, FileActionGroup, "open"); relm4::new_stateless_action!(OpenAction, FileActionGroup, "open");
@ -60,6 +64,7 @@ pub enum AppMsg {
CloseRequest, CloseRequest,
Close, Close,
OpenDialog, OpenDialog,
SwitchToTime(usize),
NewElement(Element), NewElement(Element),
DeleteElement(ElementKey), DeleteElement(ElementKey),
NewLayer(Layer), NewLayer(Layer),
@ -71,7 +76,7 @@ pub struct AppModel {
#[do_not_track] #[do_not_track]
dispatcher: RcDispatcher, dispatcher: RcDispatcher,
#[do_not_track] #[do_not_track]
cms: Arc<Mutex<CMS>>, cms: CMS,
waiting_for: Option<DateTime<Utc>>, waiting_for: Option<DateTime<Utc>>,
#[do_not_track] #[do_not_track]
open_dialog: Controller<OpenDialog>, open_dialog: Controller<OpenDialog>,
@ -82,7 +87,7 @@ pub struct AppModel {
#[do_not_track] #[do_not_track]
layers: Rc<RefCell<Vec<Layer>>>, layers: Rc<RefCell<Vec<Layer>>>,
#[do_not_track] #[do_not_track]
elements: Vec<Arc<Mutex<Element>>>, elements: Vec<Arc<Mutex<TimeSeriesElement>>>,
#[do_not_track] #[do_not_track]
setting: Controller<SettingModel>, setting: Controller<SettingModel>,
} }
@ -187,17 +192,11 @@ 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::with_capacity(20)));
let layers = Rc::new(RefCell::new(vec![ let control = ControlPanelModel::builder().launch(layers.clone()).forward(
Layer::new(true, "Layer1".to_string(), AssoElement::Test),
]));
let control = ControlPanelModel::builder().launch(0).forward(
sender.input_sender(), sender.input_sender(),
|msg| match msg { |msg| match msg {
ControlPanelOutputMsg::OpenFile((key, time)) => { ControlPanelOutputMsg::OpenFile((key, time)) => AppMsg::Close,
// AppMsg::SwitchTo((key, time, None, None))
AppMsg::Close
}
}, },
); );
let render = let render =
@ -205,38 +204,40 @@ impl Component for AppModel {
.launch(layers.clone()) .launch(layers.clone())
.forward(sender.input_sender(), |a| match a { .forward(sender.input_sender(), |a| match a {
MonitorOutputMsg::LayerRenderFinished => AppMsg::Close, MonitorOutputMsg::LayerRenderFinished => AppMsg::Close,
MonitorOutputMsg::LayerSwitchToTime(idx) => AppMsg::SwitchToTime(idx),
_ => AppMsg::Close, _ => AppMsg::Close,
}); });
let setting = SettingModel::builder() let setting = SettingModel::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |a| AppMsg::Close); .forward(sender.input_sender(), |a| AppMsg::Close);
let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1))); let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
let cms = Arc::new(Mutex::new(CMS::new( let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
Mercator::default().into(),
(3000.0, 3000.0),
)));
let dialog_dispatcher = dispatcher.clone(); let dialog_dispatcher = dispatcher.clone();
let dialog_cms = cms.clone(); let dialog_render_sender = render.sender().clone();
let dialog = OpenDialog::builder() let dialog = OpenDialog::builder()
.transient_for_native(&root) .transient_for_native(&root)
.launch(OpenDialogSettings::default()) .launch(OpenDialogSettings::default())
.forward(sender.input_sender(), move |response| match response { .forward(sender.input_sender(), move |response| match response {
OpenDialogResponse::Accept(path) => { OpenDialogResponse::Accept(path) => {
*FILE_PATH_ROOT.lock().unwrap() = path.clone();
let data = Self::open_file_only(path); let data = Self::open_file_only(path);
let meta: MetaInfo = (&data.meta).clone().into();
let element_impl = plugin_result_impl(&data); let element_impl = plugin_result_impl(&data);
let mut renderer = OffscreenRenderer::new(3000,3000).unwrap(); let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap();
let mut canvas = renderer.create_canvas(); let mut canvas = renderer.create_canvas();
let mut cms_ref = dialog_cms.lock().unwrap(); let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
let mut data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms);
let mut data_target = element_impl.render(&data,&mut canvas,&mut (*cms_ref));
data_target.data = Some(Arc::new(data) as Arc<dyn Any + Send + Sync + 'static>); data_target.data = Some(Arc::new(data) as Arc<dyn Any + Send + Sync + 'static>);
let element = Element::create_instant( let element = Element::create_instant(
InstantElementDrawerType::Prepared(data_target), InstantElementDrawerType::Prepared((data_target, Arc::new(element_impl))),
dialog_dispatcher.clone(), dialog_dispatcher.clone(),
"New Element".to_string(), "ET".to_string(),
).get_instance(); )
let layer = Layer::new(true, "New Layer".to_string(), AssoElement::Instant(element)); .get_instance();
let layer =
Layer::new(true, "New Layer".to_string(), AssoElement::Instant(element));
dialog_render_sender.emit(MonitorInputMsg::AddMetaItem(meta.to_map()));
AppMsg::NewLayer(layer) AppMsg::NewLayer(layer)
} }
_ => AppMsg::Close, _ => AppMsg::Close,
@ -252,7 +253,7 @@ impl Component for AppModel {
open_dialog: dialog, open_dialog: dialog,
control, control,
render, render,
layers , layers,
setting, setting,
tracker: 0, tracker: 0,
}; };
@ -279,13 +280,6 @@ impl Component for AppModel {
) { ) {
self.reset(); self.reset();
match msg { match msg {
AppMsg::NewElement(element) => {
let (key, id) = (element.key(), element.id());
let element = Arc::new(Mutex::new(element));
self.elements.push(element.clone());
// let layer = Layer::new(true, key, Some(element));
// _sender.input(AppMsg::NewLayer(layer));
}
AppMsg::NewLayer(layer) => { AppMsg::NewLayer(layer) => {
(*self.layers).borrow_mut().push(layer); (*self.layers).borrow_mut().push(layer);
self.render.sender().send(MonitorInputMsg::RefreshLayerList); self.render.sender().send(MonitorInputMsg::RefreshLayerList);
@ -294,6 +288,23 @@ impl Component for AppModel {
relm4::main_application().quit(); relm4::main_application().quit();
} }
AppMsg::Close => {} AppMsg::Close => {}
AppMsg::SwitchToTime(idx) => {
let mut layer = (*self.layers).borrow_mut();
let switched_layer = layer.get_mut(idx).unwrap();
let asso_element = switched_layer.pop_associated_element();
if let AssoElement::Instant(e) = asso_element {
let dispatcher = self.dispatcher.clone();
let cms = self.cms.clone();
let (mut series, start_time) = e.to_time_series(dispatcher, cms);
switched_layer.set_time(start_time);
series.register(start_time).unwrap();
let element = Arc::new(Mutex::new(series));
switched_layer.set_associated_element(AssoElement::TimeSeries(element.clone()));
self.elements.push(element);
}
self.render.sender().send(MonitorInputMsg::RefreshLayerList);
}
AppMsg::OpenDialog => { AppMsg::OpenDialog => {
self.open_dialog.emit(OpenDialogMsg::Open); self.open_dialog.emit(OpenDialogMsg::Open);
} }
@ -321,7 +332,7 @@ impl AppModel {
fn open_file( fn open_file(
path: impl AsRef<std::path::Path>, path: impl AsRef<std::path::Path>,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<Dispatcher>,
cms: Arc<Mutex<CMS>>, cms: CMS,
) -> Option<(Option<Box<dyn Any + Send + Sync>>, Element)> { ) -> Option<(Option<Box<dyn Any + Send + Sync>>, Element)> {
let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap();
let mut result = plugin let mut result = plugin
@ -332,9 +343,7 @@ impl AppModel {
.map(|v| (Some(Box::new(result) as Box<dyn Any + Send + Sync>), v)) .map(|v| (Some(Box::new(result) as Box<dyn Any + Send + Sync>), v))
} }
fn open_file_only( fn open_file_only(path: impl AsRef<std::path::Path>) -> PluginResult {
path: impl AsRef<std::path::Path>,
) -> PluginResult {
let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap();
let mut result = plugin let mut result = plugin
.load(RStr::from_str(path.as_ref().to_str().unwrap())) .load(RStr::from_str(path.as_ref().to_str().unwrap()))

View File

@ -1,3 +1,4 @@
use std::cell::{Ref, RefCell};
use super::messages::*; use super::messages::*;
use super::thumbnail::{ImgItem, TypedListView}; use super::thumbnail::{ImgItem, TypedListView};
use crate::data::{CoordType, Radar2d, RadarData2d}; use crate::data::{CoordType, Radar2d, RadarData2d};
@ -16,6 +17,7 @@ use relm4::prelude::*;
use relm4_components::open_button::{OpenButton, OpenButtonSettings}; use relm4_components::open_button::{OpenButton, OpenButtonSettings};
use relm4_components::open_dialog::OpenDialogSettings; use relm4_components::open_dialog::OpenDialogSettings;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc;
#[tracker::track] #[tracker::track]
#[derive(Debug)] #[derive(Debug)]
@ -25,13 +27,15 @@ pub struct ControlPanelModel {
timeline_start: DateTime<Utc>, timeline_start: DateTime<Utc>,
selection: Option<DateTime<Utc>>, selection: Option<DateTime<Utc>>,
key: Option<String>, key: Option<String>,
#[do_not_track]
layers: Rc<RefCell<Vec<Layer>>>,
#[tracker::no_eq] #[tracker::no_eq]
list_img_wrapper: TypedListView<ImgItem, gtk::SingleSelection>, list_img_wrapper: TypedListView<ImgItem, gtk::SingleSelection>,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for ControlPanelModel { impl SimpleComponent for ControlPanelModel {
type Init = i8; type Init = Rc<RefCell<Vec<Layer>>>;
type Output = ControlPanelOutputMsg; type Output = ControlPanelOutputMsg;
type Input = ControlPanelInputMsg; type Input = ControlPanelInputMsg;
@ -56,11 +60,18 @@ impl SimpleComponent for ControlPanelModel {
add_css_class:"h2", add_css_class:"h2",
set_halign: gtk::Align::Start, set_halign: gtk::Align::Start,
}, },
gtk::Label{ #[local]
set_label: "Subheader", layer_controller_selection -> gtk::DropDown{
add_css_class:"h3", set_expression:None::<&gtk::Expression>,
set_halign: gtk::Align::Start, connect_selected_notify[sender] => move |step_selector| {
println!("Selected: {}", step_selector.selected());
},
} }
// gtk::Label{
// set_label: "Subheader",
// add_css_class:"h3",
// set_halign: gtk::Align::Start,
// }
}, },
#[local] #[local]
step_selector -> gtk::DropDown{ step_selector -> gtk::DropDown{
@ -220,11 +231,13 @@ impl SimpleComponent for ControlPanelModel {
key: None, key: None,
enabled: true, enabled: true,
selection: None, selection: None,
layers: init,
timeline_start, timeline_start,
list_img_wrapper, list_img_wrapper,
tracker: 0, tracker: 0,
}; };
let layer_controller_selection = gtk::DropDown::from_strings(&[]);
let my_view = &model.list_img_wrapper.view; let my_view = &model.list_img_wrapper.view;
let widgets = view_output!(); let widgets = view_output!();

View File

@ -43,6 +43,7 @@ pub enum MonitorOutputMsg {
LayerAdded(usize), LayerAdded(usize),
LayerRemoved(usize), LayerRemoved(usize),
LayerUpdated(usize), LayerUpdated(usize),
LayerSwitchToTime(usize),
LayerRenderFinished, LayerRenderFinished,
} }

View File

@ -153,10 +153,15 @@ impl Component for MonitorModel {
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let sidebar_sender = sender.clone();
let sidebar: Controller<SideBarModel> = SideBarModel::builder() let sidebar: Controller<SideBarModel> = SideBarModel::builder()
.launch(init.clone()) .launch(init.clone())
.forward(sender.input_sender(), |msg| match msg { .forward(sender.input_sender(), move |msg| match msg {
SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer), SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer),
SideBarOutputMsg::SwitchToTimeSeries(layer) => {
sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer));
MonitorInputMsg::None
}
_ => MonitorInputMsg::None, _ => MonitorInputMsg::None,
}); });

View File

@ -10,7 +10,9 @@ use relm4::{
RelmObjectExt, RelmObjectExt,
}; };
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
use chrono::{DateTime, Utc};
use relm4::actions::{AccelsPlus, RelmAction}; use relm4::actions::{AccelsPlus, RelmAction};
use crate::widgets::AssoElement;
use crate::{ use crate::{
chart::Chart, chart::Chart,
@ -25,8 +27,8 @@ use super::{
}; };
relm4::new_action_group!(LayerActionGroup, "layer"); relm4::new_action_group!(LayerActionGroup, "layer");
// relm4::new_stateless_action!(ToTime, LayerActionGroup, "to_time"); relm4::new_stateful_action!(ToTime, LayerActionGroup, "to_time", u32, ());
relm4::new_stateful_action!(ToTime, LayerActionGroup, "to_time", u32, u32); relm4::new_stateless_action!(BeTime, LayerActionGroup, "be_time");
pub struct SideBarModel { pub struct SideBarModel {
layers: Rc<RefCell<Vec<Layer>>>, layers: Rc<RefCell<Vec<Layer>>>,
counter: u8, counter: u8,
@ -135,14 +137,19 @@ impl SimpleComponent for SideBarModel {
let mut group = relm4::actions::RelmActionGroup::<LayerActionGroup>::new(); let mut group = relm4::actions::RelmActionGroup::<LayerActionGroup>::new();
let action: RelmAction<ToTime> = { let action: RelmAction<ToTime> = {
RelmAction::new_stateful_with_target_value(&0, |_, state, _value| { RelmAction::new_stateful_with_target_value(&(), move |_, state, _value| {
*state ^= 1; sender.output(SideBarOutputMsg::SwitchToTimeSeries(_value as usize)).unwrap()
dbg!(state);
}) })
}; };
let action2:RelmAction<BeTime> = RelmAction::new_stateless(|_| {
dbg!("be time");
});
group.add_action(action); group.add_action(action);
group.register_for_main_application(); group.add_action(action2);
let app = relm4::main_application();
group.register_for_widget(root);
{ {
let mut bottom_bar_vec_guard = bottom_bar_vec.guard(); let mut bottom_bar_vec_guard = bottom_bar_vec.guard();
@ -168,12 +175,19 @@ impl SimpleComponent for SideBarModel {
let columns = model.meta_list_view.get_columns(); let columns = model.meta_list_view.get_columns();
let info_c = columns.get("info").unwrap(); let info_c = columns.get("info").unwrap();
let widgets = view_output!(); let widgets = view_output!();
{ {
let mut list = model let mut list = model
.layers .layers
.borrow() .borrow()
.iter() .iter()
.map(|v| LayerItem::new(v.name.clone(), v.visiable, v.get_thumbnail())) .enumerate()
.map(|(idx, v)| LayerItem::new(idx as u32,v.name.clone(), v.visiable, v.get_thumbnail(), match v.get_associated_element() {
AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
AssoElement::Instant(_) => LayerStatus::Instance,
_ => LayerStatus::Instance
}))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
model.list_view_wrapper.extend_from_iter(list); model.list_view_wrapper.extend_from_iter(list);
} }
@ -188,7 +202,13 @@ impl SimpleComponent for SideBarModel {
.layers .layers
.borrow() .borrow()
.iter() .iter()
.map(|v| LayerItem::new(v.name.clone(), v.visiable, v.get_thumbnail())) .enumerate()
.map(|(idx, v)| LayerItem::new(idx as u32,v.name.clone(), v.visiable, v.get_thumbnail(),match v.get_associated_element() {
AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
AssoElement::Instant(_) => LayerStatus::Instance,
_ => LayerStatus::Instance
}))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.list_view_wrapper.clear(); self.list_view_wrapper.clear();
self.list_view_wrapper.extend_from_iter(list); self.list_view_wrapper.extend_from_iter(list);
@ -206,18 +226,29 @@ impl SimpleComponent for SideBarModel {
} }
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum LayerStatus {
BindToTime(DateTime<Utc>),
Instance,
BindToOtherLayer(usize)
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct LayerItem { struct LayerItem {
key: u32,
layer_name: String, layer_name: String,
visiable: bool, visiable: bool,
status: LayerStatus,
img: Option<gtk::gdk::Texture>, img: Option<gtk::gdk::Texture>,
} }
impl LayerItem { impl LayerItem {
fn new(name: String, visiable: bool, img: Option<gtk::gdk::Texture>) -> Self { fn new(key: u32,name: String, visiable: bool, img: Option<gtk::gdk::Texture>, status: LayerStatus) -> Self {
Self { Self {
key,
layer_name: name, layer_name: name,
visiable, visiable,
status,
img, img,
} }
} }
@ -226,6 +257,7 @@ impl LayerItem {
struct Widgets { struct Widgets {
label: gtk::Label, label: gtk::Label,
screen_shot: gtk::Image, screen_shot: gtk::Image,
status: gtk::Label,
button: gtk::CheckButton, button: gtk::CheckButton,
menu: gtk::PopoverMenu, menu: gtk::PopoverMenu,
} }
@ -237,9 +269,11 @@ impl RelmListItem for LayerItem {
fn setup(_item: &gtk::ListItem) -> (gtk::Box, Widgets) { fn setup(_item: &gtk::ListItem) -> (gtk::Box, Widgets) {
relm4::menu! { relm4::menu! {
main_menu: { main_menu: {
"Bind To Time" => ToTime(_item.position()) "Bind To Time" => ToTime(0),
"Be Time" => BeTime,
} }
} }
relm4::view! { relm4::view! {
my_box = gtk::Box { my_box = gtk::Box {
gtk::Frame{ gtk::Frame{
@ -253,6 +287,10 @@ impl RelmListItem for LayerItem {
gtk::Label{ gtk::Label{
set_halign: gtk::Align::Start, set_halign: gtk::Align::Start,
}, },
#[name = "status"]
gtk::Label{
set_halign: gtk::Align::Start
},
gtk::Label{ gtk::Label{
set_hexpand: true, set_hexpand: true,
}, },
@ -268,6 +306,7 @@ impl RelmListItem for LayerItem {
let widgets = Widgets { let widgets = Widgets {
screen_shot, screen_shot,
label, label,
status,
button, button,
menu, menu,
}; };
@ -276,13 +315,29 @@ impl RelmListItem for LayerItem {
} }
fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) { fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
let Widgets { let Widgets {
label, label,
button, button,
screen_shot, screen_shot,
status,
menu, menu,
} = widgets; } = widgets;
relm4::menu! {
main_menu: {
"Bind To Time" => ToTime(self.key),
"Be Time" => BeTime,
}
}
menu.set_menu_model(Some(&main_menu));
status.set_label(&match self.status {
LayerStatus::BindToTime(t) => format!("Bind To Time: {}", t),
LayerStatus::Instance => "Instance".to_string(),
LayerStatus::BindToOtherLayer(idx) => format!("Bind To Layer: {}", idx)
});
let gesture_click = gtk::GestureClick::new(); let gesture_click = gtk::GestureClick::new();
gesture_click.set_button(gtk::gdk::BUTTON_SECONDARY); gesture_click.set_button(gtk::gdk::BUTTON_SECONDARY);
screen_shot.set_paintable(self.img.as_ref()); screen_shot.set_paintable(self.img.as_ref());
@ -294,7 +349,7 @@ impl RelmListItem for LayerItem {
})); }));
_root.add_controller(gesture_click); _root.add_controller(gesture_click);
label.set_label(&format!("Layer: {} ", &self.layer_name)); label.set_label(&self.layer_name);
button.set_active(self.visiable); button.set_active(self.visiable);
} }
} }

View File

@ -2,7 +2,7 @@ use std::ops::Range;
use geo_types::LineString; use geo_types::LineString;
use crate::coords::Mapper; use crate::coords::Mapper;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct CMS { pub struct CMS {
mapper: Mapper, mapper: Mapper,
window_size: (f32, f32), window_size: (f32, f32),

View File

@ -108,8 +108,7 @@ impl Dispatcher {
check_existed: bool, check_existed: bool,
mut max_retry_time: usize, mut max_retry_time: usize,
) -> Option<Vec<(String, DateTime<Utc>)>> { ) -> Option<Vec<(String, DateTime<Utc>)>> {
let datetime_format: regex::Regex = let datetime_format: regex::Regex = Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap();
Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap();
let config = CONFIG.lock().unwrap(); let config = CONFIG.lock().unwrap();
let path_format = config let path_format = config
.plugins .plugins
@ -158,12 +157,10 @@ impl Dispatcher {
} }
if check_existed { if check_existed {
if max_retry_time == 0 { // if max_retry_time == 0 {
break; // break;
} // }
if !std::path::Path::new(&result_path).exists() { if !std::path::Path::new(&result_path).exists() {
max_retry_time = max_retry_time - 1;
continue;
} else { } else {
result_paths.push((result_path.clone(), t)); result_paths.push((result_path.clone(), t));
} }
@ -183,12 +180,10 @@ impl Dispatcher {
} }
if check_existed { if check_existed {
if max_retry_time == 0 { // if max_retry_time == 0 {
break; // break;
} // }
if !std::path::Path::new(&result_path).exists() { if !std::path::Path::new(&result_path).exists() {
max_retry_time = max_retry_time - 1;
continue;
} else { } else {
result_paths.push((result_path.clone(), t)); result_paths.push((result_path.clone(), t));
} }

View File

@ -4,12 +4,15 @@ use crate::components::ControlPanelInputMsg;
use crate::coords::cms::CMS; use crate::coords::cms::CMS;
use crate::data::MetaInfo; use crate::data::MetaInfo;
use crate::errors::{PipelineError, RenderError}; use crate::errors::{PipelineError, RenderError};
use crate::widgets::Render;
use crate::RUNTIME; use crate::RUNTIME;
use crate::{coords::Range, widgets::widget::Widget}; use crate::{coords::Range, widgets::widget::Widget};
use chrono::{DateTime, Utc}; use chrono::{DateTime, TimeZone, Utc};
use core_extensions::SelfOps;
use femtovg::{renderer::OpenGl, Canvas, ImageId}; use femtovg::{renderer::OpenGl, Canvas, ImageId};
use futures::StreamExt; use futures::StreamExt;
use glib::PropertyGet; use glib::PropertyGet;
use radarg_plugin_interface::PluginResult;
use std::any::Any; use std::any::Any;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
@ -23,21 +26,17 @@ use std::{
pin::Pin, pin::Pin,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use core_extensions::SelfOps;
use radarg_plugin_interface::PluginResult;
use tokio::sync::{ use tokio::sync::{
oneshot::{channel, Receiver, Sender}, oneshot::{channel, Receiver, Sender},
Notify, Notify,
}; };
use tracing::Instrument; use tracing::Instrument;
use crate::widgets::Render;
pub type ElementID = usize; pub type ElementID = usize;
static ELEMENT_ID: AtomicUsize = AtomicUsize::new(0); static ELEMENT_ID: AtomicUsize = AtomicUsize::new(0);
pub type Data = Box<dyn Any + Send + Sync>; pub type Data = Box<dyn Any + Send + Sync>;
pub type Buffer = pub type Buffer = Arc<Mutex<BTreeMap<DateTime<Utc>, Option<RenderResult>>>>;
Arc<Mutex<BTreeMap<DateTime<Utc>, (Option<Data>, Option<RenderResult>)>>>;
type DrawFunc = Rc<Box<dyn Fn(&Render)>>; type DrawFunc = Rc<Box<dyn Fn(&Render)>>;
type IResult<T> = Result<T, PipelineError>; type IResult<T> = Result<T, PipelineError>;
@ -48,11 +47,11 @@ pub enum Element {
} }
impl Element { impl Element {
pub fn create_time_series<T: ElementImpl>( pub fn create_time_series(
imp: T, imp: Arc<Box<dyn ElementImpl>>,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<Dispatcher>,
key: String, key: String,
cms: Arc<Mutex<CMS>>, cms: CMS,
) -> Self { ) -> Self {
Element::TimeSeries(TimeSeriesElement::new(imp, dispatcher, cms, key)) Element::TimeSeries(TimeSeriesElement::new(imp, dispatcher, cms, key))
} }
@ -80,7 +79,7 @@ impl Element {
pub fn get_instance(mut self) -> InstantElement { pub fn get_instance(mut self) -> InstantElement {
match self { match self {
Element::TimeSeries(e) => panic!("TimeSeries element does not have instance"), Element::TimeSeries(e) => panic!("TimeSeries element does not have instance"),
Element::Instant(v) => v Element::Instant(v) => v,
} }
} }
@ -95,18 +94,18 @@ impl Element {
pub struct TimeSeriesElement { pub struct TimeSeriesElement {
pub id: ElementID, pub id: ElementID,
pub key: String, pub key: String,
cms: Arc<Mutex<CMS>>, cms: CMS,
imp: Arc<dyn ElementImpl>, imp: Arc<Box<dyn ElementImpl>>,
registers: Arc<Mutex<HashMap<DateTime<Utc>, Vec<Arc<Notify>>>>>, registers: Arc<Mutex<HashMap<DateTime<Utc>, Vec<Arc<Notify>>>>>,
pipeline: Pipeline, pipeline: Pipeline,
buffer: Buffer, pub buffer: Buffer,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<Dispatcher>,
} }
#[derive(Clone)] #[derive(Clone)]
pub enum InstantElementDrawerType { pub enum InstantElementDrawerType {
Draw(DrawFunc), Draw(DrawFunc),
Prepared(Target), Prepared((Target, Arc<Box<dyn ElementImpl>>)),
} }
impl Debug for InstantElementDrawerType { impl Debug for InstantElementDrawerType {
@ -141,44 +140,67 @@ impl InstantElement {
InstantElementDrawerType::Draw(ref func) => { InstantElementDrawerType::Draw(ref func) => {
func(render); func(render);
} }
InstantElementDrawerType::Prepared(ref mut target) => { InstantElementDrawerType::Prepared((ref mut target, _)) => {
let mut canvas = render.get_canvas(); let mut canvas = render.get_canvas();
let mut canvas = canvas.as_mut().unwrap(); let mut canvas = canvas.as_mut().unwrap();
let (ox,oy) = target.origin(render); let (ox, oy) = target.origin(render);
let (x,y) = target.size(render); let (x, y) = target.size(render);
let result_id = match target.target { let result_id = match target.target {
TargetType::ImageId(id) => id, TargetType::ImageId(id) => id,
TargetType::Mem(ref mem) => { TargetType::Mem(ref mem) => {
let converted = canvas.load_image_mem(mem, femtovg::ImageFlags::empty()).unwrap(); let converted = canvas
.load_image_mem(mem, femtovg::ImageFlags::empty())
.unwrap();
target.set_target(TargetType::ImageId(converted)); target.set_target(TargetType::ImageId(converted));
converted converted
} }
}; };
let paint = femtovg::Paint::image(result_id,ox,oy,x,y,0.0,1.0 ); let paint = femtovg::Paint::image(result_id, ox, oy, x, y, 0.0, 1.0);
let mut path = femtovg::Path::new(); let mut path = femtovg::Path::new();
path.rect(ox,oy,x,y); path.rect(ox, oy, x, y);
canvas.fill_path(&path, &paint); canvas.fill_path(&path, &paint);
} }
} }
} }
pub fn to_time_series(
self,
dispatcher: Rc<Dispatcher>,
cms:CMS
) -> (TimeSeriesElement, DateTime<Utc>) {
// let imp = Arc::new(InstantElementImpl::new(self));
if let InstantElementDrawerType::Prepared((target, imp)) = self.draw_type {
let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key);
let data = target.data.clone().unwrap().downcast::<PluginResult>().unwrap();
let time_stamp = data.blocks.first().unwrap().datetime;
let meta_info:MetaInfo = data.meta.clone().into();
use chrono::prelude::*;
let time = Utc.timestamp_opt(time_stamp, 0).unwrap();
(*time_series.buffer).lock().unwrap().insert(time, Some(RenderResult::new(target, meta_info)));
(time_series, time)
} else {
panic!("InstantElementDrawerType is not prepared");
}
}
} }
impl TimeSeriesElement { impl TimeSeriesElement {
fn new<T: ElementImpl>( fn new(
imp: T, imp: Arc<Box<dyn ElementImpl>>,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<Dispatcher>,
cms: Arc<Mutex<CMS>>, cms: CMS,
key: String, key: String,
) -> Self { ) -> Self {
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed); let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let pipeline = Pipeline::new(20, key.clone()); let mut pipeline = Pipeline::new(20, key.clone());
pipeline.set_dispatcher(dispatcher.clone());
let buffer = Arc::new(Mutex::new(BTreeMap::new())); let buffer = Arc::new(Mutex::new(BTreeMap::new()));
Self { Self {
id, id,
key, key,
imp: Arc::new(imp), imp,
cms, cms,
registers: Arc::new(Mutex::new(HashMap::new())), registers: Arc::new(Mutex::new(HashMap::new())),
buffer, buffer,
@ -193,22 +215,29 @@ impl TimeSeriesElement {
) -> IResult<Receiver<Result<RenderResult, RenderError>>> { ) -> IResult<Receiver<Result<RenderResult, RenderError>>> {
use tokio::sync::Notify; use tokio::sync::Notify;
use tokio::task; use tokio::task;
let notifer = Arc::new(Notify::new());
let new_notifer = notifer.clone();
let (sender, recv) = channel::<Result<RenderResult, RenderError>>(); let (sender, recv) = channel::<Result<RenderResult, RenderError>>();
self.change_time(datetime)?; self.change_time(datetime)?;
let buffer = self.buffer.lock().unwrap(); let buffer = self.buffer.lock().unwrap();
if buffer.contains_key(&datetime) { if buffer.contains_key(&datetime) {
let (_, target) = buffer.get(&datetime).unwrap(); let target = buffer.get(&datetime).unwrap();
// Already in buffer // Already in buffer
if let Some(target) = target { if let Some(target) = target {
sender.send(Ok(target.clone())).unwrap(); sender.send(Ok(target.clone())).unwrap();
} else { } else {
// self.register_noti(datetime, notifer); let new_notifer = {
let n = Arc::new(Notify::new());
let n_clone = n.clone();
self.register_noti(datetime, n);
n_clone
};
let buffer = self.buffer.clone(); let buffer = self.buffer.clone();
task::spawn_local(async move { task::spawn_local(async move {
new_notifer.notified().await; new_notifer.notified().await;
let result = buffer.lock().unwrap().get(&datetime).unwrap().1.clone(); let result = buffer.lock().unwrap().get(&datetime).unwrap().clone();
sender.send(Ok(result.unwrap())).unwrap(); sender.send(Ok(result.unwrap())).unwrap();
}); });
} }
@ -218,11 +247,11 @@ impl TimeSeriesElement {
} }
} }
pub fn set_cms(&mut self, cms: Arc<Mutex<CMS>>) { pub fn set_cms(&mut self, cms: CMS) {
self.cms = cms; self.cms = cms;
} }
fn register_noti(&mut self, datetime: DateTime<Utc>, noti: Arc<Notify>) { fn register_noti(&self, datetime: DateTime<Utc>, noti: Arc<Notify>) {
self.registers self.registers
.lock() .lock()
.unwrap() .unwrap()
@ -231,60 +260,59 @@ impl TimeSeriesElement {
.push(noti); .push(noti);
} }
pub fn change_time(&mut self, date_time: DateTime<Utc>) -> IResult<()> { fn change_time(&mut self, date_time: DateTime<Utc>) -> IResult<()> {
let imp = self.imp.clone(); let imp = self.imp.clone();
println!("Change time to {:?}", date_time);
let tasks = self.pipeline.set_current( let tasks = self.pipeline.set_current(
date_time, date_time,
true, true,
3, 3,
Arc::new(move |data ,canvas, cms| imp.render(data, canvas, cms)), Arc::new(move |data, canvas, cms| imp.render(data, canvas, cms)),
self.cms.clone(), self.cms.clone(),
); );
let tasks = tasks.map(|tms| tms.into_iter().map(|time| (time, (None, None)))); let tasks = tasks.map(|tms| tms.into_iter().map(|time| (time, None)));
if let Some(tasks) = tasks { if let Some(tasks) = tasks {
if tasks.len() == 0 { if tasks.len() == 0 {
return Err(PipelineError::DataError("No data found".to_string())); return Err(PipelineError::DataError("No data found".to_string()));
} }
let mut buffer = self.buffer.lock().unwrap(); let mut buffer = self.buffer.lock().unwrap();
buffer.extend(tasks); buffer.extend(tasks);
let buffer = self.buffer.clone();
let registers = self.registers.clone();
let listening_func = self.pipeline.listening(move |recv, idx| {
let buffer = buffer.clone();
let registers = registers.clone();
Box::pin(async move {
let registers = registers;
let (dt, result) = recv.await.unwrap();
if let Ok(result) = result {
let mut buffer = buffer.lock().unwrap();
*buffer.get_mut(&dt).unwrap() = Some(result);
}
{
registers
.lock()
.unwrap()
.get_mut(&dt)
.map(|x|x.into_iter()
.for_each(|n| {
n.notify_waiters();
}) )
;
}
})
});
let runner = Pipeline::run(&mut self.pipeline);
RUNTIME.spawn(listening_func);
RUNTIME.spawn(runner);
return Ok(());
} }
Err(PipelineError::DataError("No data found".to_string()))
let buffer = self.buffer.clone();
let registers = self.registers.clone();
let listening_func = self.pipeline.listening(move |recv, idx| {
let buffer = buffer.clone();
let registers = registers.clone();
Box::pin(async move {
let registers = registers;
let (dt, result) = recv.await.unwrap();
if let Ok(result) = result {
let mut buffer = buffer.lock().unwrap();
(*(&mut buffer.get_mut(&dt).unwrap())).1 = Some(result);
}
{
registers
.lock()
.unwrap()
.get_mut(&dt)
.unwrap()
.into_iter()
.for_each(|n| {
n.notify_waiters();
});
}
})
});
let runner = Pipeline::run(&mut self.pipeline);
RUNTIME.spawn(listening_func);
RUNTIME.spawn(runner);
Ok(())
}
pub fn insert_data(&mut self, time: DateTime<Utc>, data: Box<dyn Any + Send + Sync>) {
let mut buffer = self.buffer.lock().unwrap();
buffer.insert(time, (Some(data), None));
} }
} }
@ -298,6 +326,14 @@ impl RenderResult {
pub fn new(target: Target, meta_info: MetaInfo) -> Self { pub fn new(target: Target, meta_info: MetaInfo) -> Self {
Self { target, meta_info } Self { target, meta_info }
} }
pub fn get_meta_info(&self) -> MetaInfo {
self.meta_info.clone()
}
pub fn get_mut_target(&mut self) -> &mut Target {
&mut self.target
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -307,7 +343,7 @@ pub struct Target {
pub width: f32, pub width: f32,
pub height: f32, pub height: f32,
pub bounds: (Range, Range), pub bounds: (Range, Range),
pub data: Option<Arc<dyn Any + Send + Sync + 'static>> pub data: Option<Arc<dyn Any + Send + Sync + 'static>>,
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
@ -331,7 +367,7 @@ impl Target {
height, height,
bounds, bounds,
thumbnail, thumbnail,
data data,
} }
} }

View File

@ -85,7 +85,7 @@ impl Pipeline {
check_existed: bool, check_existed: bool,
max_retry_time: usize, max_retry_time: usize,
task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>, task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
cms: Arc<Mutex<CMS>>, cms: CMS,
) -> Option<Vec<DateTime<Utc>>> { ) -> Option<Vec<DateTime<Utc>>> {
let paths = { let paths = {
self.dispatcher.as_ref().unwrap().get_path( self.dispatcher.as_ref().unwrap().get_path(
@ -124,7 +124,7 @@ impl Pipeline {
&self, &self,
datetime: DateTime<Utc>, datetime: DateTime<Utc>,
task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>, task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
cms: Arc<Mutex<CMS>>, mut cms: CMS,
path: impl AsRef<str> + Send + 'static, path: impl AsRef<str> + Send + 'static,
) -> BoxFuture<'static, RenderR> { ) -> BoxFuture<'static, RenderR> {
Box::pin(async move { Box::pin(async move {
@ -135,7 +135,6 @@ impl Pipeline {
let handle = task::spawn_blocking(move || { let handle = task::spawn_blocking(move || {
let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap(); let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
let mut canvas_wrapper = offscreen_renderer.create_canvas(); let mut canvas_wrapper = offscreen_renderer.create_canvas();
let mut cms = cms.lock().unwrap();
let target = task(&loaded_data,&mut canvas_wrapper, &mut cms); let target = task(&loaded_data,&mut canvas_wrapper, &mut cms);
target target
}); });

View File

@ -25,7 +25,7 @@ macro_rules! match_in_macro {
match $block.data_type { match $block.data_type {
$( $(
$branch => { $branch => {
let element = Element::create_time_series(GridElementImpl::new($color), $dispatcher, $name.to_string(), $cms); let element = Element::create_time_series(Arc::new(Box::new(GridElementImpl::new($color))), $dispatcher, $name.to_string(), $cms);
Some(element) Some(element)
}, },
)+ )+
@ -39,7 +39,7 @@ macro_rules! match_in_macro {
pub fn data_to_element( pub fn data_to_element(
block: &Block, block: &Block,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<Dispatcher>,
cms: Arc<Mutex<CMS>>, cms: CMS,
) -> Option<Element> { ) -> Option<Element> {
use crate::utils::*; use crate::utils::*;
use radarg_plugin_interface::PluginResultType; use radarg_plugin_interface::PluginResultType;

View File

@ -1,6 +1,6 @@
use super::super::Render; use super::super::Render;
use crate::coords::cms::CMS; use crate::coords::cms::CMS;
use crate::pipeline::element::{self, Element, ElementID, Target}; use crate::pipeline::element::{self, Element, ElementID, Target, TargetType};
use crate::pipeline::offscreen_renderer::CanvasWrapper; use crate::pipeline::offscreen_renderer::CanvasWrapper;
use crate::{coords::Range, widgets::widget::Widget}; use crate::{coords::Range, widgets::widget::Widget};
use chrono::{prelude::*, DateTime}; use chrono::{prelude::*, DateTime};
@ -13,6 +13,7 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use core_extensions::SelfOps; use core_extensions::SelfOps;
use crate::errors::PipelineError;
type PrepareFunc = Arc< type PrepareFunc = Arc<
Mutex< Mutex<
@ -61,19 +62,77 @@ impl Layer {
} }
} }
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) { pub fn set_time(&mut self, time: DateTime<Utc>) {
self.time = Some(time);
}
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> {
if self.visiable { if self.visiable {
match self.associated_element{ match self.associated_element{
AssoElement::Instant(ref mut e) => { AssoElement::Instant(ref mut e) => {
e.render(render); e.render(render);
} }
AssoElement::TimeSeries(ref e) => {} AssoElement::TimeSeries(ref e) => {
let mut e = e.lock().unwrap();
let mut buffer = e.buffer.lock().unwrap();
let mut result = buffer.get_mut(&self.time.unwrap()).map(|x| x.as_mut());
if result.is_none(){
return Ok(()) ;
}
if let Some(result) = result.unwrap(){
let target = result.get_mut_target();
let mut canvas = render.get_canvas();
let mut canvas = canvas.as_mut().unwrap();
let (ox, oy) = target.origin(render);
let (x, y) = target.size(render);
let result_id = match target.target {
TargetType::ImageId(id) => id,
TargetType::Mem(ref mem) => {
let converted = canvas
.load_image_mem(mem, femtovg::ImageFlags::empty())
.unwrap();
target.set_target(TargetType::ImageId(converted));
converted
}
};
let paint = femtovg::Paint::image(result_id, ox, oy, x, y, 0.0, 1.0);
let mut path = femtovg::Path::new();
path.rect(ox, oy, x, y);
canvas.fill_path(&path, &paint);
}
}
_ => {} _ => {}
} }
return Ok(());
} }
Ok(())
} }
pub fn get_thumbnail(&self) -> Option<gtk::gdk::Texture> { pub fn get_thumbnail(&self) -> Option<gtk::gdk::Texture> {
None None
} }
pub fn change_visiable(&mut self, visiable: bool) {
self.visiable = visiable;
}
pub fn pop_associated_element(&mut self) -> AssoElement {
std::mem::replace(&mut self.associated_element, AssoElement::Test)
}
pub fn get_associated_element(&self) -> &AssoElement {
&self.associated_element
}
pub fn set_associated_element(&mut self, element: AssoElement) {
self.associated_element = element;
}
} }