/* -*- 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 . * * Author: James Westman */ import Cairo from 'cairo'; import Gdk from 'gi://Gdk'; import GObject from 'gi://GObject'; import Graphene from 'gi://Graphene'; import Gtk from 'gi://Gtk'; /* The maximum aspect ratio, after which the image will be cropped vertically */ const MAX_ASPECT_RATIO = 1; export class PlaceViewImage extends Gtk.DrawingArea { constructor(params) { super(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_snapshot(snapshot) { let {x, y, width, height} = this.get_allocation(); if (this._pixbuf === null || width === 0 || height === 0) { return; } let rect = new Graphene.Rect(); rect.init(x, y, width, height); let cr = snapshot.append_cairo(rect); 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(); super.vfunc_snapshot(snapshot); cr.$dispose(); } vfunc_get_request_mode() { return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH; } vfunc_measure(orientation, forSize) { if (orientation === Gtk.Orientation.VERTICAL) { if (this._pixbuf) { let height = (this._pixbuf.height / this._pixbuf.width) * forSize; return [height, height, 0, 0]; } else { return [0, 0, 0, 0]; } } else { return [forSize, forSize, 0, 0]; } } /* 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]; } } */ } GObject.registerClass(PlaceViewImage);