diff --git a/data/css/main.css b/data/css/main.css index 3afcf6f..3d0e773 100644 --- a/data/css/main.css +++ b/data/css/main.css @@ -32,3 +32,10 @@ paned>separator { .lv { background: transparent; } + + +row:selected { + background: #313131; + color: #fff; + border-radius: 5px; +} \ No newline at end of file diff --git a/src/components/app.rs b/src/components/app.rs index 4c6319a..c0cee89 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -5,8 +5,12 @@ use super::{ setting::SettingModel, ControlPanelOutputMsg, TimelineMsg, }; -use crate::pipeline::element::{Element, InstantElement, InstantElementDrawerType}; 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::{ coords::{ cms::CMS, @@ -27,6 +31,7 @@ use futures::future::BoxFuture; use glib::clone; use gtk::prelude::*; use once_cell::sync::Lazy; +use radarg_plugin_interface::PluginResult; use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup}; use relm4::*; use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent}; @@ -34,6 +39,7 @@ use relm4_components::open_dialog::{ OpenDialog, OpenDialogMsg, OpenDialogResponse, OpenDialogSettings, }; use smallvec::SmallVec; +use std::marker::PhantomData; use std::{ any::Any, borrow::{Borrow, BorrowMut}, @@ -43,11 +49,9 @@ use std::{ rc::Rc, sync::{Arc, Mutex}, }; -use radarg_plugin_interface::PluginResult; use tokio::{sync::oneshot, task}; use tracing::{debug, error, info, warn}; -use crate::pipeline::{GridElementImpl, OffscreenRenderer}; -use crate::widgets::AssoElement; +use tracing_subscriber::fmt::layer; relm4::new_action_group!(FileActionGroup, "file"); relm4::new_stateless_action!(OpenAction, FileActionGroup, "open"); @@ -60,6 +64,7 @@ pub enum AppMsg { CloseRequest, Close, OpenDialog, + SwitchToTime(usize), NewElement(Element), DeleteElement(ElementKey), NewLayer(Layer), @@ -71,7 +76,7 @@ pub struct AppModel { #[do_not_track] dispatcher: RcDispatcher, #[do_not_track] - cms: Arc>, + cms: CMS, waiting_for: Option>, #[do_not_track] open_dialog: Controller, @@ -82,7 +87,7 @@ pub struct AppModel { #[do_not_track] layers: Rc>>, #[do_not_track] - elements: Vec>>, + elements: Vec>>, #[do_not_track] setting: Controller, } @@ -187,17 +192,11 @@ impl Component for AppModel { root: &Self::Root, sender: ComponentSender, ) -> ComponentParts { - - let layers = Rc::new(RefCell::new(vec![ - Layer::new(true, "Layer1".to_string(), AssoElement::Test), - ])); - let control = ControlPanelModel::builder().launch(0).forward( + let layers = Rc::new(RefCell::new(Vec::with_capacity(20))); + let control = ControlPanelModel::builder().launch(layers.clone()).forward( sender.input_sender(), |msg| match msg { - ControlPanelOutputMsg::OpenFile((key, time)) => { - // AppMsg::SwitchTo((key, time, None, None)) - AppMsg::Close - } + ControlPanelOutputMsg::OpenFile((key, time)) => AppMsg::Close, }, ); let render = @@ -205,38 +204,40 @@ impl Component for AppModel { .launch(layers.clone()) .forward(sender.input_sender(), |a| match a { MonitorOutputMsg::LayerRenderFinished => AppMsg::Close, + MonitorOutputMsg::LayerSwitchToTime(idx) => AppMsg::SwitchToTime(idx), _ => AppMsg::Close, }); let setting = SettingModel::builder() .launch(()) .forward(sender.input_sender(), |a| AppMsg::Close); let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1))); - let cms = Arc::new(Mutex::new(CMS::new( - Mercator::default().into(), - (3000.0, 3000.0), - ))); + let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0)); let dialog_dispatcher = dispatcher.clone(); - let dialog_cms = cms.clone(); + let dialog_render_sender = render.sender().clone(); let dialog = OpenDialog::builder() .transient_for_native(&root) .launch(OpenDialogSettings::default()) .forward(sender.input_sender(), move |response| match response { OpenDialogResponse::Accept(path) => { + *FILE_PATH_ROOT.lock().unwrap() = path.clone(); let data = Self::open_file_only(path); + let meta: MetaInfo = (&data.meta).clone().into(); 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 cms_ref = dialog_cms.lock().unwrap(); - - let mut data_target = element_impl.render(&data,&mut canvas,&mut (*cms_ref)); + 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); data_target.data = Some(Arc::new(data) as Arc); let element = Element::create_instant( - InstantElementDrawerType::Prepared(data_target), + InstantElementDrawerType::Prepared((data_target, Arc::new(element_impl))), dialog_dispatcher.clone(), - "New Element".to_string(), - ).get_instance(); - let layer = Layer::new(true, "New Layer".to_string(), AssoElement::Instant(element)); + "ET".to_string(), + ) + .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::Close, @@ -252,7 +253,7 @@ impl Component for AppModel { open_dialog: dialog, control, render, - layers , + layers, setting, tracker: 0, }; @@ -279,13 +280,6 @@ impl Component for AppModel { ) { self.reset(); 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) => { (*self.layers).borrow_mut().push(layer); self.render.sender().send(MonitorInputMsg::RefreshLayerList); @@ -294,6 +288,23 @@ impl Component for AppModel { relm4::main_application().quit(); } 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 => { self.open_dialog.emit(OpenDialogMsg::Open); } @@ -321,7 +332,7 @@ impl AppModel { fn open_file( path: impl AsRef, dispatcher: Rc, - cms: Arc>, + cms: CMS, ) -> Option<(Option>, Element)> { let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); let mut result = plugin @@ -332,9 +343,7 @@ impl AppModel { .map(|v| (Some(Box::new(result) as Box), v)) } - fn open_file_only( - path: impl AsRef, - ) -> PluginResult { + fn open_file_only(path: impl AsRef) -> PluginResult { let plugin = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); let mut result = plugin .load(RStr::from_str(path.as_ref().to_str().unwrap())) diff --git a/src/components/control_panel/control_panel.rs b/src/components/control_panel/control_panel.rs index 467fd98..e3146b2 100644 --- a/src/components/control_panel/control_panel.rs +++ b/src/components/control_panel/control_panel.rs @@ -1,3 +1,4 @@ +use std::cell::{Ref, RefCell}; use super::messages::*; use super::thumbnail::{ImgItem, TypedListView}; use crate::data::{CoordType, Radar2d, RadarData2d}; @@ -16,6 +17,7 @@ use relm4::prelude::*; use relm4_components::open_button::{OpenButton, OpenButtonSettings}; use relm4_components::open_dialog::OpenDialogSettings; use std::path::PathBuf; +use std::rc::Rc; #[tracker::track] #[derive(Debug)] @@ -25,13 +27,15 @@ pub struct ControlPanelModel { timeline_start: DateTime, selection: Option>, key: Option, + #[do_not_track] + layers: Rc>>, #[tracker::no_eq] list_img_wrapper: TypedListView, } #[relm4::component(pub)] impl SimpleComponent for ControlPanelModel { - type Init = i8; + type Init = Rc>>; type Output = ControlPanelOutputMsg; type Input = ControlPanelInputMsg; @@ -56,11 +60,18 @@ impl SimpleComponent for ControlPanelModel { add_css_class:"h2", set_halign: gtk::Align::Start, }, - gtk::Label{ - set_label: "Subheader", - add_css_class:"h3", - set_halign: gtk::Align::Start, + #[local] + layer_controller_selection -> gtk::DropDown{ + set_expression:None::<>k::Expression>, + 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] step_selector -> gtk::DropDown{ @@ -220,11 +231,13 @@ impl SimpleComponent for ControlPanelModel { key: None, enabled: true, selection: None, + layers: init, timeline_start, list_img_wrapper, tracker: 0, }; + let layer_controller_selection = gtk::DropDown::from_strings(&[]); let my_view = &model.list_img_wrapper.view; let widgets = view_output!(); diff --git a/src/components/monitor/messages.rs b/src/components/monitor/messages.rs index 565f570..57e0caa 100644 --- a/src/components/monitor/messages.rs +++ b/src/components/monitor/messages.rs @@ -43,6 +43,7 @@ pub enum MonitorOutputMsg { LayerAdded(usize), LayerRemoved(usize), LayerUpdated(usize), + LayerSwitchToTime(usize), LayerRenderFinished, } diff --git a/src/components/monitor/monitor.rs b/src/components/monitor/monitor.rs index b2bbd01..5fb1e98 100644 --- a/src/components/monitor/monitor.rs +++ b/src/components/monitor/monitor.rs @@ -153,10 +153,15 @@ impl Component for MonitorModel { root: &Self::Root, sender: ComponentSender, ) -> ComponentParts { + let sidebar_sender = sender.clone(); let sidebar: Controller = SideBarModel::builder() .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::SwitchToTimeSeries(layer) => { + sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer)); + MonitorInputMsg::None + } _ => MonitorInputMsg::None, }); diff --git a/src/components/monitor/sidebar/sidebar.rs b/src/components/monitor/sidebar/sidebar.rs index e9b86df..8efe3e9 100644 --- a/src/components/monitor/sidebar/sidebar.rs +++ b/src/components/monitor/sidebar/sidebar.rs @@ -10,7 +10,9 @@ use relm4::{ RelmObjectExt, }; use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use chrono::{DateTime, Utc}; use relm4::actions::{AccelsPlus, RelmAction}; +use crate::widgets::AssoElement; use crate::{ chart::Chart, @@ -25,8 +27,8 @@ use super::{ }; relm4::new_action_group!(LayerActionGroup, "layer"); -// relm4::new_stateless_action!(ToTime, LayerActionGroup, "to_time"); -relm4::new_stateful_action!(ToTime, LayerActionGroup, "to_time", u32, u32); +relm4::new_stateful_action!(ToTime, LayerActionGroup, "to_time", u32, ()); +relm4::new_stateless_action!(BeTime, LayerActionGroup, "be_time"); pub struct SideBarModel { layers: Rc>>, counter: u8, @@ -135,14 +137,19 @@ impl SimpleComponent for SideBarModel { let mut group = relm4::actions::RelmActionGroup::::new(); let action: RelmAction = { - RelmAction::new_stateful_with_target_value(&0, |_, state, _value| { - *state ^= 1; - dbg!(state); + RelmAction::new_stateful_with_target_value(&(), move |_, state, _value| { + sender.output(SideBarOutputMsg::SwitchToTimeSeries(_value as usize)).unwrap() }) }; + let action2:RelmAction = RelmAction::new_stateless(|_| { + dbg!("be time"); + }); + 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(); @@ -168,12 +175,19 @@ impl SimpleComponent for SideBarModel { let columns = model.meta_list_view.get_columns(); let info_c = columns.get("info").unwrap(); let widgets = view_output!(); + { let mut list = model .layers .borrow() .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::>(); model.list_view_wrapper.extend_from_iter(list); } @@ -188,7 +202,13 @@ impl SimpleComponent for SideBarModel { .layers .borrow() .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::>(); self.list_view_wrapper.clear(); 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), + Instance, + BindToOtherLayer(usize) +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] struct LayerItem { + key: u32, layer_name: String, visiable: bool, + status: LayerStatus, img: Option, } impl LayerItem { - fn new(name: String, visiable: bool, img: Option) -> Self { + fn new(key: u32,name: String, visiable: bool, img: Option, status: LayerStatus) -> Self { Self { + key, layer_name: name, visiable, + status, img, } } @@ -226,6 +257,7 @@ impl LayerItem { struct Widgets { label: gtk::Label, screen_shot: gtk::Image, + status: gtk::Label, button: gtk::CheckButton, menu: gtk::PopoverMenu, } @@ -237,9 +269,11 @@ impl RelmListItem for LayerItem { fn setup(_item: >k::ListItem) -> (gtk::Box, Widgets) { relm4::menu! { main_menu: { - "Bind To Time" => ToTime(_item.position()) + "Bind To Time" => ToTime(0), + "Be Time" => BeTime, } } + relm4::view! { my_box = gtk::Box { gtk::Frame{ @@ -253,6 +287,10 @@ impl RelmListItem for LayerItem { gtk::Label{ set_halign: gtk::Align::Start, }, + #[name = "status"] + gtk::Label{ + set_halign: gtk::Align::Start + }, gtk::Label{ set_hexpand: true, }, @@ -268,6 +306,7 @@ impl RelmListItem for LayerItem { let widgets = Widgets { screen_shot, label, + status, button, menu, }; @@ -276,13 +315,29 @@ impl RelmListItem for LayerItem { } fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) { + let Widgets { label, button, screen_shot, + status, menu, } = 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(); gesture_click.set_button(gtk::gdk::BUTTON_SECONDARY); screen_shot.set_paintable(self.img.as_ref()); @@ -294,7 +349,7 @@ impl RelmListItem for LayerItem { })); _root.add_controller(gesture_click); - label.set_label(&format!("Layer: {} ", &self.layer_name)); + label.set_label(&self.layer_name); button.set_active(self.visiable); } } diff --git a/src/coords/cms.rs b/src/coords/cms.rs index 814860a..772b077 100644 --- a/src/coords/cms.rs +++ b/src/coords/cms.rs @@ -2,7 +2,7 @@ use std::ops::Range; use geo_types::LineString; use crate::coords::Mapper; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CMS { mapper: Mapper, window_size: (f32, f32), diff --git a/src/pipeline/dispatcher.rs b/src/pipeline/dispatcher.rs index 1b0d390..514fdab 100644 --- a/src/pipeline/dispatcher.rs +++ b/src/pipeline/dispatcher.rs @@ -108,8 +108,7 @@ impl Dispatcher { check_existed: bool, mut max_retry_time: usize, ) -> Option)>> { - let datetime_format: regex::Regex = - Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap(); + let datetime_format: regex::Regex = Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap(); let config = CONFIG.lock().unwrap(); let path_format = config .plugins @@ -158,12 +157,10 @@ impl Dispatcher { } if check_existed { - if max_retry_time == 0 { - break; - } + // if max_retry_time == 0 { + // break; + // } if !std::path::Path::new(&result_path).exists() { - max_retry_time = max_retry_time - 1; - continue; } else { result_paths.push((result_path.clone(), t)); } @@ -183,12 +180,10 @@ impl Dispatcher { } if check_existed { - if max_retry_time == 0 { - break; - } + // if max_retry_time == 0 { + // break; + // } if !std::path::Path::new(&result_path).exists() { - max_retry_time = max_retry_time - 1; - continue; } else { result_paths.push((result_path.clone(), t)); } diff --git a/src/pipeline/element.rs b/src/pipeline/element.rs index e45ae7e..06b828e 100644 --- a/src/pipeline/element.rs +++ b/src/pipeline/element.rs @@ -4,12 +4,15 @@ use crate::components::ControlPanelInputMsg; use crate::coords::cms::CMS; use crate::data::MetaInfo; use crate::errors::{PipelineError, RenderError}; +use crate::widgets::Render; use crate::RUNTIME; 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 futures::StreamExt; use glib::PropertyGet; +use radarg_plugin_interface::PluginResult; use std::any::Any; use std::borrow::Borrow; use std::collections::{BTreeMap, HashMap}; @@ -23,21 +26,17 @@ use std::{ pin::Pin, sync::{Arc, Mutex}, }; -use core_extensions::SelfOps; -use radarg_plugin_interface::PluginResult; use tokio::sync::{ oneshot::{channel, Receiver, Sender}, Notify, }; use tracing::Instrument; -use crate::widgets::Render; pub type ElementID = usize; static ELEMENT_ID: AtomicUsize = AtomicUsize::new(0); pub type Data = Box; -pub type Buffer = - Arc, (Option, Option)>>>; +pub type Buffer = Arc, Option>>>; type DrawFunc = Rc>; type IResult = Result; @@ -48,11 +47,11 @@ pub enum Element { } impl Element { - pub fn create_time_series( - imp: T, + pub fn create_time_series( + imp: Arc>, dispatcher: Rc, key: String, - cms: Arc>, + cms: CMS, ) -> Self { Element::TimeSeries(TimeSeriesElement::new(imp, dispatcher, cms, key)) } @@ -80,7 +79,7 @@ impl Element { pub fn get_instance(mut self) -> InstantElement { match self { 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 id: ElementID, pub key: String, - cms: Arc>, - imp: Arc, + cms: CMS, + imp: Arc>, registers: Arc, Vec>>>>, pipeline: Pipeline, - buffer: Buffer, + pub buffer: Buffer, dispatcher: Rc, } #[derive(Clone)] pub enum InstantElementDrawerType { Draw(DrawFunc), - Prepared(Target), + Prepared((Target, Arc>)), } impl Debug for InstantElementDrawerType { @@ -141,44 +140,67 @@ impl InstantElement { InstantElementDrawerType::Draw(ref func) => { func(render); } - InstantElementDrawerType::Prepared(ref mut target) => { + InstantElementDrawerType::Prepared((ref 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 (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(); + 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 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); + path.rect(ox, oy, x, y); canvas.fill_path(&path, &paint); } } } + + pub fn to_time_series( + self, + dispatcher: Rc, + cms:CMS + ) -> (TimeSeriesElement, DateTime) { + // 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::().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 { - fn new( - imp: T, + fn new( + imp: Arc>, dispatcher: Rc, - cms: Arc>, + cms: CMS, key: String, ) -> Self { 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())); Self { id, key, - imp: Arc::new(imp), + imp, cms, registers: Arc::new(Mutex::new(HashMap::new())), buffer, @@ -193,22 +215,29 @@ impl TimeSeriesElement { ) -> IResult>> { use tokio::sync::Notify; use tokio::task; - let notifer = Arc::new(Notify::new()); - let new_notifer = notifer.clone(); + let (sender, recv) = channel::>(); self.change_time(datetime)?; + let buffer = self.buffer.lock().unwrap(); if buffer.contains_key(&datetime) { - let (_, target) = buffer.get(&datetime).unwrap(); + let target = buffer.get(&datetime).unwrap(); + // Already in buffer if let Some(target) = target { sender.send(Ok(target.clone())).unwrap(); } 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(); task::spawn_local(async move { 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(); }); } @@ -218,11 +247,11 @@ impl TimeSeriesElement { } } - pub fn set_cms(&mut self, cms: Arc>) { + pub fn set_cms(&mut self, cms: CMS) { self.cms = cms; } - fn register_noti(&mut self, datetime: DateTime, noti: Arc) { + fn register_noti(&self, datetime: DateTime, noti: Arc) { self.registers .lock() .unwrap() @@ -231,60 +260,59 @@ impl TimeSeriesElement { .push(noti); } - pub fn change_time(&mut self, date_time: DateTime) -> IResult<()> { + fn change_time(&mut self, date_time: DateTime) -> IResult<()> { let imp = self.imp.clone(); + println!("Change time to {:?}", date_time); let tasks = self.pipeline.set_current( date_time, true, 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(), ); - 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 tasks.len() == 0 { return Err(PipelineError::DataError("No data found".to_string())); } + let mut buffer = self.buffer.lock().unwrap(); 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(()); } - - 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, data: Box) { - let mut buffer = self.buffer.lock().unwrap(); - buffer.insert(time, (Some(data), None)); + Err(PipelineError::DataError("No data found".to_string())) } } @@ -298,6 +326,14 @@ impl RenderResult { pub fn new(target: Target, meta_info: MetaInfo) -> Self { 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)] @@ -307,7 +343,7 @@ pub struct Target { pub width: f32, pub height: f32, pub bounds: (Range, Range), - pub data: Option> + pub data: Option>, } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] @@ -331,7 +367,7 @@ impl Target { height, bounds, thumbnail, - data + data, } } diff --git a/src/pipeline/new_pipeline.rs b/src/pipeline/new_pipeline.rs index 0a4ae16..55af127 100644 --- a/src/pipeline/new_pipeline.rs +++ b/src/pipeline/new_pipeline.rs @@ -85,7 +85,7 @@ impl Pipeline { check_existed: bool, max_retry_time: usize, task: Arc Target + Send + Sync>, - cms: Arc>, + cms: CMS, ) -> Option>> { let paths = { self.dispatcher.as_ref().unwrap().get_path( @@ -124,7 +124,7 @@ impl Pipeline { &self, datetime: DateTime, task: Arc Target + Send + Sync>, - cms: Arc>, + mut cms: CMS, path: impl AsRef + Send + 'static, ) -> BoxFuture<'static, RenderR> { Box::pin(async move { @@ -135,7 +135,6 @@ impl Pipeline { let handle = task::spawn_blocking(move || { let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap(); let mut canvas_wrapper = offscreen_renderer.create_canvas(); - let mut cms = cms.lock().unwrap(); let target = task(&loaded_data,&mut canvas_wrapper, &mut cms); target }); diff --git a/src/pipeline/utils.rs b/src/pipeline/utils.rs index 8ed3d36..f62d7e0 100644 --- a/src/pipeline/utils.rs +++ b/src/pipeline/utils.rs @@ -25,7 +25,7 @@ macro_rules! match_in_macro { match $block.data_type { $( $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) }, )+ @@ -39,7 +39,7 @@ macro_rules! match_in_macro { pub fn data_to_element( block: &Block, dispatcher: Rc, - cms: Arc>, + cms: CMS, ) -> Option { use crate::utils::*; use radarg_plugin_interface::PluginResultType; diff --git a/src/widgets/render/interior/layers.rs b/src/widgets/render/interior/layers.rs index bed9ca6..9410e31 100644 --- a/src/widgets/render/interior/layers.rs +++ b/src/widgets/render/interior/layers.rs @@ -1,6 +1,6 @@ use super::super::Render; 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::{coords::Range, widgets::widget::Widget}; use chrono::{prelude::*, DateTime}; @@ -13,6 +13,7 @@ use std::{ sync::{Arc, Mutex}, }; use core_extensions::SelfOps; +use crate::errors::PipelineError; type PrepareFunc = Arc< 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) { + self.time = Some(time); + } + + pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> { if self.visiable { match self.associated_element{ AssoElement::Instant(ref mut e) => { 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 { 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; + } + }