From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/ui/widget/preview.cpp | 511 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 src/ui/widget/preview.cpp (limited to 'src/ui/widget/preview.cpp') diff --git a/src/ui/widget/preview.cpp b/src/ui/widget/preview.cpp new file mode 100644 index 0000000..663d4b8 --- /dev/null +++ b/src/ui/widget/preview.cpp @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MPL-1.1 OR LGPL-2.1-or-later +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Eek Preview Stuffs. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include "preview.h" +#include "preferences.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +#define PRIME_BUTTON_MAGIC_NUMBER 1 + +/* Keep in sync with last value in eek-preview.h */ +#define PREVIEW_SIZE_LAST PREVIEW_SIZE_HUGE +#define PREVIEW_SIZE_NEXTFREE (PREVIEW_SIZE_HUGE + 1) + +#define PREVIEW_MAX_RATIO 500 + +void +Preview::set_color(int r, int g, int b ) +{ + _r = r; + _g = g; + _b = b; + + queue_draw(); +} + + +void +Preview::set_pixbuf(const Glib::RefPtr &pixbuf) +{ + _previewPixbuf = pixbuf; + + queue_draw(); + + if (_scaled) + { + _scaled.reset(); + } + + _scaledW = _previewPixbuf->get_width(); + _scaledH = _previewPixbuf->get_height(); +} + +static gboolean setupDone = FALSE; +static GtkRequisition sizeThings[PREVIEW_SIZE_NEXTFREE]; + +void +Preview::set_size_mappings( guint count, GtkIconSize const* sizes ) +{ + gint width = 0; + gint height = 0; + gint smallest = 512; + gint largest = 0; + guint i = 0; + guint delta = 0; + + for ( i = 0; i < count; ++i ) { + gboolean worked = gtk_icon_size_lookup( sizes[i], &width, &height ); + if ( worked ) { + if ( width < smallest ) { + smallest = width; + } + if ( width > largest ) { + largest = width; + } + } + } + + smallest = (smallest * 3) / 4; + + delta = largest - smallest; + + for ( i = 0; i < G_N_ELEMENTS(sizeThings); ++i ) { + guint val = smallest + ( (i * delta) / (G_N_ELEMENTS(sizeThings) - 1) ); + sizeThings[i].width = val; + sizeThings[i].height = val; + } + + setupDone = TRUE; +} + +void Preview::set_freesize(bool en) { + _freesize = en; +} + +void +Preview::size_request(GtkRequisition* req) const +{ + if (_freesize) { + req->width = req->height = 1; + return; + } + + int width = 0; + int height = 0; + + if ( !setupDone ) { + GtkIconSize sizes[] = { + GTK_ICON_SIZE_MENU, + GTK_ICON_SIZE_SMALL_TOOLBAR, + GTK_ICON_SIZE_LARGE_TOOLBAR, + GTK_ICON_SIZE_BUTTON, + GTK_ICON_SIZE_DIALOG + }; + set_size_mappings( G_N_ELEMENTS(sizes), sizes ); + } + + width = sizeThings[_size].width; + height = sizeThings[_size].height; + + if ( _view == VIEW_TYPE_LIST ) { + width *= 3; + } + + if ( _ratio != 100 ) { + width = (width * _ratio) / 100; + if ( width < 0 ) { + width = 1; + } + } + + req->width = width; + req->height = height; +} + +void +Preview::get_preferred_width_vfunc(int &minimal_width, int &natural_width) const +{ + GtkRequisition requisition; + size_request(&requisition); + minimal_width = natural_width = requisition.width; +} + +void +Preview::get_preferred_height_vfunc(int &minimal_height, int &natural_height) const +{ + GtkRequisition requisition; + size_request(&requisition); + minimal_height = natural_height = requisition.height; +} + +bool +Preview::on_draw(const Cairo::RefPtr &cr) +{ + auto allocation = get_allocation(); + + gint insetTop = 0, insetBottom = 0; + gint insetLeft = 0, insetRight = 0; + + if (_border == BORDER_SOLID) { + insetTop = 1; + insetLeft = 1; + } + if (_border == BORDER_SOLID_LAST_ROW) { + insetTop = insetBottom = 1; + insetLeft = 1; + } + if (_border == BORDER_WIDE) { + insetTop = insetBottom = 1; + insetLeft = insetRight = 1; + } + + auto context = get_style_context(); + + context->render_frame(cr, + 0, 0, + allocation.get_width(), allocation.get_height()); + + context->render_background(cr, + 0, 0, + allocation.get_width(), allocation.get_height()); + + // Border + if (_border != BORDER_NONE) { + cr->set_source_rgb(0.0, 0.0, 0.0); + cr->rectangle(0, 0, allocation.get_width(), allocation.get_height()); + cr->fill(); + } + + cr->set_source_rgb(_r/65535.0, _g/65535.0, _b/65535.0 ); + cr->rectangle(insetLeft, insetTop, allocation.get_width() - (insetLeft + insetRight), allocation.get_height() - (insetTop + insetBottom)); + cr->fill(); + + if (_previewPixbuf ) + { + if ((allocation.get_width() != _scaledW) || (allocation.get_height() != _scaledH)) { + if (_scaled) + { + _scaled.reset(); + } + + _scaledW = allocation.get_width() - (insetLeft + insetRight); + _scaledH = allocation.get_height() - (insetTop + insetBottom); + + _scaled = _previewPixbuf->scale_simple(_scaledW, + _scaledH, + Gdk::INTERP_BILINEAR); + } + + Glib::RefPtr pix = (_scaled) ? _scaled : _previewPixbuf; + + // Border + if (_border != BORDER_NONE) { + cr->set_source_rgb(0.0, 0.0, 0.0); + cr->rectangle(0, 0, allocation.get_width(), allocation.get_height()); + cr->fill(); + } + + Gdk::Cairo::set_source_pixbuf(cr, pix, insetLeft, insetTop); + cr->paint(); + } + + if (_linked) + { + /* Draw arrow */ + GdkRectangle possible = {insetLeft, + insetTop, + (allocation.get_width() - (insetLeft + insetRight)), + (allocation.get_height() - (insetTop + insetBottom)) + }; + + GdkRectangle area = {possible.x, + possible.y, + possible.width / 2, + possible.height / 2 }; + + /* Make it square */ + if ( area.width > area.height ) + area.width = area.height; + if ( area.height > area.width ) + area.height = area.width; + + /* Center it horizontally */ + if ( area.width < possible.width ) { + int diff = (possible.width - area.width) / 2; + area.x += diff; + } + + if (_linked & PREVIEW_LINK_IN) + { + context->render_arrow(cr, + G_PI, // Down-pointing arrow + area.x, area.y, + std::min(area.width, area.height) + ); + } + + if (_linked & PREVIEW_LINK_OUT) + { + GdkRectangle otherArea = {area.x, area.y, area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height); + } + + context->render_arrow(cr, + G_PI, // Down-pointing arrow + otherArea.x, otherArea.y, + std::min(otherArea.width, otherArea.height) + ); + } + + if (_linked & PREVIEW_LINK_OTHER) + { + GdkRectangle otherArea = {insetLeft, area.y, area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } + + context->render_arrow(cr, + 1.5*G_PI, // Left-pointing arrow + otherArea.x, otherArea.y, + std::min(otherArea.width, otherArea.height) + ); + } + + + if (_linked & PREVIEW_FILL) + { + GdkRectangle otherArea = {possible.x + ((possible.width / 4) - (area.width / 2)), + area.y, + area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } + context->render_check(cr, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); + } + + if (_linked & PREVIEW_STROKE) + { + GdkRectangle otherArea = {possible.x + (((possible.width * 3) / 4) - (area.width / 2)), + area.y, + area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } + // This should be a diamond too? + context->render_check(cr, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); + } + } + + + if ( has_focus() ) { + allocation = get_allocation(); + + context->render_focus(cr, + 0 + 1, 0 + 1, + allocation.get_width() - 2, allocation.get_height() - 2 ); + } + + return false; +} + + +bool +Preview::on_enter_notify_event(GdkEventCrossing* event ) +{ + _within = true; + set_state_flags(_hot ? Gtk::STATE_FLAG_ACTIVE : Gtk::STATE_FLAG_PRELIGHT, false); + + return false; +} + +bool +Preview::on_leave_notify_event(GdkEventCrossing* event) +{ + _within = false; + set_state_flags(Gtk::STATE_FLAG_NORMAL, false); + + return false; +} + +bool +Preview::on_button_press_event(GdkEventButton *event) +{ + if (_takesFocus && !has_focus() ) + { + grab_focus(); + } + + if ( event->button == PRIME_BUTTON_MAGIC_NUMBER || + event->button == 2 ) + { + _hot = true; + + if ( _within ) + { + set_state_flags(Gtk::STATE_FLAG_ACTIVE, false); + } + } + + return false; +} + +bool +Preview::on_button_release_event(GdkEventButton* event) +{ + _hot = false; + set_state_flags(Gtk::STATE_FLAG_NORMAL, false); + + if (_within && + (event->button == PRIME_BUTTON_MAGIC_NUMBER || + event->button == 2)) + { + gboolean isAlt = ( ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) || + (event->button == 2)); + + if ( isAlt ) + { + _signal_alt_clicked(2); + } + else + { + _signal_clicked.emit(); + } + } + + return false; +} + +void +Preview::set_linked(LinkType link) +{ + link = (LinkType)(link & PREVIEW_LINK_ALL); + + if (link != _linked) + { + _linked = link; + + queue_draw(); + } +} + +LinkType +Preview::get_linked() const +{ + return (LinkType)_linked; +} + +void +Preview::set_details(ViewType view, + PreviewSize size, + guint ratio, + guint border) +{ + _view = view; + + if ( size > PREVIEW_SIZE_LAST ) + { + size = PREVIEW_SIZE_LAST; + } + + _size = size; + + if ( ratio > PREVIEW_MAX_RATIO ) + { + ratio = PREVIEW_MAX_RATIO; + } + + _ratio = ratio; + _border = border; + + queue_draw(); +} + +Preview::Preview() + : _r(0x80), + _g(0x80), + _b(0xcc), + _scaledW(0), + _scaledH(0), + _hot(false), + _within(false), + _takesFocus(false), + _view(VIEW_TYPE_LIST), + _size(PREVIEW_SIZE_SMALL), + _ratio(100), + _border(BORDER_NONE), + _previewPixbuf(nullptr), + _scaled(nullptr), + _linked(PREVIEW_LINK_NONE) +{ + set_can_focus(true); + set_receives_default(true); + + set_sensitive(true); + + add_events(Gdk::BUTTON_PRESS_MASK + |Gdk::BUTTON_RELEASE_MASK + |Gdk::KEY_PRESS_MASK + |Gdk::KEY_RELEASE_MASK + |Gdk::FOCUS_CHANGE_MASK + |Gdk::ENTER_NOTIFY_MASK + |Gdk::LEAVE_NOTIFY_MASK ); +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3