fractal/src/components/location_viewer.rs

145 lines
4.4 KiB
Rust

use adw::{prelude::*, subclass::prelude::*};
use geo_uri::GeoUri;
use gtk::{glib, CompositeTemplate};
use shumate::prelude::*;
use crate::i18n::gettext_f;
mod imp {
use std::cell::Cell;
use glib::subclass::InitializingObject;
use once_cell::sync::Lazy;
use super::*;
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/Fractal/ui/components/location_viewer.ui")]
pub struct LocationViewer {
#[template_child]
pub map: TemplateChild<shumate::SimpleMap>,
#[template_child]
pub marker_img: TemplateChild<gtk::Image>,
pub marker: shumate::Marker,
pub compact: Cell<bool>,
}
#[glib::object_subclass]
impl ObjectSubclass for LocationViewer {
const NAME: &'static str = "ComponentsLocationViewer";
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();
}
}
impl ObjectImpl for LocationViewer {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecBoolean::builder("compact")
.explicit_notify()
.build()]
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"compact" => self.obj().set_compact(value.get().unwrap()),
_ => unimplemented!(),
}
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"compact" => self.obj().compact().to_value(),
_ => unimplemented!(),
}
}
fn constructed(&self) {
self.marker.set_child(Some(&*self.marker_img));
let registry = shumate::MapSourceRegistry::with_defaults();
let source = registry.by_id(shumate::MAP_SOURCE_OSM_MAPNIK).unwrap();
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);
// Hide the scale
self.map.scale().unwrap().set_visible(false);
self.parent_constructed();
}
}
impl WidgetImpl for LocationViewer {}
impl BinImpl for LocationViewer {}
}
glib::wrapper! {
/// A widget displaying a location message in the timeline.
pub struct LocationViewer(ObjectSubclass<imp::LocationViewer>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl LocationViewer {
/// Create a new location message.
pub fn new() -> Self {
glib::Object::new()
}
/// Whether to display this location in a compact format.
pub fn compact(&self) -> bool {
self.imp().compact.get()
}
/// Set the compact format of this location.
pub fn set_compact(&self, compact: bool) {
if self.compact() == compact {
return;
}
let map = &self.imp().map;
map.set_show_zoom_buttons(!compact);
if let Some(license) = map.license() {
license.set_visible(!compact);
}
self.imp().compact.set(compact);
self.notify("compact");
}
// Move the map viewport to the provided coordinates and draw a marker.
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()),
],
))]);
}
}