use adw::{prelude::*, subclass::prelude::*};
use geo_uri::GeoUri;
use gtk::{gdk_pixbuf, gio, glib, CompositeTemplate};
use shumate::prelude::*;
use crate::i18n::gettext_f;
mod imp {
use std::cell::Cell;
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
#[template(resource = "/org/gnome/Fractal/ui/components/media/location_viewer.ui")]
#[properties(wrapper_type = super::LocationViewer)]
pub struct LocationViewer {
#[template_child]
pub map: TemplateChild<shumate::SimpleMap>,
#[template_child]
pub marker_img: TemplateChild<gtk::Image>,
pub marker: shumate::Marker,
#[property(get, set = Self::set_compact, explicit_notify)]
pub compact: Cell<bool>,
}
#[glib::object_subclass]
impl ObjectSubclass for LocationViewer {
const NAME: &'static str = "LocationViewer";
type Type = super::LocationViewer;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
klass.set_css_name("location-viewer");
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for LocationViewer {
fn constructed(&self) {
self.marker.set_child(Some(&*self.marker_img));
let style = gio::resources_lookup_data(
"/org/gnome/Fractal/mapstyle/osm-liberty/style.json",
gio::ResourceLookupFlags::NONE,
)
.expect("Could not load map style");
let source =
shumate::VectorRenderer::new("vector-tiles", &String::from_utf8_lossy(&style))
.expect("Could not read map style");
source.set_license("© OpenMapTiles © OpenStreetMap contributors");
source.set_license_uri("https://www.openstreetmap.org/copyright");
let spritepixbuf = gdk_pixbuf::Pixbuf::from_resource(
"/org/gnome/Fractal/mapstyle/osm-liberty/sprites.png",
)
.expect("Could not load map sprites");
let spritejson = gio::resources_lookup_data(
"/org/gnome/Fractal/mapstyle/osm-liberty/sprites.json",
gio::ResourceLookupFlags::NONE,
)
.expect("Could not load map sprite sheet");
source
.set_sprite_sheet_data(&spritepixbuf, &String::from_utf8_lossy(&spritejson))
.expect("Could not set map sprite sheet");
self.map.set_map_source(Some(&source));
let viewport = self.map.viewport().unwrap();
viewport.set_zoom_level(12.0);
let marker_layer = shumate::MarkerLayer::new(&viewport);
marker_layer.add_marker(&self.marker);
self.map.add_overlay_layer(&marker_layer);
self.map.scale().unwrap().set_visible(false);
self.parent_constructed();
}
}
impl WidgetImpl for LocationViewer {}
impl BinImpl for LocationViewer {}
impl LocationViewer {
fn set_compact(&self, compact: bool) {
if self.compact.get() == compact {
return;
}
self.map.set_show_zoom_buttons(!compact);
if let Some(license) = self.map.license() {
license.set_visible(!compact);
}
self.compact.set(compact);
self.obj().notify_compact();
}
}
}
glib::wrapper! {
pub struct LocationViewer(ObjectSubclass<imp::LocationViewer>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl LocationViewer {
pub fn new() -> Self {
glib::Object::new()
}
pub fn set_location(&self, geo_uri: &GeoUri) {
let imp = self.imp();
let latitude = geo_uri.latitude();
let longitude = geo_uri.longitude();
imp.map
.viewport()
.unwrap()
.set_location(latitude, longitude);
imp.marker.set_location(latitude, longitude);
self.update_property(&[gtk::accessible::Property::Description(&gettext_f(
"Location at latitude {latitude} and longitude {longitude}",
&[
("latitude", &latitude.to_string()),
("longitude", &longitude.to_string()),
],
))]);
}
}