298 lines
11 KiB
Rust
298 lines
11 KiB
Rust
use tracing::*;
|
|
use super::messages::{MonitorInputMsg, MonitorOutputMsg};
|
|
use crate::coords::cms::CMS;
|
|
use crate::pipeline::offscreen_renderer::OffscreenRenderer;
|
|
use crate::widgets::predefined::color_mapper::BoundaryNorm;
|
|
use crate::widgets::predefined::widgets::ColorBar;
|
|
use crate::widgets::render::RenderConfig;
|
|
use crate::widgets::widget::{Widget, WidgetType};
|
|
use crate::widgets::WidgetFrame;
|
|
use crate::{
|
|
coords::{proj::Mercator, Mapper},
|
|
widgets::dynamic_col::DynamicCol,
|
|
widgets::render::{Layer, Render},
|
|
};
|
|
use geo::k_nearest_concave_hull;
|
|
use glib::{clone, PropertyGet};
|
|
use std::cell::RefCell;
|
|
use std::collections::HashMap;
|
|
use std::rc::Rc;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use super::sidebar::{sidebar::SideBarModel, SideBarInputMsg, SideBarOutputMsg};
|
|
use crate::coords::Range;
|
|
use crate::map_tile::MapTile;
|
|
use crate::map_tile_utils::lat_lon_to_zoom;
|
|
use crate::pipeline::element::Target;
|
|
use adw::prelude::*;
|
|
use femtovg::ImageId;
|
|
use quick_cache::unsync::Cache;
|
|
use relm4::{component::Component, *};
|
|
use slippy_map_tiles::Tile;
|
|
use tokio::task;
|
|
use tracing::instrument::WithSubscriber;
|
|
|
|
#[derive(Debug)]
|
|
pub enum MonitorCommand {
|
|
LoadTile(Tile, Vec<u8>, (f64, f64), (Range, Range)),
|
|
None,
|
|
}
|
|
#[tracker::track]
|
|
pub struct MonitorModel {
|
|
render_cfg: RenderConfig,
|
|
render_range: (f64, f64, f64, f64),
|
|
sidebar_open: bool,
|
|
sidebar_width: i32,
|
|
zoom: u8,
|
|
#[do_not_track]
|
|
tile_cache: Cache<Tile, Target>,
|
|
#[do_not_track]
|
|
map_tile_getter: Arc<tokio::sync::Mutex<MapTile>>,
|
|
#[do_not_track]
|
|
tiles: Rc<RefCell<HashMap<Tile, Option<Target>>>>,
|
|
new_layer: i8,
|
|
#[no_eq]
|
|
widgets: Vec<WidgetFrame>,
|
|
#[no_eq]
|
|
layers: Rc<RefCell<Vec<Layer>>>,
|
|
#[no_eq]
|
|
sidebar: Controller<SideBarModel>,
|
|
}
|
|
|
|
pub struct MonitorWidgets {
|
|
paned: gtk::Paned,
|
|
}
|
|
|
|
#[relm4::component(pub)]
|
|
impl Component for MonitorModel {
|
|
type CommandOutput = MonitorCommand;
|
|
type Input = MonitorInputMsg;
|
|
type Init = Rc<RefCell<Vec<Layer>>>;
|
|
type Output = MonitorOutputMsg;
|
|
|
|
view! {
|
|
#[root]
|
|
adw::BreakpointBin {
|
|
set_hexpand: true,
|
|
set_vexpand: true,
|
|
set_height_request: 500,
|
|
set_width_request: 700,
|
|
#[wrap(Some)]
|
|
#[name="test"]
|
|
set_child = &DynamicCol{
|
|
set_end_width: 300,
|
|
set_hexpand: true,
|
|
set_vexpand: true,
|
|
#[wrap(Some)]
|
|
#[name="paned"]
|
|
set_child_paned=>k::Paned{
|
|
#[wrap(Some)]
|
|
#[name="render"]
|
|
set_start_child=>k::Frame{
|
|
add_css_class: "rb",
|
|
set_margin_all: 5,
|
|
#[name="widget_layer"]
|
|
gtk::Overlay{
|
|
#[name = "renderer"]
|
|
#[wrap(Some)]
|
|
set_child = &Render{
|
|
#[track = "model.changed(MonitorModel::render_cfg())"]
|
|
set_cfg: model.render_cfg,
|
|
#[track = "model.changed(MonitorModel::render_range())"]
|
|
set_view: model.render_range,
|
|
connect_render_status_notify[sender] => move |r| {
|
|
sender.output(MonitorOutputMsg::LayerRenderFinished);
|
|
},
|
|
set_tiles: model.tiles.clone(),
|
|
connect_range_changing_notify[sender] => move |r| {
|
|
sender.input(MonitorInputMsg::RefreshTiles);
|
|
},
|
|
connect_scale_notify[sender] => move |r| {
|
|
let scale_factor = r.scale();
|
|
let zoom = scale_factor.log2().round() as u8;
|
|
let new_zoom = model.zoom + zoom;
|
|
if model.zoom != new_zoom {
|
|
sender.input(MonitorInputMsg::ChangeZoom(new_zoom));
|
|
}
|
|
},
|
|
set_interior_layers: model.layers.clone(),
|
|
},
|
|
add_overlay=>k::Button{
|
|
set_label:"Add",
|
|
set_margin_all:10,
|
|
set_valign: gtk::Align::Start,
|
|
set_halign: gtk::Align::End,
|
|
},
|
|
#[track = "model.changed(MonitorModel::new_layer())"]
|
|
#[iterate]
|
|
add_overlay: &model.widgets
|
|
},
|
|
|
|
},
|
|
#[wrap(Some)]
|
|
set_end_child=model.sidebar.widget(),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn update_with_view(
|
|
&mut self,
|
|
widgets: &mut Self::Widgets,
|
|
message: Self::Input,
|
|
sender: ComponentSender<Self>,
|
|
root: &Self::Root,
|
|
) {
|
|
self.reset();
|
|
match message {
|
|
MonitorInputMsg::RefreshLayerList => {
|
|
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
|
widgets.renderer.queue_render();
|
|
}
|
|
MonitorInputMsg::AddMetaItem(map) => {
|
|
self.sidebar.emit(SideBarInputMsg::AddMetaItems(map))
|
|
}
|
|
MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => {
|
|
self.set_render_range((lat_start, lat_end, lon_start, lon_end));
|
|
}
|
|
MonitorInputMsg::ClearMetaItems => self.sidebar.emit(SideBarInputMsg::ClearMetaItems),
|
|
MonitorInputMsg::UpdateMetaItem(map) => {
|
|
self.sidebar.emit(SideBarInputMsg::ClearMetaItems);
|
|
self.sidebar.emit(SideBarInputMsg::AddMetaItems(map))
|
|
}
|
|
MonitorInputMsg::RefreshTiles => {
|
|
let ((x1 , x2), (y1,y2)) = widgets.renderer.render_range();
|
|
// Self::load_cache_tile(&mut self.tile_cache,&sender, &self.map_tile_getter, self.zoom, ((y1 as f32, y2 as f32),(x1 as f32,x2 as f32)));
|
|
}
|
|
MonitorInputMsg::AddWidget(widget) => match widget.widget_type() {
|
|
WidgetType::Cairo => {
|
|
let frame = WidgetFrame::new();
|
|
frame.set_widget(widget);
|
|
self.widgets.push(frame);
|
|
}
|
|
WidgetType::OpenGl => {}
|
|
_ => {}
|
|
},
|
|
MonitorInputMsg::ChangeZoom(zoom) => {
|
|
if self.zoom != zoom {
|
|
self.zoom = zoom;
|
|
sender.input(MonitorInputMsg::RefreshTiles);
|
|
}
|
|
}
|
|
MonitorInputMsg::RemoveWidget => {}
|
|
MonitorInputMsg::None => {}
|
|
_ => {}
|
|
}
|
|
|
|
self.update_view(widgets, sender);
|
|
}
|
|
|
|
fn init(
|
|
init: Self::Init,
|
|
root: &Self::Root,
|
|
sender: ComponentSender<Self>,
|
|
) -> ComponentParts<Self> {
|
|
let sidebar_sender = sender.clone();
|
|
let sidebar: Controller<SideBarModel> = SideBarModel::builder()
|
|
.launch(init.clone())
|
|
.forward(sender.input_sender(), move |msg| match msg {
|
|
SideBarOutputMsg::SwitchToTimeSeries(layer) => {
|
|
sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer));
|
|
MonitorInputMsg::None
|
|
}
|
|
_ => MonitorInputMsg::None,
|
|
});
|
|
|
|
let render_cfg = RenderConfig {
|
|
padding: [20.0, 40.0, 20.0, 40.0],
|
|
};
|
|
|
|
let mut model = MonitorModel {
|
|
render_range: (4.0, 53.3, 73.3, 135.0),
|
|
new_layer: 0,
|
|
widgets: vec![],
|
|
tiles: Rc::new(RefCell::new(HashMap::new())),
|
|
render_cfg,
|
|
tile_cache: Cache::new(32),
|
|
sidebar_open: true,
|
|
sidebar_width: 400,
|
|
layers: init,
|
|
zoom: 4,
|
|
map_tile_getter: Arc::new(tokio::sync::Mutex::new( MapTile::default())),
|
|
sidebar,
|
|
tracker: 0,
|
|
};
|
|
|
|
let map_tile_getter = model.map_tile_getter.clone();
|
|
let tiles = model.tiles.clone();
|
|
let widgets = view_output! {};
|
|
ComponentParts { model, widgets }
|
|
}
|
|
|
|
fn update_cmd_with_view(
|
|
&mut self,
|
|
widgets: &mut Self::Widgets,
|
|
message: Self::CommandOutput,
|
|
sender: ComponentSender<Self>,
|
|
root: &Self::Root,
|
|
) {
|
|
self.reset();
|
|
match message {
|
|
MonitorCommand::LoadTile(key, ref tile, origin, bounds) => {
|
|
let target = widgets
|
|
.renderer
|
|
.load_img_mem(&tile, origin, (256f32, 256f32), bounds)
|
|
.unwrap();
|
|
let mut binding = self.tiles.borrow_mut();
|
|
if !binding.contains_key(&key) {
|
|
return ;
|
|
}
|
|
binding.entry(key).and_modify(|x| *x = Some(target));
|
|
widgets.renderer.queue_draw();
|
|
}
|
|
_ => {}
|
|
}
|
|
self.update_view(widgets, sender);
|
|
}
|
|
}
|
|
|
|
|
|
impl MonitorModel {
|
|
fn load_tile(tiles: &Rc<RefCell<HashMap<Tile, Option<Target>>>> ,sender: &ComponentSender<Self>, map_tile_getter: &Arc<MapTile>, zoom:u8, range:((f32,f32), (f32,f32))) {
|
|
|
|
let map_tile_getter = map_tile_getter.clone();
|
|
let new_tiles = map_tile_getter.new_tiles(zoom ,range.0, range.1);
|
|
let mut tiles = (*tiles).borrow_mut();
|
|
let new_tiles = new_tiles.filter(|x| !tiles.contains_key(x)).collect::<Vec<_>>();
|
|
tiles.extend(new_tiles.iter().map(|x| (*x, None)));
|
|
|
|
if new_tiles.len() > 0 {
|
|
let new_sender = sender.clone();
|
|
sender.oneshot_command(async move {
|
|
for tile in new_tiles {
|
|
let map_tile_getter = map_tile_getter.clone();
|
|
let sender = new_sender.clone();
|
|
task::spawn(async move {
|
|
let result = map_tile_getter.get_tile(&tile).await;
|
|
if let Ok(result) = result {
|
|
let origin = tile.nw_corner();
|
|
let rb = tile.se_corner();
|
|
let bounds = ((origin.lon() as f64..rb.lon() as f64).into(), (origin.lat() as f64..rb.lat() as f64).into());
|
|
sender.command_sender().emit(MonitorCommand::LoadTile(tile, result,(origin.lon() as f64, origin.lat() as f64), bounds));
|
|
}
|
|
}).await;
|
|
}
|
|
MonitorCommand::None
|
|
});
|
|
}
|
|
}
|
|
|
|
fn load_tiles(&self, sender: &ComponentSender<Self>,range:((f32,f32), (f32,f32))) {
|
|
|
|
// sender.oneshot_command(async move {
|
|
// MapTile::load_tiles(self.map_tile_getter.clone(), self.zoom, range).await;
|
|
// MonitorCommand::None
|
|
// });
|
|
}
|
|
|
|
} |