Codebase list gnome-maps / feb76c24-716e-4fcd-b3e1-357626f6d9cc/main src / placeViewImage.js
feb76c24-716e-4fcd-b3e1-357626f6d9cc/main

Tree @feb76c24-716e-4fcd-b3e1-357626f6d9cc/main (Download .tar.gz)

placeViewImage.js @feb76c24-716e-4fcd-b3e1-357626f6d9cc/mainraw · history · blame

/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
/* vim: set et ts=4 sw=4: */
/*
 * Copyright (c) 2020 James Westman
 *
 * 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 <http://www.gnu.org/licenses/>.
 *
 * Author: James Westman <james@flyingpimonster.net>
 */

const Cairo = imports.cairo;
const Gdk = imports.gi.Gdk;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

/* The maximum aspect ratio, after which the image will be cropped vertically */
const MAX_ASPECT_RATIO = 1;

var PlaceViewImage = GObject.registerClass(
class PlaceViewImage extends Gtk.DrawingArea {
    _init(params) {
        super._init(params);

        this._pixbuf = null;
        this._cached = null;
    }

    get pixbuf() {
        return this._pixbuf;
    }

    set pixbuf(val) {
        /* crop the pixbuf to the max aspect ratio, if necessary */
        if (val.height / val.width > MAX_ASPECT_RATIO) {
            let y = (val.height - val.width * MAX_ASPECT_RATIO) / 2;
            val = val.new_subpixbuf(0, y, val.width, val.width * MAX_ASPECT_RATIO);
        }

        this._pixbuf = val;
        this.queue_resize();
    }

    vfunc_draw(cr) {
        let [{x, y, width, height}, baseline] = this.get_allocated_size();

        if (this._pixbuf === null || width === 0 || height === 0) {
            return;
        }

        width *= this.scale_factor;
        height *= this.scale_factor;

        /* Cache surfaces so we don't have to do as much scaling */
        if (this._cached === null || width !== this._cached.getWidth() || height !== this._cached.getHeight()) {
            // create a new, scaled image
            this._cached = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height);

            let cr_scaled = new Cairo.Context(this._cached);
            cr_scaled.scale(width / this._pixbuf.width, height / this._pixbuf.height);
            Gdk.cairo_set_source_pixbuf(cr_scaled, this._pixbuf, 0, 0);
            cr_scaled.paint();
        }

        cr.save();

        if (this.scale_factor !== 1) {
            cr.scale(1 / this.scale_factor, 1 / this.scale_factor);
        }

        cr.setSourceSurface(this._cached, 0, 0);

        cr.paint();
        cr.restore();

        return false;
    }

    vfunc_get_request_mode() {
        return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;
    }

    vfunc_get_preferred_height_for_width(width) {
        if (this._pixbuf) {
            let height = (this._pixbuf.height / this._pixbuf.width) * width;
            return [height, height];
        } else {
            return [0, 0];
        }
    }
});