This commit is contained in:
Tsuki 2024-03-14 18:39:32 +08:00
parent f860aadfa8
commit 763ff502da
7 changed files with 214 additions and 171 deletions

10
Cargo.lock generated
View File

@ -511,6 +511,7 @@ dependencies = [
"euclid", "euclid",
"femtovg", "femtovg",
"flate2", "flate2",
"fns",
"futures", "futures",
"geo", "geo",
"geo-macros", "geo-macros",
@ -1187,6 +1188,15 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "fns"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d318f82a68feac152dab48e8a6f1eb665a915ea6a0c76e4ad5ed137f80c368"
dependencies = [
"log",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"

View File

@ -94,6 +94,7 @@ slippy-map-tiles = "0.16.0"
reqwest = "0.11.25" reqwest = "0.11.25"
url = "2.5.0" url = "2.5.0"
quick_cache = "0.4.1" quick_cache = "0.4.1"
fns = "0.0.7"
[build-dependencies] [build-dependencies]

View File

@ -26,10 +26,12 @@ use crate::map_tile_utils::lat_lon_to_zoom;
use crate::pipeline::element::Target; use crate::pipeline::element::Target;
use adw::prelude::*; use adw::prelude::*;
use femtovg::ImageId; use femtovg::ImageId;
use fns::debounce;
use relm4::{component::Component, *}; use relm4::{component::Component, *};
use slippy_map_tiles::Tile; use slippy_map_tiles::Tile;
use tokio::task; use tokio::task;
use tracing::instrument::WithSubscriber; use tracing::instrument::WithSubscriber;
use crate::utils::estimate_zoom_level;
#[derive(Debug)] #[derive(Debug)]
pub enum MonitorCommand { pub enum MonitorCommand {
@ -42,8 +44,12 @@ pub struct MonitorModel {
render_range: (f64, f64, f64, f64), render_range: (f64, f64, f64, f64),
sidebar_open: bool, sidebar_open: bool,
sidebar_width: i32, sidebar_width: i32,
#[do_not_track]
debouncer: Rc<dyn Fn(u8)>,
zoom: u8, zoom: u8,
#[do_not_track] #[do_not_track]
last_call: Rc<RefCell<std::time::Instant>>,
#[do_not_track]
map_tile_getter: Rc<MapTile>, map_tile_getter: Rc<MapTile>,
new_layer: i8, new_layer: i8,
#[no_eq] #[no_eq]
@ -99,17 +105,17 @@ impl Component for MonitorModel {
connect_render_status_notify[sender] => move |r| { connect_render_status_notify[sender] => move |r| {
sender.output(MonitorOutputMsg::LayerRenderFinished); sender.output(MonitorOutputMsg::LayerRenderFinished);
}, },
connect_range_changing_notify[sender] => move |r| { // connect_range_changing_notify[sender] => move |r| {
sender.input(MonitorInputMsg::RefreshTiles); // sender.input(MonitorInputMsg::RefreshTiles);
}, // },
connect_scale_notify[sender] => move |r| { // connect_scale_notify => move |r| {
let scale_factor = r.scale(); // let ((x1,x2), (y1,y2)) = r.render_range();
let zoom = scale_factor.log2().round() as u8; // let (w, h) = r.window_size();
let new_zoom = model.zoom + zoom; // let new_zoom = estimate_zoom_level(x1,x2,y1,y2,w as f64, h as f64);
if model.zoom != new_zoom { // if model.zoom != new_zoom {
sender.input(MonitorInputMsg::ChangeZoom(new_zoom)); // debouncer(new_zoom);
} // }
}, // },
set_interior_layers: model.layers.clone(), set_interior_layers: model.layers.clone(),
}, },
add_overlay=&gtk::Button{ add_overlay=&gtk::Button{
@ -152,6 +158,8 @@ impl Component for MonitorModel {
} }
MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => { MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => {
self.set_render_range((lat_start, lat_end, lon_start, lon_end)); self.set_render_range((lat_start, lat_end, lon_start, lon_end));
let r = &widgets.renderer;
(*self.debouncer)(10);
} }
MonitorInputMsg::ClearMetaItems => self.sidebar.emit(SideBarInputMsg::ClearMetaItems), MonitorInputMsg::ClearMetaItems => self.sidebar.emit(SideBarInputMsg::ClearMetaItems),
MonitorInputMsg::UpdateMetaItem(map) => { MonitorInputMsg::UpdateMetaItem(map) => {
@ -206,6 +214,16 @@ impl Component for MonitorModel {
padding: [20.0, 40.0, 20.0, 40.0], padding: [20.0, 40.0, 20.0, 40.0],
}; };
let new_sender = sender.clone();
let _debouncer = fns::debounce(move |new_zoom: u8| {
new_sender.input(MonitorInputMsg::ChangeZoom(new_zoom));
}, std::time::Duration::from_millis(500));
let debouncer = move |zoom: u8| {
_debouncer.call(zoom);
};
let mut model = MonitorModel { let mut model = MonitorModel {
render_range: (4.0, 53.3, 73.3, 135.0), render_range: (4.0, 53.3, 73.3, 135.0),
new_layer: 0, new_layer: 0,
@ -213,13 +231,18 @@ impl Component for MonitorModel {
render_cfg, render_cfg,
sidebar_open: true, sidebar_open: true,
sidebar_width: 400, sidebar_width: 400,
last_call : Rc::new(RefCell::new(std::time::Instant::now())),
layers: init, layers: init,
zoom: 4, zoom: 4,
debouncer : Rc::new(debouncer),
map_tile_getter: Rc::new(MapTile::default()), map_tile_getter: Rc::new(MapTile::default()),
sidebar, sidebar,
tracker: 0, tracker: 0,
}; };
let last_call = model.last_call.clone();
let debouncer = model.debouncer.clone();
let widgets = view_output! {}; let widgets = view_output! {};
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }

View File

@ -34,7 +34,7 @@ impl Default for MapTile {
Self { Self {
server: "https://tiles.stadiamaps.com/tiles/".to_string(), server: "https://tiles.stadiamaps.com/tiles/".to_string(),
api_key: "06f1aeed-5d91-48e3-9ce5-1e99063f7f73".to_string(), api_key: "06f1aeed-5d91-48e3-9ce5-1e99063f7f73".to_string(),
style: "stamen_terrain/".to_string(), style: "stamen_toner".to_string(),
client: Client::new(), client: Client::new(),
onloading: Arc::new(std::sync::Mutex::new( HashSet::new())), onloading: Arc::new(std::sync::Mutex::new( HashSet::new())),
cache: Arc::new(std::sync::Mutex::new(Cache::new(32))), cache: Arc::new(std::sync::Mutex::new(Cache::new(32))),
@ -58,7 +58,7 @@ impl MapTile {
fn get_tile_task(&self, tile: &Tile) -> BoxFuture<'static, Result<Vec<u8>, Error>> { fn get_tile_task(&self, tile: &Tile) -> BoxFuture<'static, Result<Vec<u8>, Error>> {
let base_url = Url::parse(&self.server).unwrap(); let base_url = Url::parse(&self.server).unwrap();
let mut request_url = base_url let mut request_url = base_url
.join(&self.style) .join(&format!("{}/", self.style))
.unwrap() .unwrap()
.join(&format!("{}/{}/{}.png", tile.zoom(), tile.x(), tile.y())) .join(&format!("{}/{}/{}.png", tile.zoom(), tile.x(), tile.y()))
.unwrap(); .unwrap();
@ -164,7 +164,6 @@ impl MapTile {
if let Some(target) = cache.get(&tile) { if let Some(target) = cache.get(&tile) {
results.push(target); results.push(target);
} else { } else {
debug!("Tile {:?} is not in cache", tile);
let center = tile.center_point(); let center = tile.center_point();
let mut start_zoom = zoom - 1; let mut start_zoom = zoom - 1;
while start_zoom > 0 { while start_zoom > 0 {

View File

@ -12,6 +12,10 @@ use surfman::{
}; };
use crate::widgets::render::predefined::color_mapper::BoundaryNorm; use crate::widgets::render::predefined::color_mapper::BoundaryNorm;
use std::sync::Arc;
use std::time::{Duration};
use tokio::{time, sync::{Mutex, mpsc, oneshot}};
use crate::RUNTIME;
pub fn meshgrid<T>(x: ArrayView1<T>, y: ArrayView1<T>) -> (Array2<T>, Array2<T>) pub fn meshgrid<T>(x: ArrayView1<T>, y: ArrayView1<T>) -> (Array2<T>, Array2<T>)
where where
@ -331,3 +335,25 @@ pub fn create_kdp_boundarynorm() -> BoundaryNorm<f32> {
-125.0, -125.0,
) )
} }
pub fn estimate_zoom_level(lat_min: f64, lon_min: f64, lat_max: f64, lon_max: f64, screen_width: f64, screen_height: f64) -> u8 {
let r: f64 = 6371.0;
let avg_lat = (lat_min + lat_max) / 2.0;
// 将经纬度范围转换为在该纬度下的公里数
let delta_lon = (lon_max - lon_min) * (r * std::f64::consts::PI / 180.0) * (avg_lat * std::f64::consts::PI / 180.0).cos().abs();
let delta_lat = (lat_max - lat_min) * 111.32;
// 估算每个像素代表的实际距离(公里/像素)
let km_per_pixel_x = delta_lon / screen_width;
let km_per_pixel_y = delta_lat / screen_height;
// 选择较小的比例尺
let km_per_pixel = km_per_pixel_x.min(km_per_pixel_y);
// 根据比例尺估算Zoom Level
// 这里的比例尺和Zoom Level的对应关系可能需要根据实际地图服务进行调整
let zoom_level_estimation = 14.0 - km_per_pixel.log10();
zoom_level_estimation.round() as u8
}

View File

@ -3,19 +3,19 @@ use super::interior::InteriorWidget;
use super::{Layer, WindowCoord}; use super::{Layer, WindowCoord};
use crate::coords::proj::Mercator; use crate::coords::proj::Mercator;
use crate::coords::Mapper; use crate::coords::Mapper;
use crate::map_tile::MapTile;
use crate::pipeline::element::{Target, TargetType}; use crate::pipeline::element::{Target, TargetType};
use femtovg::{Canvas, Color, FontId, Paint, Renderer}; use femtovg::{Canvas, Color, FontId, Paint, Renderer};
use gtk::glib::{self, prelude::*, Properties}; use gtk::glib::{self, prelude::*, Properties};
use gtk::subclass::prelude::*; use gtk::subclass::prelude::*;
use gtk::traits::{GLAreaExt, WidgetExt}; use gtk::traits::{GLAreaExt, WidgetExt};
use slippy_map_tiles::Tile;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use slippy_map_tiles::Tile;
use tracing::info; use tracing::info;
use crate::map_tile::MapTile;
#[derive(Debug, Default, Clone, Copy, PartialEq)] #[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct RenderConfig { pub struct RenderConfig {
@ -41,12 +41,11 @@ pub struct RenderStatus {
pub(super) scale_rate: Option<f64>, pub(super) scale_rate: Option<f64>,
pub(super) pointer_location: WindowCoord, pub(super) pointer_location: WindowCoord,
pub(super) motion: RenderMotion, pub(super) motion: RenderMotion,
pub(super) scale: f32, pub(super) view_range: ((f64, f64), (f64, f64)),
pub(super) translate: Option<(f32, f32)>, pub(super) translation: (f64, f64),
pub(super) view_range: Option<((f64, f64), (f64, f64))>, pub(super) init_scale_rate: f64,
translation: Option<(f64, f64)>, pub(super) init_lat_lon: ((f64, f64), (f64, f64)),
init_scale_rate: f64, pub(super) init_translation: (f64, f64),
init_translation: (f64, f64),
} }
#[derive(Properties)] #[derive(Properties)]
@ -119,7 +118,10 @@ impl WidgetImpl for Render {}
impl GLAreaImpl for Render { impl GLAreaImpl for Render {
fn resize(&self, width: i32, height: i32) { fn resize(&self, width: i32, height: i32) {
self.status.borrow_mut().window_size = Some((width, height)); {
let mut status = self.status.borrow_mut();
status.window_size = Some((width, height));
}
self.ensure_canvas(); self.ensure_canvas();
let mut canvas = self.canvas.borrow_mut(); let mut canvas = self.canvas.borrow_mut();
let canvas = canvas.as_mut().unwrap(); let canvas = canvas.as_mut().unwrap();
@ -129,33 +131,35 @@ impl GLAreaImpl for Render {
self.obj().scale_factor() as f32, self.obj().scale_factor() as f32,
); );
let translation = self.status.borrow().translation; let scale_rate = self.status.borrow_mut().scale_rate;
let scale_rate = self.status.borrow().scale_rate;
let mapper = self.mapper.borrow();
if let None = translation { if let Some(scale) = scale_rate {
let ((x1,x2), (y1, y2)) = self.view_range().unwrap();
// let (x1, y1) = self.map((x1, y1)).unwrap();
// let (x2, y2) = self.map((x2, y2)).unwrap();
// let scale = ((y2 - y1) / height as f32).min((x2 - x1) / width as f32) as f64;
// let mut status = self.status.borrow_mut();
// status.scale_rate = Some(scale);
} else {
let mut status = self.status.borrow_mut(); let mut status = self.status.borrow_mut();
status.translation = Some((mapper.get_bounds().0, mapper.get_bounds().2)); let ((y1, y2), (x1, x2)) = status.init_lat_lon;
status.init_translation = (mapper.get_bounds().0, mapper.get_bounds().2); let mapper = self.mapper.borrow();
} let (x1, y1) = mapper.map((x1, y1)).unwrap();
let (x2, y2) = mapper.map((x2, y2)).unwrap();
if let None = scale_rate { let scale = ((y2 - y1) / height as f64).min((x2 - x1) / width as f64);
let scale = (mapper.get_bounds().3 - mapper.get_bounds().2) / canvas.height() as f64; status.scale_rate = Some(scale);
self.status.borrow_mut().scale_rate = Some(scale);
} }
} }
fn render(&self, context: &gtk::gdk::GLContext) -> bool { fn render(&self, context: &gtk::gdk::GLContext) -> bool {
self.ensure_canvas(); self.ensure_canvas();
let configs = self.config.borrow();
let (w, h) = { {
let mut canvas = self.canvas.borrow_mut(); let mut canvas = self.canvas.borrow_mut();
let canvas = canvas.as_mut().unwrap(); let canvas = canvas.as_mut().unwrap();
let dpi = self.obj().scale_factor(); let dpi = self.obj().scale_factor();
let w = canvas.width(); let w = canvas.width();
let h = canvas.height(); let h = canvas.height();
canvas.clear_rect( canvas.clear_rect(
0, 0,
0, 0,
@ -163,78 +167,27 @@ impl GLAreaImpl for Render {
(h as i32 * dpi) as u32, (h as i32 * dpi) as u32,
Color::rgba(0, 0, 0, 255), Color::rgba(0, 0, 0, 255),
); );
(w, h)
}; };
let binding = self.tiles.borrow(); let binding = self.tiles.borrow();
if let Some(tiles) = binding.as_ref() { if let Some(tiles) = binding.as_ref() {
let ((x1 , x2), (y1,y2)) = self.view_range().unwrap(); let ((x1, x2), (y1, y2)) = self.view_range().unwrap();
let mut tiles = tiles.current_tiles( ((y1 as f32, y2 as f32), (x1 as f32, x2 as f32))); let mut tiles = tiles.current_tiles(((y1 as f32, y2 as f32), (x1 as f32, x2 as f32)));
for tile in tiles.iter_mut() { for tile in tiles.iter_mut() {
let mut binding = (*tile).lock().unwrap(); let mut binding = (*tile).lock().unwrap();
self.draw_target(&mut *binding); self.draw_target(&mut *binding);
} }
} }
let render_range = self.status.borrow().view_range.clone(); {
if let Some(((lat1, lat2), (lon1, lon2))) = render_range { let configs = self.config.borrow();
let mut status = self.status.borrow_mut(); let c = self.interior_layers.borrow();
let c = &mut *c.borrow_mut();
let mapper = self.mapper.borrow(); self.interior
.borrow()
let (tx, ty) = mapper.map((lon1, lat1)).unwrap(); .draw(c, &self.obj(), self.status.borrow(), configs);
status.translation.replace((tx, ty));
status.init_translation = (tx, ty);
let (lon1, lat1) = mapper.map((lon1, lat1)).unwrap();
let (lon2, lat2) = mapper.map((lon2, lat2)).unwrap();
let scale = ((lat1 - lat2).abs() / h as f64).max((lon1 - lon2).abs() / w as f64);
status.scale_rate.replace(scale);
status.init_scale_rate = scale;
status.view_range = None;
} else {
let mut status = self.status.borrow_mut();
match status.motion {
RenderMotion::Translate => {
if let Some((x, y)) = status.translate {
let (ix, iy) = status.init_translation;
status.translation = Some((
ix + x as f64 * status.scale_rate.unwrap(),
iy + y as f64 * status.scale_rate.unwrap(),
));
} else {
status.init_translation = status.translation.unwrap();
}
}
RenderMotion::Scale => {
let scale_rate = status.scale_rate.unwrap();
let scale_flag = status.scale as f64;
let initial = status.init_scale_rate;
let step = scale_rate * 0.1;
let (tx, ty) = status.translation.unwrap();
let (px, py) = status.pointer_location;
let scaled = scale_rate + scale_flag * step;
status.scale_rate = Some(scaled);
self.obj().set_scale(initial / scaled);
let sx = scale_flag * step * px as f64;
let sy = scale_flag * step * py as f64;
status.translation = Some((tx - sx, ty - sy));
status.init_translation = status.translation.unwrap();
}
RenderMotion::None => {}
}
} }
let c = self.interior_layers.borrow();
let c = &mut *c.borrow_mut();
self.interior
.borrow()
.draw(c, &self.obj(), self.status.borrow(), configs);
{ {
let mut canvas = self.canvas.borrow_mut(); let mut canvas = self.canvas.borrow_mut();
let canvas = canvas.as_mut().unwrap(); let canvas = canvas.as_mut().unwrap();
@ -293,33 +246,27 @@ impl Render {
h as f32 - padding[0] - padding[2], h as f32 - padding[0] - padding[2],
); );
let (w, h) = (w as f64, h as f64); let (w, h) = (w as f64, h as f64);
let mapper = self.mapper.borrow(); let mapper = self.mapper.borrow();
let status = self.status.borrow(); let status = self.status.borrow();
status.translation.and_then(|(tx, ty)| { let (tx, ty) = status.translation;
status.scale_rate.and_then(|scale| { let scale = status.scale_rate;
let (x1, y1) = (tx + padding[3] as f64, ty + padding[2] as f64); let (x1, y1) = (tx + padding[3] as f64, ty + padding[2] as f64);
let (x2, y2) = ( let (x2, y2) = (
tx + w * scale + padding[3] as f64, tx + w * scale.unwrap() + padding[3] as f64,
ty + h * scale + padding[2] as f64, ty + h * scale.unwrap() + padding[2] as f64,
); );
let (x1, y1) = mapper.inverse_map((x1, y1)).unwrap(); let (x1, y1) = mapper.inverse_map((x1, y1)).unwrap();
let (x2, y2) = mapper.inverse_map((x2, y2)).unwrap(); let (x2, y2) = mapper.inverse_map((x2, y2)).unwrap();
Some(((x1, x2), (y1, y2))) Some(((x1, x2), (y1, y2)))
})
})
} }
pub(super) fn inverse_map(&self, loc: (f32, f32)) -> Option<(f64, f64)> { pub(super) fn inverse_map(&self, loc: (f32, f32)) -> Option<(f64, f64)> {
let (x, y) = loc; let (x, y) = loc;
let status = self.status.borrow(); let status = self.status.borrow();
status.translation.and_then(|(tx, ty)| { let (tx, ty) = status.translation;
status.scale_rate.and_then(|scale| { let scale = status.scale_rate;
let (x, y) = (x as f64, y as f64); let (x, y) = (x as f64, y as f64);
Some((tx + x * scale, (ty + y * scale))) Some((tx + x * scale.unwrap(), (ty + y * scale.unwrap())))
})
})
} }
fn padding(&self) -> [f32; 4] { fn padding(&self) -> [f32; 4] {
@ -330,19 +277,13 @@ impl Render {
let (x, y) = loc; let (x, y) = loc;
let (_, h) = self.window_size().unwrap(); let (_, h) = self.window_size().unwrap();
let status = self.status.borrow(); let status = self.status.borrow();
status.translation.and_then(|(tx, ty)| { let (tx, ty) = status.translation;
status.scale_rate.and_then(|scale| { let scale = status.scale_rate;
Some((
(x - tx as f64) as f32 / scale as f32,
h as f32 - (y - ty as f64) as f32 / scale as f32,
))
})
})
}
pub(super) fn set_translation(&self, translation: (f64, f64)) { Some((
let mut status = self.status.borrow_mut(); (x - tx) as f32 / scale.unwrap() as f32,
status.translation = Some(translation); h as f32 - (y - ty) as f32 / scale.unwrap() as f32,
))
} }
fn pointer_loc(&self) -> (f32, f32) { fn pointer_loc(&self) -> (f32, f32) {
@ -353,10 +294,21 @@ impl Render {
pub(super) fn set_view(&self, range: (f64, f64, f64, f64)) { pub(super) fn set_view(&self, range: (f64, f64, f64, f64)) {
let (lat1, lat2, lon1, lon2) = range; let (lat1, lat2, lon1, lon2) = range;
self.status let mapper = self.mapper.borrow();
.borrow_mut() let lb = mapper.map((lon1, lat1)).unwrap();
.view_range let rt = mapper.map((lon2, lat2)).unwrap();
.replace(((lat1, lat2), (lon1, lon2))); let mut s = self.status.borrow_mut();
s.translation = (lb.0, lb.1);
s.init_translation = (lb.0, lb.1);
s.init_lat_lon = ((lat1, lat2), (lon1, lon2));
if let Some((w, h)) = s.window_size {
let scale = ((rt.0 - lb.0) / w as f64).min((rt.1 - lb.1) / h as f64);
s.scale_rate = Some(scale);
} else {
s.scale_rate = None;
}
s.view_range = ((lat1, lat2), (lon1, lon2));
} }
pub(super) fn draw_target(&self, target: &mut Target) { pub(super) fn draw_target(&self, target: &mut Target) {
@ -365,13 +317,15 @@ impl Render {
let obj = self.obj(); let obj = self.obj();
let (ox,oy) = target.origin(&obj); let (ox, oy) = target.origin(&obj);
let (x, y) = target.size(&obj); let (x, y) = target.size(&obj);
let id = match target.target{ let 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
} }

View File

@ -6,25 +6,26 @@ pub mod predefined;
pub mod renders; pub mod renders;
pub mod widget; pub mod widget;
// pub use self::cms::CMS; // pub use self::cms::CMS;
use crate::coords::cms::CMS;
pub use self::imp::{RenderConfig, RenderMotion, RenderStatus}; pub use self::imp::{RenderConfig, RenderMotion, RenderStatus};
use crate::components::messages::MonitorInputMsg;
use crate::coords::cms::CMS;
use crate::coords::{Mapper, Range}; use crate::coords::{Mapper, Range};
use crate::errors::PipelineError;
use crate::map_tile::MapTile;
use crate::pipeline::element::{Target, TargetType};
use adw::prelude::{GLAreaExt, GestureDragExt}; use adw::prelude::{GLAreaExt, GestureDragExt};
use femtovg::ImageFlags;
use geo_types::LineString; use geo_types::LineString;
use glib::clone; use glib::clone;
pub use glib::subclass::prelude::*; pub use glib::subclass::prelude::*;
use gtk::traits::WidgetExt; use gtk::traits::WidgetExt;
use gtk::{EventControllerScrollFlags, Inhibit}; use gtk::{EventControllerScrollFlags, Inhibit};
pub use interior::*; pub use interior::*;
use slippy_map_tiles::Tile;
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use femtovg::ImageFlags;
use slippy_map_tiles::Tile;
use crate::errors::PipelineError;
use crate::map_tile::MapTile;
use crate::pipeline::element::{Target, TargetType};
pub type WindowCoord = (f32, f32); pub type WindowCoord = (f32, f32);
@ -42,15 +43,12 @@ impl Default for Render {
impl Render { impl Render {
pub fn new(mapper: Option<Mapper>, cfg: RenderConfig) -> Self { pub fn new(mapper: Option<Mapper>, cfg: RenderConfig) -> Self {
let this: Self = glib::Object::new(); let this: Self = glib::Object::new();
{
let mut status = this.imp().status.borrow_mut();
status.scale = 1.0;
}
this.imp().config.replace(cfg); this.imp().config.replace(cfg);
if let Some(mapper) = mapper { if let Some(mapper) = mapper {
this.set_mapper(mapper); this.set_mapper(mapper);
} }
let dpi = this.scale_factor() as f32;
let pointer_location_detecture = gtk::EventControllerMotion::new(); let pointer_location_detecture = gtk::EventControllerMotion::new();
pointer_location_detecture.connect_motion( pointer_location_detecture.connect_motion(
clone!( @weak this as r => move |_context, x, y| { clone!( @weak this as r => move |_context, x, y| {
@ -64,35 +62,57 @@ impl Render {
); );
let scale_detecture = gtk::EventControllerScroll::new(EventControllerScrollFlags::VERTICAL); let scale_detecture = gtk::EventControllerScroll::new(EventControllerScrollFlags::VERTICAL);
let _r = Mutex::new(this.clone());
let debouncer = fns::debounce(
move |scale: f64| {
_r.lock().unwrap().set_scale(scale);
},
std::time::Duration::from_millis(500),
);
scale_detecture.connect_scroll(clone!( scale_detecture.connect_scroll(clone!(
@weak this as r => @default-panic,move |_context, _x, y| { @weak this as r => @default-panic,move |_context, _x, y| {
r.update_status(|status|{ let mut rate = 0.0;
status.scale = y as f32; r.update_status(|s|{
status.motion = RenderMotion::Scale; let scale_rate = s.scale_rate.unwrap();
}); let scale_flag = y as f64;
r.queue_render(); let step = scale_rate * 0.1;
Inhibit(false) let (tx, ty) = s.translation;
} let (px, py) = s.pointer_location;
let scaled = scale_rate + scale_flag * step;
s.scale_rate = Some(scaled);
rate = scaled / 1.0;
let sx = scale_flag * step * px as f64;
let sy = scale_flag * step * py as f64;
s.translation = (tx - sx, ty - sy);
s.init_translation = s.translation;
s.motion = RenderMotion::Scale;
});
r.queue_render();
debouncer.call(rate);
Inhibit(true)
}
)); ));
let drag_detecture = gtk::GestureDrag::new(); let drag_detecture = gtk::GestureDrag::new();
drag_detecture.connect_drag_update(clone!( drag_detecture.connect_drag_update(clone!(@weak this as r => move |this, _, _| {
@weak this as r => move |this, _, _| {
let (ox, oy) = this.offset().unwrap_or((0.0,0.0)); let (ox, oy) = this.offset().unwrap_or((0.0,0.0));
let dpi = r.scale_factor() as f32;
r.update_status(|s| { r.update_status(|s| {
s.translate = Some((-ox as f32 * dpi , oy as f32 * dpi)); let (ix, iy) = s.init_translation;
let x = -ox as f32 * dpi;
let y = oy as f32 * dpi;
s.translation = (ix + x as f64 * s.scale_rate.unwrap(), iy + y as f64 * s.scale_rate.unwrap());
s.motion = RenderMotion::Translate; s.motion = RenderMotion::Translate;
}); });
r.set_range_changing(0.0); r.set_range_changing(0.0);
r.queue_render(); r.queue_render();
})); }));
drag_detecture.connect_drag_end(clone!( drag_detecture.connect_drag_end(clone!(
@weak this as r => move |_,_,_|{ @weak this as r => move |_,_,_|{
r.update_status(|cfg| { r.update_status(|s| {
cfg.translate = None; s.init_translation = s.translation;
cfg.motion = RenderMotion::Translate;
}) })
} }
r.queue_render(); r.queue_render();
@ -103,7 +123,6 @@ impl Render {
this.add_controller(pointer_location_detecture); this.add_controller(pointer_location_detecture);
this.add_controller(scale_detecture); this.add_controller(scale_detecture);
this.add_controller(drag_detecture); this.add_controller(drag_detecture);
this this
} }
@ -221,12 +240,25 @@ impl Render {
self.queue_render(); self.queue_render();
} }
pub fn load_img_mem(&self, img: &[u8], origin:(f64,f64),size :(f32,f32), bounds: (Range, Range)) -> Result<Target, PipelineError> { pub fn load_img_mem(
&self,
img: &[u8],
origin: (f64, f64),
size: (f32, f32),
bounds: (Range, Range),
) -> Result<Target, PipelineError> {
let mut canvas = self.get_canvas(); let mut canvas = self.get_canvas();
let cvs = canvas.as_mut().unwrap(); let cvs = canvas.as_mut().unwrap();
let img_id = cvs.load_image_mem(img, ImageFlags::empty()).unwrap(); let img_id = cvs.load_image_mem(img, ImageFlags::empty()).unwrap();
let (width, height) = size; let (width, height) = size;
Ok(Target::new(TargetType::ImageId(img_id), width, height, bounds, None, None)) Ok(Target::new(
TargetType::ImageId(img_id),
width,
height,
bounds,
None,
None,
))
} }
pub fn delete_img(&self, img: Target) { pub fn delete_img(&self, img: Target) {
@ -236,8 +268,6 @@ impl Render {
cvs.delete_image(id); cvs.delete_image(id);
} }
} }
pub fn get_scale(&self) -> f32 {
self.imp().status.borrow().scale
}
} }
unsafe impl Send for Render {}