gimp/libgimp/gimpzoompreview.c
Jehan 7a03b3ea09 libgimp: gimp_pdb_get_data() and gimp_pdb_set_data() are made internal.
These are not usable by plug-ins anymore which should store their data between
runs as arguments or aux arguments (in case of values which should be stored
from one run to another but are not really usable for non-interactive scripts).
These are per-plug-in (not polluting the whole process space with just random
strings as identifiers which could be used by other plug-ins) and even survive
restarts of GIMP.

I still keep these functions, but only internally, as they are used to store
settings of GimpAspectPreview, GimpDrawablePreview and GimpZoomPreview across
plug-in runs. Still I changed their API to set and return a GBytes directly
(mimicking the private PDB functions' API).
Also I remove gimp_pdb_get_data_size() which is useless when exchanging GBytes
directly.

Note that the 2 functions are still exported in the library, and only not
advertized through headers (so they are not really internal, just hidden), on
purpose, because we need to call them in libgimpui. So it is still relatively
easy for a plug-in to use them. Nevertheless I made clear in the function
documentation that these must not be considered public and could end up deleted
at any time. Any plug-in still trying to call these takes the risk of having
their code relying on unreliable API.
2023-10-27 10:16:45 +00:00

945 lines
31 KiB
C

/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimpzoompreview.c
* Copyright (C) 2005 David Odin <dindinx@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "gimpuitypes.h"
#include "gimp.h"
#include "gimppdb-private.h"
#include "gimpdrawablepreview.h"
#include "gimpzoompreview.h"
/**
* SECTION: gimpzoompreview
* @title: GimpZoomPreview
* @short_description: A drawable preview with zooming capabilities.
*
* A drawable preview with zooming capabilities.
**/
enum
{
PROP_0,
PROP_DRAWABLE,
PROP_MODEL
};
typedef struct
{
gboolean update;
} PreviewSettings;
struct _GimpZoomPreviewPrivate
{
GimpDrawable *drawable;
GimpZoomModel *model;
GdkRectangle extents;
};
#define GET_PRIVATE(obj) (((GimpZoomPreview *) (obj))->priv)
static void gimp_zoom_preview_constructed (GObject *object);
static void gimp_zoom_preview_finalize (GObject *object);
static void gimp_zoom_preview_dispose (GObject *object);
static void gimp_zoom_preview_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_zoom_preview_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_zoom_preview_set_adjustments (GimpZoomPreview *preview,
gdouble old_factor,
gdouble new_factor);
static void gimp_zoom_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation,
GimpZoomPreview *preview);
static void gimp_zoom_preview_style_updated (GtkWidget *widget);
static gboolean gimp_zoom_preview_scroll_event (GtkWidget *widget,
GdkEventScroll *event,
GimpZoomPreview *preview);
static void gimp_zoom_preview_draw (GimpPreview *preview);
static void gimp_zoom_preview_draw_buffer (GimpPreview *preview,
const guchar *buffer,
gint rowstride);
static void gimp_zoom_preview_draw_thumb (GimpPreview *preview,
GimpPreviewArea *area,
gint width,
gint height);
static void gimp_zoom_preview_set_cursor (GimpPreview *preview);
static void gimp_zoom_preview_transform (GimpPreview *preview,
gint src_x,
gint src_y,
gint *dest_x,
gint *dest_y);
static void gimp_zoom_preview_untransform (GimpPreview *preview,
gint src_x,
gint src_y,
gint *dest_x,
gint *dest_y);
static void gimp_zoom_preview_set_drawable (GimpZoomPreview *preview,
GimpDrawable *drawable);
static void gimp_zoom_preview_set_model (GimpZoomPreview *preview,
GimpZoomModel *model);
static void gimp_zoom_preview_get_source_area (GimpPreview *preview,
gint *x,
gint *y,
gint *w,
gint *h);
G_DEFINE_TYPE_WITH_PRIVATE (GimpZoomPreview, gimp_zoom_preview,
GIMP_TYPE_SCROLLED_PREVIEW)
#define parent_class gimp_zoom_preview_parent_class
static gint gimp_zoom_preview_counter = 0;
static void
gimp_zoom_preview_class_init (GimpZoomPreviewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GimpPreviewClass *preview_class = GIMP_PREVIEW_CLASS (klass);
object_class->constructed = gimp_zoom_preview_constructed;
object_class->finalize = gimp_zoom_preview_finalize;
object_class->dispose = gimp_zoom_preview_dispose;
object_class->get_property = gimp_zoom_preview_get_property;
object_class->set_property = gimp_zoom_preview_set_property;
widget_class->style_updated = gimp_zoom_preview_style_updated;
preview_class->draw = gimp_zoom_preview_draw;
preview_class->draw_buffer = gimp_zoom_preview_draw_buffer;
preview_class->draw_thumb = gimp_zoom_preview_draw_thumb;
preview_class->set_cursor = gimp_zoom_preview_set_cursor;
preview_class->transform = gimp_zoom_preview_transform;
preview_class->untransform = gimp_zoom_preview_untransform;
/**
* GimpZoomPreview:drawable-id:
*
* The drawable the #GimpZoomPreview is attached to.
*
* Since: 2.10
*/
g_object_class_install_property (object_class, PROP_DRAWABLE,
g_param_spec_object ("drawable",
"Drawable",
"The drawable this preview is attached to",
GIMP_TYPE_DRAWABLE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* GimpZoomPreview:model:
*
* The #GimpZoomModel used by this #GimpZoomPreview.
*
* Since: 2.4
*/
g_object_class_install_property (object_class, PROP_MODEL,
g_param_spec_object ("model",
"Model",
"The zoom preview's GimpZoomModel",
GIMP_TYPE_ZOOM_MODEL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
gimp_zoom_preview_init (GimpZoomPreview *preview)
{
GtkWidget *area = gimp_preview_get_area (GIMP_PREVIEW (preview));
preview->priv = gimp_zoom_preview_get_instance_private (preview);
g_signal_connect (area, "size-allocate",
G_CALLBACK (gimp_zoom_preview_size_allocate),
preview);
g_signal_connect (area, "scroll-event",
G_CALLBACK (gimp_zoom_preview_scroll_event),
preview);
g_object_set (area,
"check-size", gimp_check_size (),
"check-type", gimp_check_type (),
"check-custom-color1", gimp_check_custom_color1 (),
"check-custom-color2", gimp_check_custom_color2 (),
NULL);
gimp_scrolled_preview_set_policy (GIMP_SCROLLED_PREVIEW (preview),
GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
}
static void
gimp_zoom_preview_constructed (GObject *object)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (object);
gchar *data_name;
PreviewSettings settings;
GBytes *settings_bytes = NULL;
G_OBJECT_CLASS (parent_class)->constructed (object);
data_name = g_strdup_printf ("%s-zoom-preview-%d",
g_get_prgname (),
gimp_zoom_preview_counter++);
if (gimp_pdb_get_data (data_name, &settings_bytes) &&
g_bytes_get_size (settings_bytes) == sizeof (PreviewSettings))
{
settings = *((PreviewSettings *) g_bytes_get_data (settings_bytes, NULL));
gimp_preview_set_update (GIMP_PREVIEW (object), settings.update);
}
g_bytes_unref (settings_bytes);
g_object_set_data_full (object, "gimp-zoom-preview-data-name",
data_name, (GDestroyNotify) g_free);
if (! priv->model)
{
GimpZoomModel *model = gimp_zoom_model_new ();
gimp_zoom_model_set_range (model, 1.0, 256.0);
gimp_zoom_preview_set_model (GIMP_ZOOM_PREVIEW (object), model);
g_object_unref (model);
}
gimp_zoom_preview_set_adjustments (GIMP_ZOOM_PREVIEW (object), 1.0, 1.0);
}
static void
gimp_zoom_preview_finalize (GObject *object)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (object);
g_clear_object (&priv->model);
g_clear_object (&priv->drawable);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_zoom_preview_dispose (GObject *object)
{
const gchar *data_name = g_object_get_data (G_OBJECT (object),
"gimp-zoom-preview-data-name");
if (data_name)
{
GimpPreview *preview = GIMP_PREVIEW (object);
GBytes *bytes;
PreviewSettings settings;
settings.update = gimp_preview_get_update (preview);
bytes = g_bytes_new_static (&settings, sizeof (PreviewSettings));
gimp_pdb_set_data (data_name, bytes);
g_bytes_unref (bytes);
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gimp_zoom_preview_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpZoomPreview *preview = GIMP_ZOOM_PREVIEW (object);
switch (property_id)
{
case PROP_DRAWABLE:
g_value_set_object (value, gimp_zoom_preview_get_drawable (preview));
break;
case PROP_MODEL:
g_value_set_object (value, gimp_zoom_preview_get_model (preview));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_zoom_preview_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpZoomPreview *preview = GIMP_ZOOM_PREVIEW (object);
switch (property_id)
{
case PROP_DRAWABLE:
gimp_zoom_preview_set_drawable (preview, g_value_dup_object (value));
break;
case PROP_MODEL:
gimp_zoom_preview_set_model (preview, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_zoom_preview_set_adjustments (GimpZoomPreview *preview,
gdouble old_factor,
gdouble new_factor)
{
GimpScrolledPreview *scrolled_preview = GIMP_SCROLLED_PREVIEW (preview);
GtkAdjustment *hadj;
GtkAdjustment *vadj;
gint width;
gint height;
gdouble ratio;
gimp_scrolled_preview_freeze (scrolled_preview);
gimp_preview_get_size (GIMP_PREVIEW (preview), &width, &height);
ratio = new_factor / old_factor;
gimp_scrolled_preview_get_adjustments (scrolled_preview, &hadj, &vadj);
gtk_adjustment_configure (hadj,
(gtk_adjustment_get_value (vadj) + width / 2.0) * ratio
- width / 2.0,
0,
width * new_factor,
new_factor,
MAX (width / 2.0, new_factor),
width);
gtk_adjustment_configure (vadj,
(gtk_adjustment_get_value (vadj) + height / 2.0) * ratio
- height / 2.0,
0,
height * new_factor,
new_factor,
MAX (height / 2.0, new_factor),
height);
gimp_scrolled_preview_thaw (scrolled_preview);
}
static void
gimp_zoom_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation,
GimpZoomPreview *preview)
{
gdouble zoom;
#if 0
gint width = GIMP_PREVIEW (preview)->xmax - GIMP_PREVIEW (preview)->xmin;
gint height = GIMP_PREVIEW (preview)->ymax - GIMP_PREVIEW (preview)->ymin;
GIMP_PREVIEW (preview)->width = MIN (width, allocation->width);
GIMP_PREVIEW (preview)->height = MIN (height, allocation->height);
#endif
zoom = gimp_zoom_model_get_factor (preview->priv->model);
gimp_zoom_preview_set_adjustments (preview, zoom, zoom);
}
static void
gimp_zoom_preview_style_updated (GtkWidget *widget)
{
GimpPreview *preview = GIMP_PREVIEW (widget);
GtkWidget *area = gimp_preview_get_area (preview);
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
if (area)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (preview);
gint size;
gint width;
gint height;
gint preview_width;
gint preview_height;
gint x1, y1;
gint x2, y2;
gtk_widget_style_get (widget, "size", &size, NULL);
if (_gimp_drawable_preview_get_bounds (priv->drawable,
&x1, &y1, &x2, &y2))
{
width = x2 - x1;
height = y2 - y1;
}
else
{
width = gimp_drawable_get_width (priv->drawable);
height = gimp_drawable_get_height (priv->drawable);
}
if (width > height)
{
preview_width = MIN (width, size);
preview_height = (height * preview_width) / width;
}
else
{
preview_height = MIN (height, size);
preview_width = (width * preview_height) / height;
}
gimp_preview_set_size (preview, preview_width, preview_height);
}
}
static gboolean
gimp_zoom_preview_scroll_event (GtkWidget *widget,
GdkEventScroll *event,
GimpZoomPreview *preview)
{
if (event->state & GDK_CONTROL_MASK)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (preview);
gdouble delta;
gimp_scrolled_preview_freeze (GIMP_SCROLLED_PREVIEW (preview));
switch (event->direction)
{
case GDK_SCROLL_UP:
gimp_zoom_model_zoom (priv->model, GIMP_ZOOM_IN, 0.0);
break;
case GDK_SCROLL_DOWN:
gimp_zoom_model_zoom (priv->model, GIMP_ZOOM_OUT, 0.0);
break;
case GDK_SCROLL_SMOOTH:
gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta);
gimp_zoom_model_zoom (priv->model, GIMP_ZOOM_SMOOTH, delta);
break;
default:
break;
}
gimp_scrolled_preview_thaw (GIMP_SCROLLED_PREVIEW (preview));
}
return FALSE;
}
static void
gimp_zoom_preview_draw (GimpPreview *preview)
{
GimpZoomPreviewPrivate *priv = GIMP_ZOOM_PREVIEW (preview)->priv;
guchar *data;
gint width;
gint height;
gint bpp;
if (! priv->model)
return;
if (priv->drawable == NULL)
return;
data = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview),
&width, &height, &bpp);
if (data)
{
GtkWidget *area = gimp_preview_get_area (preview);
gimp_preview_area_draw (GIMP_PREVIEW_AREA (area),
0, 0, width, height,
gimp_drawable_type (priv->drawable),
data, width * bpp);
g_free (data);
}
}
static void
gimp_zoom_preview_draw_buffer (GimpPreview *preview,
const guchar *buffer,
gint rowstride)
{
GimpZoomPreviewPrivate *priv = GIMP_ZOOM_PREVIEW (preview)->priv;
GtkWidget *area = gimp_preview_get_area (preview);
GimpImage *image;
gint width;
gint height;
gimp_preview_get_size (preview, &width, &height);
image = gimp_item_get_image (GIMP_ITEM (priv->drawable));
if (gimp_selection_is_empty (image))
{
gimp_preview_area_draw (GIMP_PREVIEW_AREA (area),
0, 0,
width, height,
gimp_drawable_type (priv->drawable),
buffer,
rowstride);
}
else
{
GBytes *sel;
GBytes *src;
GimpSelection *selection;
gint w, h;
gint bpp;
gint src_x;
gint src_y;
gint src_width;
gint src_height;
gint offsx = 0;
gint offsy = 0;
selection = gimp_image_get_selection (image);
gimp_zoom_preview_get_source_area (preview,
&src_x, &src_y,
&src_width, &src_height);
src = gimp_drawable_get_sub_thumbnail_data (priv->drawable,
src_x, src_y,
src_width, src_height,
width, height,
&w, &h, &bpp);
gimp_drawable_get_offsets (priv->drawable, &offsx, &offsy);
sel = gimp_drawable_get_sub_thumbnail_data (GIMP_DRAWABLE (selection),
src_x + offsx, src_y + offsy,
src_width, src_height,
width, height,
&w, &h, &bpp);
gimp_preview_area_mask (GIMP_PREVIEW_AREA (area),
0, 0, width, height,
gimp_drawable_type (priv->drawable),
g_bytes_get_data (src, NULL), width * gimp_drawable_get_bpp (priv->drawable),
buffer, rowstride,
g_bytes_get_data (sel, NULL), width);
g_bytes_unref (sel);
g_bytes_unref (src);
}
}
static void
gimp_zoom_preview_draw_thumb (GimpPreview *preview,
GimpPreviewArea *area,
gint width,
gint height)
{
GimpZoomPreviewPrivate *priv = GIMP_ZOOM_PREVIEW (preview)->priv;
if (priv->drawable != NULL)
_gimp_drawable_preview_area_draw_thumb (area, priv->drawable,
width, height);
}
static void
gimp_zoom_preview_set_cursor (GimpPreview *preview)
{
GtkWidget *area = gimp_preview_get_area (preview);
if (! gtk_widget_get_realized (area))
return;
if (gimp_zoom_preview_get_factor (GIMP_ZOOM_PREVIEW (preview)) > 1.0)
{
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (preview));
GdkCursor *cursor;
cursor = gdk_cursor_new_for_display (display, GDK_HAND1);
gdk_window_set_cursor (gtk_widget_get_window (area),
cursor);
g_object_unref (cursor);
}
else
{
gdk_window_set_cursor (gtk_widget_get_window (area),
gimp_preview_get_default_cursor (preview));
}
}
static void
gimp_zoom_preview_transform (GimpPreview *preview,
gint src_x,
gint src_y,
gint *dest_x,
gint *dest_y)
{
GimpZoomPreviewPrivate *priv = GIMP_ZOOM_PREVIEW (preview)->priv;
gint width;
gint height;
gint xoff;
gint yoff;
gdouble zoom;
gimp_preview_get_size (preview, &width, &height);
gimp_preview_get_offsets (preview, &xoff, &yoff);
zoom = gimp_zoom_preview_get_factor (GIMP_ZOOM_PREVIEW (preview));
*dest_x = ((gdouble) (src_x - priv->extents.x) *
width / priv->extents.width * zoom) - xoff;
*dest_y = ((gdouble) (src_y - priv->extents.y) *
height / priv->extents.height * zoom) - yoff;
}
static void
gimp_zoom_preview_untransform (GimpPreview *preview,
gint src_x,
gint src_y,
gint *dest_x,
gint *dest_y)
{
GimpZoomPreviewPrivate *priv = GIMP_ZOOM_PREVIEW (preview)->priv;
gint width;
gint height;
gint xoff;
gint yoff;
gdouble zoom;
gimp_preview_get_size (preview, &width, &height);
gimp_preview_get_offsets (preview, &xoff, &yoff);
zoom = gimp_zoom_preview_get_factor (GIMP_ZOOM_PREVIEW (preview));
*dest_x = (priv->extents.x +
((gdouble) (src_x + xoff) *
priv->extents.width / width / zoom));
*dest_y = (priv->extents.y +
((gdouble) (src_y + yoff) *
priv->extents.height / height / zoom));
}
static void
gimp_zoom_preview_set_drawable (GimpZoomPreview *preview,
GimpDrawable *drawable)
{
GimpZoomPreviewPrivate *priv = preview->priv;
gint x, y;
gint width, height;
gint max_width, max_height;
g_return_if_fail (preview->priv->drawable == NULL);
priv->drawable = drawable;
if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
{
priv->extents.x = x;
priv->extents.y = y;
}
else
{
width = gimp_drawable_get_width (drawable);
height = gimp_drawable_get_height (drawable);
priv->extents.x = 0;
priv->extents.y = 0;
}
priv->extents.width = width;
priv->extents.height = height;
if (width > height)
{
max_width = MIN (width, 512);
max_height = (height * max_width) / width;
}
else
{
max_height = MIN (height, 512);
max_width = (width * max_height) / height;
}
gimp_preview_set_bounds (GIMP_PREVIEW (preview),
0, 0, max_width, max_height);
g_object_set (gimp_preview_get_frame (GIMP_PREVIEW (preview)),
"ratio", (gdouble) width / (gdouble) height,
NULL);
}
static void
gimp_zoom_preview_set_model (GimpZoomPreview *preview,
GimpZoomModel *model)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (preview);
GtkWidget *button_bar;
GtkWidget *button;
GtkWidget *box;
g_return_if_fail (priv->model == NULL);
if (! model)
return;
priv->model = g_object_ref (model);
g_signal_connect_swapped (priv->model, "zoomed",
G_CALLBACK (gimp_zoom_preview_set_adjustments),
preview);
box = gimp_preview_get_controls (GIMP_PREVIEW (preview));
g_return_if_fail (GTK_IS_BOX (box));
button_bar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_end (GTK_BOX (box), button_bar, FALSE, FALSE, 0);
gtk_widget_show (button_bar);
/* zoom out */
button = gimp_zoom_button_new (priv->model,
GIMP_ZOOM_OUT, GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_box_pack_start (GTK_BOX (button_bar), button, FALSE, FALSE, 0);
gtk_widget_show (button);
/* zoom in */
button = gimp_zoom_button_new (priv->model,
GIMP_ZOOM_IN, GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_box_pack_start (GTK_BOX (button_bar), button, FALSE, FALSE, 0);
gtk_widget_show (button);
}
static void
gimp_zoom_preview_get_source_area (GimpPreview *preview,
gint *x,
gint *y,
gint *w,
gint *h)
{
GimpZoomPreviewPrivate *priv = GET_PRIVATE (preview);
gdouble zoom = gimp_zoom_model_get_factor (priv->model);
gimp_zoom_preview_untransform (preview, 0, 0, x, y);
*w = priv->extents.width / zoom;
*h = priv->extents.height / zoom;
}
/**
* gimp_zoom_preview_new_from_drawable:
* @drawable: (transfer none): a drawable
*
* Creates a new #GimpZoomPreview widget for @drawable.
*
* Since: 3.0
*
* Returns: a new #GimpZoomPreview.
**/
GtkWidget *
gimp_zoom_preview_new_from_drawable (GimpDrawable *drawable)
{
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (gimp_item_is_valid (GIMP_ITEM (drawable)), NULL);
return g_object_new (GIMP_TYPE_ZOOM_PREVIEW,
"drawable", drawable,
NULL);
}
/**
* gimp_zoom_preview_new_with_model_from_drawable:
* @drawable: a #GimpDrawable
* @model: a #GimpZoomModel
*
* Creates a new #GimpZoomPreview widget for @drawable using the
* given @model.
*
* This variant of gimp_zoom_preview_new_from_drawable() allows you
* to create a preview using an existing zoom model. This may be
* useful if for example you want to have two zoom previews that keep
* their zoom factor in sync.
*
* Since: 2.10
*
* Returns: a new #GimpZoomPreview.
**/
GtkWidget *
gimp_zoom_preview_new_with_model_from_drawable (GimpDrawable *drawable,
GimpZoomModel *model)
{
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (gimp_item_is_valid (GIMP_ITEM (drawable)), NULL);
g_return_val_if_fail (GIMP_IS_ZOOM_MODEL (model), NULL);
return g_object_new (GIMP_TYPE_ZOOM_PREVIEW,
"drawable", drawable,
"model", model,
NULL);
}
/**
* gimp_zoom_preview_get_drawable:
* @preview: a #GimpZoomPreview widget
*
* Returns the drawable the #GimpZoomPreview is attached to.
*
* Returns: (transfer none): the drawable that was passed to
* gimp_zoom_preview_new_from_drawable().
*
* Since: 3.0
**/
GimpDrawable *
gimp_zoom_preview_get_drawable (GimpZoomPreview *preview)
{
g_return_val_if_fail (GIMP_IS_ZOOM_PREVIEW (preview), NULL);
return GET_PRIVATE (preview)->drawable;
}
/**
* gimp_zoom_preview_get_model:
* @preview: a #GimpZoomPreview widget
*
* Returns the #GimpZoomModel the preview is using.
*
* Returns: (transfer none): a pointer to the #GimpZoomModel owned
* by the @preview
*
* Since: 2.4
**/
GimpZoomModel *
gimp_zoom_preview_get_model (GimpZoomPreview *preview)
{
g_return_val_if_fail (GIMP_IS_ZOOM_PREVIEW (preview), NULL);
return GET_PRIVATE (preview)->model;
}
/**
* gimp_zoom_preview_get_factor:
* @preview: a #GimpZoomPreview widget
*
* Returns the zoom factor the preview is currently using.
*
* Returns: the current zoom factor
*
* Since: 2.4
**/
gdouble
gimp_zoom_preview_get_factor (GimpZoomPreview *preview)
{
GimpZoomPreviewPrivate *priv;
g_return_val_if_fail (GIMP_IS_ZOOM_PREVIEW (preview), 1.0);
priv = GET_PRIVATE (preview);
return priv->model ? gimp_zoom_model_get_factor (priv->model) : 1.0;
}
/**
* gimp_zoom_preview_get_source:
* @preview: a #GimpZoomPreview widget
* @width: (out): a pointer to an int where the current width of the zoom widget
* will be put.
* @height: (out): a pointer to an int where the current width of the zoom widget
* will be put.
* @bpp: (out): return location for the number of bytes per pixel
*
* Returns the scaled image data of the part of the drawable the
* #GimpZoomPreview is currently showing, as a newly allocated array of guchar.
* This function also allow to get the current width, height and bpp of the
* #GimpZoomPreview.
*
* Returns: (transfer full) (array): newly allocated data that should be
* released using g_free() when it is not any longer needed
*
* Since: 2.4
*/
guchar *
gimp_zoom_preview_get_source (GimpZoomPreview *preview,
gint *width,
gint *height,
gint *bpp)
{
GimpDrawable *drawable;
g_return_val_if_fail (GIMP_IS_ZOOM_PREVIEW (preview), NULL);
g_return_val_if_fail (width != NULL && height != NULL && bpp != NULL, NULL);
drawable = gimp_zoom_preview_get_drawable (preview);
if (drawable)
{
GimpPreview *gimp_preview = GIMP_PREVIEW (preview);
gint src_x;
gint src_y;
gint src_width;
gint src_height;
GBytes *src_bytes;
gsize src_bytes_size;
gimp_preview_get_size (gimp_preview, width, height);
gimp_zoom_preview_get_source_area (gimp_preview,
&src_x, &src_y,
&src_width, &src_height);
src_bytes = gimp_drawable_get_sub_thumbnail_data (drawable,
src_x, src_y,
src_width, src_height,
*width, *height,
width, height, bpp);
return g_bytes_unref_to_data (src_bytes, &src_bytes_size);
}
else
{
*width = 0;
*height = 0;
*bpp = 0;
return NULL;
}
}