/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
/* vim: set et ts=4 sw=4: */
/*
* GNOME Maps is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* GNOME Maps is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with GNOME Maps; if not, see .
*
* Author: Jonas Danielsson
*/
const Champlain = imports.gi.Champlain;
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const GtkClutter = imports.gi.GtkClutter;
const System = imports.system;
const Service = imports.service;
const Utils = imports.utils;
let _attributionImages = [];
const _FILE_CACHE_SIZE_LIMIT = (10 * 1024 * 1024); /* 10Mb */
const _MEMORY_CACHE_SIZE_LIMIT = 100; /* number of tiles */
const _LOGO_PADDING_X = 10;
const _LOGO_PADDING_Y = 25;
// extra padding below logo in RTL, where scale will be on the right side
const _LOGO_PADDING_Y_RTL = 35;
var AttributionLogo = GObject.registerClass({},
class AttributionLogo extends GtkClutter.Actor {
_init(view) {
super._init();
this._view = view;
this._rtl = Gtk.get_locale_direction() === Gtk.TextDirection.RTL;
view.connect('notify::width', () => this._updatePosition());
view.connect('notify::height', () => this._updatePosition());
this._updatePosition(view);
}
setSource(source) {
this._id = source.get_id();
let bin = this.get_widget();
if (bin.get_child())
bin.remove(bin.get_child());
if (_attributionImages[source.get_id()]) {
bin.add(_attributionImages[source.get_id()]);
bin.visible = true;
} else {
bin.visible = false;
}
this._updatePosition();
}
_updatePosition() {
let image = _attributionImages[this._id];
if (image) {
let width = image.pixbuf.width;
let height = image.pixbuf.height;
let x = this._view.width - width - _LOGO_PADDING_X;
/* TODO: ideally the attribution logo should be aligned to the left
* side in RTL locales, but I couldn't get that working with Clutter
* actor positioning, so adjust the padding to fit above the scale
* for now
*/
let y = this._view.height - height -
(this._rtl ? _LOGO_PADDING_Y_RTL : _LOGO_PADDING_Y);
this.set_position(x, y);
}
}
});
function _updateAttributionImage(source) {
if (!source.attribution_logo || source.attribution_logo === "")
return;
if (!_attributionImages[source.id])
_attributionImages[source.id] = new Gtk.Image({ visible: true });
let data = GLib.base64_decode(source.attribution_logo);
let stream = Gio.MemoryInputStream.new_from_bytes(GLib.Bytes.new(data));
_attributionImages[source.id].pixbuf =
GdkPixbuf.Pixbuf.new_from_stream(stream, null);
}
function _createTileSource(source) {
let tileSource = new Champlain.NetworkTileSource({
id: source.id,
name: source.name,
license: source.license,
license_uri: source.license_uri,
min_zoom_level: source.min_zoom_level,
max_zoom_level: source.max_zoom_level,
tile_size: source.tile_size,
renderer: new Champlain.ImageRenderer(),
uri_format: source.uri_format
});
tileSource.max_conns = source.max_connections;
return tileSource;
}
function _createCachedSource(source) {
let tileSource = _createTileSource(source);
_updateAttributionImage(source);
let fileCache = new Champlain.FileCache({
size_limit: _FILE_CACHE_SIZE_LIMIT,
renderer: new Champlain.ImageRenderer()
});
let memoryCache = new Champlain.MemoryCache({
size_limit: _MEMORY_CACHE_SIZE_LIMIT,
renderer: new Champlain.ImageRenderer()
});
let errorSource = new Champlain.NullTileSource({
renderer: new Champlain.ImageRenderer()
});
/*
* When the a source in the chain fails to load a given tile
* the next one in the chain tries instead. Until we get to the error
* source.
*/
let sourceChain = new Champlain.MapSourceChain();
sourceChain.push(errorSource);
sourceChain.push(tileSource);
sourceChain.push(fileCache);
sourceChain.push(memoryCache);
return sourceChain;
}
function createAerialSource() {
return _createCachedSource(Service.getService().tiles.aerial);
}
function createHybridAerialSource() {
return _createCachedSource(Service.getService().tiles.hybridAerial);
}
function createStreetSource() {
return _createCachedSource(Service.getService().tiles.street);
}
function createStreetDarkSource() {
return _createCachedSource(Service.getService().tiles.streetDark)
}
function createPrintSource() {
return _createCachedSource(Service.getService().tiles.print);
}