end: system
This commit is contained in:
parent
558bc68d81
commit
53d5b6a57f
@ -32,3 +32,10 @@ paned>separator {
|
|||||||
.lv {
|
.lv {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
row:selected {
|
||||||
|
background: #313131;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
@ -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()))
|
||||||
|
|||||||
@ -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::<>k::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!();
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ pub enum MonitorOutputMsg {
|
|||||||
LayerAdded(usize),
|
LayerAdded(usize),
|
||||||
LayerRemoved(usize),
|
LayerRemoved(usize),
|
||||||
LayerUpdated(usize),
|
LayerUpdated(usize),
|
||||||
|
LayerSwitchToTime(usize),
|
||||||
LayerRenderFinished,
|
LayerRenderFinished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -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: >k::ListItem) -> (gtk::Box, Widgets) {
|
fn setup(_item: >k::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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,27 +260,28 @@ 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 buffer = self.buffer.clone();
|
||||||
let registers = self.registers.clone();
|
let registers = self.registers.clone();
|
||||||
|
|
||||||
let listening_func = self.pipeline.listening(move |recv, idx| {
|
let listening_func = self.pipeline.listening(move |recv, idx| {
|
||||||
let buffer = buffer.clone();
|
let buffer = buffer.clone();
|
||||||
let registers = registers.clone();
|
let registers = registers.clone();
|
||||||
@ -260,7 +290,7 @@ impl TimeSeriesElement {
|
|||||||
let (dt, result) = recv.await.unwrap();
|
let (dt, result) = recv.await.unwrap();
|
||||||
if let Ok(result) = result {
|
if let Ok(result) = result {
|
||||||
let mut buffer = buffer.lock().unwrap();
|
let mut buffer = buffer.lock().unwrap();
|
||||||
(*(&mut buffer.get_mut(&dt).unwrap())).1 = Some(result);
|
*buffer.get_mut(&dt).unwrap() = Some(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -268,23 +298,21 @@ impl TimeSeriesElement {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut(&dt)
|
.get_mut(&dt)
|
||||||
.unwrap()
|
.map(|x|x.into_iter()
|
||||||
.into_iter()
|
|
||||||
.for_each(|n| {
|
.for_each(|n| {
|
||||||
n.notify_waiters();
|
n.notify_waiters();
|
||||||
});
|
}) )
|
||||||
|
;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let runner = Pipeline::run(&mut self.pipeline);
|
let runner = Pipeline::run(&mut self.pipeline);
|
||||||
|
|
||||||
RUNTIME.spawn(listening_func);
|
RUNTIME.spawn(listening_func);
|
||||||
RUNTIME.spawn(runner);
|
RUNTIME.spawn(runner);
|
||||||
Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
Err(PipelineError::DataError("No data found".to_string()))
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user