app, libgimp, pdb: new gimp_pattern_get_buffer() and improved GimpPatternSelectButton.

Similar to the latest commits for GimpBrush:

- gimp_pattern_get_buffer() returns a GeglBuffer and allow getting a scaled
  version of the pattern.
- Old gimp_pattern_get_pixels() is made private.
- Moved GimpPattern into its own file and store the buffer to avoid re-querying
  it through PDB continuously.

No as for the widget to select a pattern:

- Preview frame ensured to be square.
- Default size increased.
- Drawing code using the new gimp_pattern_get_buffer().
- Cleaned up code.
This commit is contained in:
Jehan 2023-08-19 00:13:36 +02:00
parent 330d05e2fc
commit 457f52a6d1
12 changed files with 405 additions and 209 deletions

View File

@ -252,7 +252,7 @@ register_pattern_procs (GimpPDB *pdb)
"gimp-pattern-get-pixels"); "gimp-pattern-get-pixels");
gimp_procedure_set_static_help (procedure, gimp_procedure_set_static_help (procedure,
"Gets information about the pattern (including pixels).", "Gets information about the pattern (including pixels).",
"Gets information about the pattern: the pattern extents (width and height), its bpp, and its pixel data. The pixel data is an array in C or a list in some languages.", "Gets information about the pattern: the pattern extents (width and height), its bpp, and its pixel data.",
NULL); NULL);
gimp_procedure_set_static_attribution (procedure, gimp_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>", "Michael Natterer <mitch@gimp.org>",

View File

@ -680,9 +680,9 @@ EXPORTS
gimp_param_spec_vectors gimp_param_spec_vectors
gimp_param_text_layer_get_type gimp_param_text_layer_get_type
gimp_param_vectors_get_type gimp_param_vectors_get_type
gimp_pattern_get_buffer
gimp_pattern_get_by_name gimp_pattern_get_by_name
gimp_pattern_get_info gimp_pattern_get_info
gimp_pattern_get_pixels
gimp_pattern_get_type gimp_pattern_get_type
gimp_patterns_close_popup gimp_patterns_close_popup
gimp_patterns_get_list gimp_patterns_get_list

View File

@ -51,6 +51,7 @@
#include <libgimp/gimplayermask.h> #include <libgimp/gimplayermask.h>
#include <libgimp/gimploadprocedure.h> #include <libgimp/gimploadprocedure.h>
#include <libgimp/gimpparamspecs.h> #include <libgimp/gimpparamspecs.h>
#include <libgimp/gimppattern.h>
#include <libgimp/gimppdb.h> #include <libgimp/gimppdb.h>
#include <libgimp/gimpplugin.h> #include <libgimp/gimpplugin.h>
#include <libgimp/gimpprocedureconfig.h> #include <libgimp/gimpprocedureconfig.h>

207
libgimp/gimppattern.c Normal file
View File

@ -0,0 +1,207 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimppattern.c
* Copyright (C) 2023 Jehan
*
* 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 "gimp.h"
#include "gimppattern.h"
struct _GimpPattern
{
GimpResource parent_instance;
/* Native size buffer of the pattern contents. */
GeglBuffer *buffer;
};
static void gimp_pattern_finalize (GObject *object);
static void gimp_pattern_get_data (GimpPattern *pattern);
static GeglBuffer * gimp_pattern_scale (GeglBuffer *buffer,
gint max_width,
gint max_height);
G_DEFINE_TYPE (GimpPattern, gimp_pattern, GIMP_TYPE_RESOURCE);
static void gimp_pattern_class_init (GimpPatternClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gimp_pattern_finalize;
}
static void gimp_pattern_init (GimpPattern *pattern)
{
pattern->buffer = NULL;
}
static void
gimp_pattern_finalize (GObject *object)
{
GimpPattern *pattern = GIMP_PATTERN (object);
g_clear_object (&pattern->buffer);
G_OBJECT_CLASS (gimp_pattern_parent_class)->finalize (object);
}
/**
* gimp_pattern_get_buffer:
* @pattern: a [class@Pattern].
* @max_width: a maximum width for the returned buffer.
* @max_height: a maximum height for the returned buffer.
* @format: an optional Babl format.
*
* Gets pixel data of the pattern within the bounding box specified by @max_width
* and @max_height. The data will be scaled down so that it fits within this
* size without changing its ratio. If the pattern is smaller than this size to
* begin with, it will not be scaled up.
*
* If @max_width or @max_height are %NULL, the buffer is returned in the pattern's
* native size.
*
* Make sure you called [func@Gegl.Init] before calling any function using
* `GEGL`.
*
* Returns: (transfer full): a [Gegl@Buffer].
*/
GeglBuffer *
gimp_pattern_get_buffer (GimpPattern *pattern,
gint max_width,
gint max_height,
const Babl *format)
{
gimp_pattern_get_data (pattern);
g_return_val_if_fail (pattern->buffer != NULL, NULL);
if (max_width == 0 || max_height == 0 ||
(gegl_buffer_get_width (pattern->buffer) <= max_width &&
gegl_buffer_get_height (pattern->buffer) <= max_height))
return gegl_buffer_dup (pattern->buffer);
return gimp_pattern_scale (pattern->buffer, max_width, max_height);
}
static void
gimp_pattern_get_data (GimpPattern *pattern)
{
gint width;
gint height;
gint bpp;
GBytes *bytes;
const guchar *pixels;
gsize pixels_size;
const Babl *format;
/*
* This check assumes that the pattern contents doesn't change, which is not a
* perfect assumption. We could maybe add a PDB call which would return
* the new pattern data only if it changed since last call (which can be
* verified with some kind of internal runtime version to pass from one call
* to another). TODO
*/
if (pattern->buffer != NULL)
return;
g_clear_object (&pattern->buffer);
_gimp_pattern_get_pixels (pattern, &width, &height, &bpp, &bytes);
pixels = g_bytes_unref_to_data (bytes, &pixels_size);
/* It's an ugly way to determine the proper format but gimp_pattern_get_pixels()
* doesn't give more info.
*/
switch (bpp)
{
case 1:
format = babl_format ("Y' u8");
break;
case 2:
format = babl_format ("Y'A u8");
break;
case 3:
format = babl_format ("R'G'B' u8");
break;
case 4:
format = babl_format ("R'G'B'A u8");
break;
default:
g_return_if_reached ();
}
pattern->buffer = gegl_buffer_linear_new_from_data ((const gpointer) pixels, format,
GEGL_RECTANGLE (0, 0, width, height),
0, g_free, NULL);
}
static GeglBuffer *
gimp_pattern_scale (GeglBuffer *buffer,
gint max_width,
gint max_height)
{
GeglBuffer *scaled = NULL;
GeglNode *graph;
GeglNode *source;
GeglNode *op;
GeglNode *sink;
gdouble width;
gdouble height;
gdouble scale;
height = (gdouble) max_height;
width = (gdouble) gegl_buffer_get_width (buffer) / gegl_buffer_get_height (buffer) * height;
if (width > (gdouble) max_width)
{
width = (gdouble) max_width;
height = (gdouble) gegl_buffer_get_height (buffer) / gegl_buffer_get_width (buffer) * width;
}
scale = width / gegl_buffer_get_width (buffer);
graph = gegl_node_new ();
source = gegl_node_new_child (graph,
"operation", "gegl:buffer-source",
"buffer", buffer,
NULL);
op = gegl_node_new_child (graph,
"operation", "gegl:scale-ratio",
"origin-x", 0.0,
"origin-y", 0.0,
"sampler", GIMP_INTERPOLATION_LINEAR,
"abyss-policy", GEGL_ABYSS_CLAMP,
"x", scale,
"y", scale,
NULL);
sink = gegl_node_new_child (graph,
"operation", "gegl:buffer-sink",
"buffer", &scaled,
"format", gegl_buffer_get_format (buffer),
NULL);
gegl_node_link_many (source, op, sink, NULL);
gegl_node_process (sink);
g_object_unref (graph);
return scaled;
}

49
libgimp/gimppattern.h Normal file
View File

@ -0,0 +1,49 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimppattern.h
* Copyright (C) 2023 Jehan
*
* 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/>.
*/
#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION)
#error "Only <libgimp/gimp.h> can be included directly."
#endif
#ifndef __GIMP_PATTERN_H__
#define __GIMP_PATTERN_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#include <libgimp/gimpresource.h>
#define GIMP_TYPE_PATTERN (gimp_pattern_get_type ())
G_DECLARE_FINAL_TYPE (GimpPattern, gimp_pattern, GIMP, PATTERN, GimpResource)
GeglBuffer * gimp_pattern_get_buffer (GimpPattern *pattern,
gint max_width,
gint max_height,
const Babl *format) G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS
#endif /* __GIMP_PATTERN_H__ */

View File

@ -126,7 +126,7 @@ gimp_pattern_get_info (GimpPattern *pattern,
} }
/** /**
* gimp_pattern_get_pixels: * _gimp_pattern_get_pixels:
* @pattern: The pattern. * @pattern: The pattern.
* @width: (out): The pattern width. * @width: (out): The pattern width.
* @height: (out): The pattern height. * @height: (out): The pattern height.
@ -136,15 +136,14 @@ gimp_pattern_get_info (GimpPattern *pattern,
* Gets information about the pattern (including pixels). * Gets information about the pattern (including pixels).
* *
* Gets information about the pattern: the pattern extents (width and * Gets information about the pattern: the pattern extents (width and
* height), its bpp, and its pixel data. The pixel data is an array in * height), its bpp, and its pixel data.
* C or a list in some languages.
* *
* Returns: TRUE on success. * Returns: TRUE on success.
* *
* Since: 2.2 * Since: 2.2
**/ **/
gboolean gboolean
gimp_pattern_get_pixels (GimpPattern *pattern, _gimp_pattern_get_pixels (GimpPattern *pattern,
gint *width, gint *width,
gint *height, gint *height,
gint *bpp, gint *bpp,

View File

@ -37,7 +37,7 @@ gboolean gimp_pattern_get_info (GimpPattern *pattern,
gint *width, gint *width,
gint *height, gint *height,
gint *bpp); gint *bpp);
gboolean gimp_pattern_get_pixels (GimpPattern *pattern, G_GNUC_INTERNAL gboolean _gimp_pattern_get_pixels (GimpPattern *pattern,
gint *width, gint *width,
gint *height, gint *height,
gint *bpp, gint *bpp,

View File

@ -19,10 +19,6 @@
* <https://www.gnu.org/licenses/>. * <https://www.gnu.org/licenses/>.
*/ */
/* Similar to gimpbrushselectbutton.c.
* FUTURE: inherit or share common code.
*/
#include "config.h" #include "config.h"
#include <gegl.h> #include <gegl.h>
@ -45,18 +41,12 @@
* @short_description: A button which pops up a pattern selection dialog. * @short_description: A button which pops up a pattern selection dialog.
* *
* A button which pops up a pattern selection dialog. * A button which pops up a pattern selection dialog.
*
* Note that this widget draws itself using `GEGL` code. You **must** call
* [func@Gegl.Init] first to be able to use this chooser.
**/ **/
#define CELL_SIZE 20 #define CELL_SIZE 40
/* An image. pixelels is allocated and must be freed. */
typedef struct _PreviewImage
{
gint width;
gint height;
gint bpp;
guchar *pixelels;
} _PreviewImage;
struct _GimpPatternSelectButton struct _GimpPatternSelectButton
{ {
@ -64,28 +54,27 @@ struct _GimpPatternSelectButton
GtkWidget *preview; GtkWidget *preview;
GtkWidget *popup; GtkWidget *popup;
GimpPattern *pattern;
GeglBuffer *buffer;
gint width;
gint height;
}; };
/* local */ /* local */
static void gimp_pattern_select_button_draw_interior (GimpResourceSelectButton *self);
static void gimp_pattern_select_on_preview_resize (GimpPatternSelectButton *button);
static gboolean gimp_pattern_select_on_preview_events (GtkWidget *widget, static gboolean gimp_pattern_select_on_preview_events (GtkWidget *widget,
GdkEvent *event, GdkEvent *event,
GimpPatternSelectButton *button); GimpPatternSelectButton *button);
/* local drawing methods. */ /* local drawing methods. */
static void gimp_pattern_select_preview_draw (GimpPreviewArea *area, static void gimp_pattern_select_preview_fill_draw (GimpPatternSelectButton *chooser,
gint x, GimpPreviewArea *area);
gint y,
_PreviewImage image,
gint rowstride);
static void gimp_pattern_select_preview_fill_draw (GtkWidget *preview,
_PreviewImage image);
static void gimp_pattern_select_button_draw (GimpPatternSelectButton *self); static void gimp_pattern_select_button_draw (GimpResourceSelectButton *self);
static _PreviewImage gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *self); static void gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *self,
gint width,
gint height);
/* Popup methods. */ /* Popup methods. */
static void gimp_pattern_select_button_open_popup (GimpPatternSelectButton *button, static void gimp_pattern_select_button_open_popup (GimpPatternSelectButton *button,
@ -94,16 +83,12 @@ static void gimp_pattern_select_button_open_popup (GimpPatternSelectButton
static void gimp_pattern_select_button_close_popup (GimpPatternSelectButton *button); static void gimp_pattern_select_button_close_popup (GimpPatternSelectButton *button);
/* A GtkTargetEntry has a string and two ints. /* A GtkTargetEntry has a string and two ints.
* This is one, but we treat it as an array. * This is one, but we treat it as an array.
*/ */
static const GtkTargetEntry drag_target = { "application/x-gimp-pattern-name", 0, 0 }; static const GtkTargetEntry drag_target = { "application/x-gimp-pattern-name", 0, 0 };
G_DEFINE_FINAL_TYPE (GimpPatternSelectButton, G_DEFINE_FINAL_TYPE (GimpPatternSelectButton, gimp_pattern_select_button, GIMP_TYPE_RESOURCE_SELECT_BUTTON)
gimp_pattern_select_button,
GIMP_TYPE_RESOURCE_SELECT_BUTTON)
static void static void
@ -111,7 +96,7 @@ gimp_pattern_select_button_class_init (GimpPatternSelectButtonClass *klass)
{ {
GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass);
superclass->draw_interior = gimp_pattern_select_button_draw_interior; superclass->draw_interior = gimp_pattern_select_button_draw;
superclass->resource_type = GIMP_TYPE_PATTERN; superclass->resource_type = GIMP_TYPE_PATTERN;
} }
@ -121,18 +106,20 @@ gimp_pattern_select_button_init (GimpPatternSelectButton *self)
GtkWidget *frame; GtkWidget *frame;
GtkWidget *button; GtkWidget *button;
frame = gtk_frame_new (NULL); frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (self), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (self), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
self->preview = gimp_preview_area_new (); self->preview = gimp_preview_area_new ();
gtk_widget_add_events (self->preview, gtk_widget_add_events (self->preview,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
gtk_widget_set_size_request (self->preview, CELL_SIZE, CELL_SIZE); gtk_widget_set_size_request (self->preview, CELL_SIZE, CELL_SIZE);
gtk_container_add (GTK_CONTAINER (frame), self->preview); gtk_container_add (GTK_CONTAINER (frame), self->preview);
gtk_widget_show (self->preview);
g_signal_connect_swapped (self->preview, "size-allocate", g_signal_connect_swapped (self->preview, "size-allocate",
G_CALLBACK (gimp_pattern_select_on_preview_resize), G_CALLBACK (gimp_pattern_select_button_draw),
self); self);
g_signal_connect (self->preview, "event", g_signal_connect (self->preview, "event",
@ -142,23 +129,15 @@ gimp_pattern_select_button_init (GimpPatternSelectButton *self)
button = gtk_button_new_with_mnemonic (_("_Browse...")); button = gtk_button_new_with_mnemonic (_("_Browse..."));
gtk_box_pack_start (GTK_BOX (self), button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (self), button, FALSE, FALSE, 0);
gtk_widget_show_all (GTK_WIDGET (self));
gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self),
self->preview, self->preview,
&drag_target); &drag_target);
gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self),
button); button);
gtk_widget_show (button);
} }
static void
gimp_pattern_select_button_draw_interior (GimpResourceSelectButton *self)
{
gimp_pattern_select_button_draw (GIMP_PATTERN_SELECT_BUTTON (self));
}
/** /**
* gimp_pattern_select_button_new: * gimp_pattern_select_button_new:
* @title: (nullable): Title of the dialog to use or %NULL to use the default title. * @title: (nullable): Title of the dialog to use or %NULL to use the default title.
@ -197,62 +176,52 @@ gimp_pattern_select_button_new (const gchar *title,
"resource", resource, "resource", resource,
NULL); NULL);
gimp_pattern_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); gimp_pattern_select_button_draw (GIMP_RESOURCE_SELECT_BUTTON (self));
return self; return self;
} }
/* Draw self.
*
* This knows that we only draw the preview. Gtk draws the browse button.
*/
static void static void
gimp_pattern_select_button_draw (GimpPatternSelectButton *self) gimp_pattern_select_button_draw (GimpResourceSelectButton *chooser)
{ {
_PreviewImage image; GimpPatternSelectButton *pchooser = GIMP_PATTERN_SELECT_BUTTON (chooser);
GtkAllocation allocation;
image = gimp_pattern_select_button_get_pattern_image (self); gtk_widget_get_allocation (pchooser->preview, &allocation);
gimp_pattern_select_preview_fill_draw (self->preview, image);
g_free (image.pixelels); gimp_pattern_select_button_get_pattern_image (pchooser, allocation.width, allocation.height);
gimp_pattern_select_preview_fill_draw (pchooser, GIMP_PREVIEW_AREA (pchooser->preview));
} }
static void
gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *chooser,
/* Return the image of self's pattern. gint width,
* Caller must free pixelels. gint height)
*/
static _PreviewImage
gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *self)
{ {
GimpPattern *pattern; GimpPattern *pattern;
gsize pixelels_size;
GBytes *color_bytes;
_PreviewImage result;
g_object_get (self, "resource", &pattern, NULL); g_object_get (chooser, "resource", &pattern, NULL);
gimp_pattern_get_pixels (pattern, if (chooser->pattern == pattern &&
&result.width, chooser->width == width &&
&result.height, chooser->height == height)
&result.bpp, {
&color_bytes); /* Let's assume pattern contents is not changing in a single run. */
result.pixelels = g_bytes_unref_to_data (color_bytes, &pixelels_size); g_object_unref (pattern);
return;
}
g_clear_object (&chooser->buffer);
chooser->pattern = pattern;
chooser->buffer = gimp_pattern_get_buffer (pattern, width, height, NULL);
chooser->width = gegl_buffer_get_width (chooser->buffer);
chooser->height = gegl_buffer_get_height (chooser->buffer);
g_object_unref (pattern); g_object_unref (pattern);
return result;
} }
/* On resize event, redraw. */
static void
gimp_pattern_select_on_preview_resize (GimpPatternSelectButton *self)
{
gimp_pattern_select_button_draw (self);
}
/* On mouse events in self's preview, popup a zoom view of entire pattern */ /* On mouse events in self's preview, popup a zoom view of entire pattern */
static gboolean static gboolean
gimp_pattern_select_on_preview_events (GtkWidget *widget, gimp_pattern_select_on_preview_events (GtkWidget *widget,
@ -291,80 +260,70 @@ gimp_pattern_select_on_preview_events (GtkWidget *widget,
return FALSE; return FALSE;
} }
/* Draw a GimpPreviewArea with a given image. */
static void
gimp_pattern_select_preview_draw (GimpPreviewArea *area,
gint x,
gint y,
_PreviewImage image,
gint rowstride)
{
GimpImageType type;
switch (image.bpp)
{
case 1: type = GIMP_GRAY_IMAGE; break;
case 2: type = GIMP_GRAYA_IMAGE; break;
case 3: type = GIMP_RGB_IMAGE; break;
case 4: type = GIMP_RGBA_IMAGE; break;
default:
g_warning ("Invalid bpp");
return;
}
gimp_preview_area_draw (area,
x, y,
image.width, image.height,
type,
image.pixelels,
rowstride);
}
/* Fill a GimpPreviewArea with a image then draw. */ /* Fill a GimpPreviewArea with a image then draw. */
static void static void
gimp_pattern_select_preview_fill_draw (GtkWidget *preview, gimp_pattern_select_preview_fill_draw (GimpPatternSelectButton *chooser,
_PreviewImage image) GimpPreviewArea *area)
{ {
GimpPreviewArea *area = GIMP_PREVIEW_AREA (preview); GeglBuffer *src_buffer;
const Babl *format;
const Babl *model;
guchar *src;
GimpImageType type;
gint rowstride;
GtkAllocation allocation; GtkAllocation allocation;
gint x, y; gint x = 0;
gint width, height; gint y = 0;
_PreviewImage drawn_image;
gtk_widget_get_allocation (preview, &allocation); gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
width = MIN (image.width, allocation.width); /* Fill with white. */
height = MIN (image.height, allocation.height); if (chooser->width < allocation.width ||
chooser->height < allocation.height)
x = ((allocation.width - width) / 2); {
y = ((allocation.height - height) / 2);
if (x || y)
gimp_preview_area_fill (area, gimp_preview_area_fill (area,
0, 0, 0, 0,
allocation.width, allocation.width,
allocation.height, allocation.height,
0xFF, 0xFF, 0xFF); 0xFF, 0xFF, 0xFF);
/* Draw same data to new bounds. x = ((allocation.width - chooser->width) / 2);
* drawn_image.pixelels points to same array. y = ((allocation.height - chooser->height) / 2);
*/ }
drawn_image.width = width;
drawn_image.height = height;
drawn_image.pixelels = image.pixelels;
drawn_image.bpp = image.bpp;
gimp_pattern_select_preview_draw (area, /* Draw the pattern. */
x, y, src_buffer = chooser->buffer;
drawn_image, format = gegl_buffer_get_format (src_buffer);
image.width * image.bpp ); /* row stride */ rowstride = chooser->width * babl_format_get_bytes_per_pixel (format);
/* Caller will free image.pixelels */ model = babl_format_get_model (format);
if (model == babl_model ("R'G'B'"))
type = GIMP_RGB_IMAGE;
else if (model == babl_model ("R'G'B'A"))
type = GIMP_RGBA_IMAGE;
else if (model == babl_model ("Y'"))
type = GIMP_GRAY_IMAGE;
else if (model == babl_model ("Y'A"))
type = GIMP_GRAYA_IMAGE;
else
/* I just know that we can't have other formats because I set it up this way
* in gimp_pattern_get_buffer(). If we make the latter more generic, able to
* return more types of pixel data, this should be reviewed. XXX
*/
g_return_if_reached ();
src = g_try_malloc (sizeof (guchar) * rowstride * chooser->height);
gegl_buffer_get (chooser->buffer, NULL, 1.0, format, src, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gimp_preview_area_draw (area, x, y, chooser->width, chooser->height, type, src, rowstride);
g_free (src);
} }
/* popup methods. */ /* popup methods. */
static void static void
gimp_pattern_select_button_open_popup (GimpPatternSelectButton *self, gimp_pattern_select_button_open_popup (GimpPatternSelectButton *chooser,
gint x, gint x,
gint y) gint y)
{ {
@ -374,54 +333,47 @@ gimp_pattern_select_button_open_popup (GimpPatternSelectButton *self,
GdkRectangle workarea; GdkRectangle workarea;
gint x_org; gint x_org;
gint y_org; gint y_org;
_PreviewImage image;
if (self->popup) if (chooser->popup)
gimp_pattern_select_button_close_popup (self); gimp_pattern_select_button_close_popup (chooser);
image = gimp_pattern_select_button_get_pattern_image (self); if (chooser->width <= CELL_SIZE && chooser->height <= CELL_SIZE)
if (image.width <= CELL_SIZE && image.height <= CELL_SIZE)
return; return;
self->popup = gtk_window_new (GTK_WINDOW_POPUP); chooser->popup = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_type_hint (GTK_WINDOW (self->popup), GDK_WINDOW_TYPE_HINT_DND); gtk_window_set_type_hint (GTK_WINDOW (chooser->popup), GDK_WINDOW_TYPE_HINT_DND);
gtk_window_set_screen (GTK_WINDOW (self->popup), gtk_window_set_screen (GTK_WINDOW (chooser->popup),
gtk_widget_get_screen (GTK_WIDGET (self))); gtk_widget_get_screen (GTK_WIDGET (chooser)));
frame = gtk_frame_new (NULL); frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (self->popup), frame); gtk_container_add (GTK_CONTAINER (chooser->popup), frame);
gtk_widget_show (frame); gtk_widget_show (frame);
preview = gimp_preview_area_new (); preview = gimp_preview_area_new ();
gtk_widget_set_size_request (preview, image.width, image.height); gtk_widget_set_size_request (preview, chooser->width, chooser->height);
gtk_container_add (GTK_CONTAINER (frame), preview); gtk_container_add (GTK_CONTAINER (frame), preview);
gtk_widget_show (preview); gtk_widget_show (preview);
/* decide where to put the popup: near the preview i.e. at mousedown coords */ /* decide where to put the popup: near the preview i.e. at mousedown coords */
gdk_window_get_origin (gtk_widget_get_window (self->preview), gdk_window_get_origin (gtk_widget_get_window (chooser->preview),
&x_org, &y_org); &x_org, &y_org);
monitor = gimp_widget_get_monitor (GTK_WIDGET (self)); monitor = gimp_widget_get_monitor (GTK_WIDGET (chooser));
gdk_monitor_get_workarea (monitor, &workarea); gdk_monitor_get_workarea (monitor, &workarea);
x = x_org + x - (image.width / 2); x = x_org + x - (chooser->width / 2);
y = y_org + y - (image.height / 2); y = y_org + y - (chooser->height / 2);
x = CLAMP (x, workarea.x, workarea.x + workarea.width - image.width); x = CLAMP (x, workarea.x, workarea.x + workarea.width - chooser->width);
y = CLAMP (y, workarea.y, workarea.y + workarea.height - image.height); y = CLAMP (y, workarea.y, workarea.y + workarea.height - chooser->height);
gtk_window_move (GTK_WINDOW (self->popup), x, y); gtk_window_move (GTK_WINDOW (chooser->popup), x, y);
gtk_widget_show (self->popup); gtk_widget_show (chooser->popup);
/* Draw popup now. Usual events do not cause a draw. */ /* Draw popup now. Usual events do not cause a draw. */
gimp_pattern_select_preview_draw (GIMP_PREVIEW_AREA (preview), gimp_pattern_select_preview_fill_draw (chooser, GIMP_PREVIEW_AREA (preview));
0, 0,
image,
image.width * image.bpp);
g_free (image.pixelels);
} }
static void static void

View File

@ -460,17 +460,6 @@ gimp_resource_is_font (GimpResource *resource)
} }
struct _GimpPattern
{
GimpResource parent_instance;
};
G_DEFINE_TYPE (GimpPattern, gimp_pattern, GIMP_TYPE_RESOURCE);
static void gimp_pattern_class_init (GimpPatternClass *klass) {}
static void gimp_pattern_init (GimpPattern *self) {}
struct _GimpGradient struct _GimpGradient
{ {
GimpResource parent_instance; GimpResource parent_instance;

View File

@ -60,9 +60,6 @@ gboolean gimp_resource_is_palette (GimpResource *resource);
gboolean gimp_resource_is_font (GimpResource *resource); gboolean gimp_resource_is_font (GimpResource *resource);
#define GIMP_TYPE_PATTERN (gimp_pattern_get_type ())
G_DECLARE_FINAL_TYPE (GimpPattern, gimp_pattern, GIMP, PATTERN, GimpResource)
#define GIMP_TYPE_GRADIENT (gimp_gradient_get_type ()) #define GIMP_TYPE_GRADIENT (gimp_gradient_get_type ())
G_DECLARE_FINAL_TYPE (GimpGradient, gimp_gradient, GIMP, GRADIENT, GimpResource) G_DECLARE_FINAL_TYPE (GimpGradient, gimp_gradient, GIMP, GRADIENT, GimpResource)

View File

@ -184,6 +184,7 @@ libgimp_sources_introspectable = [
'gimplayermask.c', 'gimplayermask.c',
'gimploadprocedure.c', 'gimploadprocedure.c',
'gimpparamspecs.c', 'gimpparamspecs.c',
'gimppattern.c',
'gimppdb.c', 'gimppdb.c',
'gimpplugin.c', 'gimpplugin.c',
'gimpprocedure.c', 'gimpprocedure.c',
@ -238,6 +239,7 @@ libgimp_headers_introspectable = [
'gimplayermask.h', 'gimplayermask.h',
'gimploadprocedure.h', 'gimploadprocedure.h',
'gimpparamspecs.h', 'gimpparamspecs.h',
'gimppattern.h',
'gimppdb.h', 'gimppdb.h',
'gimpplugin.h', 'gimpplugin.h',
'gimpprocedure.h', 'gimpprocedure.h',

View File

@ -99,10 +99,10 @@ BLURB
$help = <<'HELP'; $help = <<'HELP';
Gets information about the pattern: Gets information about the pattern:
the pattern extents (width and height), its bpp, and its pixel data. the pattern extents (width and height), its bpp, and its pixel data.
The pixel data is an array in C or a list in some languages.
HELP HELP
&mitch_pdb_misc('2004', '2.2'); &mitch_pdb_misc('2004', '2.2');
$lib_private = 1;
@inargs = ( @inargs = (
${pattern_arg_spec} ${pattern_arg_spec}