use slint::{ComponentHandle, ModelRc, SharedString, VecModel};
use slint_mapping::sources::{FileTileSource, SyntheticTileSource};
use slint_mapping::{MapPageDemo, Tile, TileSource};
use std::cell::RefCell;
use std::rc::Rc;
fn main() -> Result<(), slint::PlatformError> {
let arg = std::env::args().nth(1);
let source: Box<dyn TileSource> = match arg.as_deref() {
Some("--synthetic") => Box::new(SyntheticTileSource::new()),
Some(path) => Box::new(FileTileSource::new(path)),
None => Box::new(FileTileSource::new(slint_mapping::SAMPLE_TILES_DIR)),
};
let win = MapPageDemo::new()?;
win.set_query(SharedString::from(""));
win.set_longitude(-0.1276);
win.set_latitude(51.5074);
win.set_zoom(10.0);
let tiles_model: Rc<VecModel<Tile>> = Rc::new(VecModel::from(Vec::new()));
win.set_tiles(ModelRc::from(tiles_model.clone()));
let state = Rc::new(RefCell::new(State {
source,
tiles_model: tiles_model.clone(),
}));
{
let win_weak = win.as_weak();
let state = Rc::clone(&state);
slint::Timer::single_shot(std::time::Duration::from_millis(0), move || {
if let Some(win) = win_weak.upgrade() {
refresh(&win, &state.borrow());
}
});
}
{
let win_weak = win.as_weak();
let state = Rc::clone(&state);
win.on_pan(move |dx, dy| {
let Some(win) = win_weak.upgrade() else {
return;
};
let s = state.borrow();
let tile_size = s.source.tile_size() as f64;
let z = win.get_zoom() as f64;
let (tx, ty) = slint_mapping::projection::lonlat_to_tile(
win.get_longitude() as f64,
win.get_latitude() as f64,
z,
);
let (lon, lat) = slint_mapping::projection::tile_to_lonlat(
tx - dx as f64 / tile_size,
ty - dy as f64 / tile_size,
z,
);
win.set_longitude(lon as f32);
win.set_latitude(lat as f32);
refresh(&win, &s);
});
}
{
let win_weak = win.as_weak();
let state = Rc::clone(&state);
win.on_zoom_by(move |delta, anchor_x, anchor_y| {
let Some(win) = win_weak.upgrade() else {
return;
};
let s = state.borrow();
let tile_size = s.source.tile_size() as f64;
let min_z = s.source.min_zoom() as f64;
let max_z = s.source.max_zoom() as f64;
let (vw, vh) = logical_size(&win);
let z_before = win.get_zoom() as f64;
let lon = win.get_longitude() as f64;
let lat = win.get_latitude() as f64;
let (tx_c, ty_c) = slint_mapping::projection::lonlat_to_tile(lon, lat, z_before);
let adx = anchor_x as f64 - vw / 2.0;
let ady = anchor_y as f64 - vh / 2.0;
let (anchor_lon, anchor_lat) = slint_mapping::projection::tile_to_lonlat(
tx_c + adx / tile_size,
ty_c + ady / tile_size,
z_before,
);
let z_after = (z_before + delta as f64).clamp(min_z, max_z);
let (tx_a_new, ty_a_new) =
slint_mapping::projection::lonlat_to_tile(anchor_lon, anchor_lat, z_after);
let (new_lon, new_lat) = slint_mapping::projection::tile_to_lonlat(
tx_a_new - adx / tile_size,
ty_a_new - ady / tile_size,
z_after,
);
win.set_longitude(new_lon as f32);
win.set_latitude(new_lat as f32);
win.set_zoom(z_after as f32);
refresh(&win, &s);
});
}
win.run()
}
struct State {
source: Box<dyn TileSource>,
tiles_model: Rc<VecModel<Tile>>,
}
fn refresh(win: &MapPageDemo, s: &State) {
let (vw, vh) = logical_size(win);
if vw <= 0.0 || vh <= 0.0 {
return;
}
let placed = slint_mapping::viewport::visible_tiles(
win.get_longitude() as f64,
win.get_latitude() as f64,
win.get_zoom() as f64,
vw,
vh,
s.source.tile_size(),
);
let mut rows: Vec<Tile> = Vec::with_capacity(placed.len());
for p in placed {
if let Some(image) = s.source.tile(p.key) {
rows.push(Tile {
x: p.x,
y: p.y,
size: p.size,
image,
});
}
}
s.tiles_model.set_vec(rows);
}
fn logical_size(win: &MapPageDemo) -> (f64, f64) {
let w = win.window();
let phys = w.size();
let scale = w.scale_factor() as f64;
let scale = if scale == 0.0 { 1.0 } else { scale };
(phys.width as f64 / scale, phys.height as f64 / scale)
}