mirror of https://github.com/GNOME/gimp.git
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:
parent
330d05e2fc
commit
457f52a6d1
|
@ -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>",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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__ */
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Loading…
Reference in New Issue