Updated new files from upstream
This commit is contained in:
312
libpika/pikabrush.c
Normal file
312
libpika/pikabrush.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikabrush.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 "pika.h"
|
||||
|
||||
#include "pikabrush.h"
|
||||
|
||||
struct _PikaBrush
|
||||
{
|
||||
PikaResource parent_instance;
|
||||
|
||||
/* Native size buffers of the brush contents. */
|
||||
GeglBuffer *buffer;
|
||||
GeglBuffer *mask;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PikaBrush, pika_brush, PIKA_TYPE_RESOURCE);
|
||||
|
||||
static void pika_brush_finalize (GObject *object);
|
||||
static void pika_brush_get_data (PikaBrush *brush);
|
||||
static GeglBuffer * pika_brush_scale (GeglBuffer *buffer,
|
||||
gint max_width,
|
||||
gint max_height);
|
||||
static const Babl * pika_brush_data_get_format (gint bpp,
|
||||
gboolean with_alpha);
|
||||
|
||||
|
||||
static void pika_brush_class_init (PikaBrushClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_brush_finalize;
|
||||
}
|
||||
|
||||
static void pika_brush_init (PikaBrush *brush)
|
||||
{
|
||||
brush->buffer = NULL;
|
||||
brush->mask = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_finalize (GObject *object)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (object);
|
||||
|
||||
g_clear_object (&brush->buffer);
|
||||
g_clear_object (&brush->mask);
|
||||
|
||||
G_OBJECT_CLASS (pika_brush_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pika_brush_get_buffer:
|
||||
* @brush: a [class@Brush].
|
||||
* @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 brush 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 brush 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 brush's
|
||||
* native size.
|
||||
*
|
||||
* When the brush is parametric or a raster mask, only the mask (as returned by
|
||||
* [method@Gimp.Brush.get_mask]) will be set. The returned buffer will be NULL.
|
||||
*
|
||||
* Make sure you called [func@Gegl.init] before calling any function using
|
||||
* `GEGL`.
|
||||
*
|
||||
* Returns: (transfer full): a [class@Gegl.Buffer] of %NULL if the brush is parametric
|
||||
* or mask only.
|
||||
*/
|
||||
GeglBuffer *
|
||||
pika_brush_get_buffer (PikaBrush *brush,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format)
|
||||
{
|
||||
pika_brush_get_data (brush);
|
||||
|
||||
if (brush->buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
if (max_width == 0 || max_height == 0 ||
|
||||
(gegl_buffer_get_width (brush->buffer) <= max_width &&
|
||||
gegl_buffer_get_height (brush->buffer) <= max_height))
|
||||
return gegl_buffer_dup (brush->buffer);
|
||||
|
||||
return pika_brush_scale (brush->buffer, max_width, max_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_brush_get_mask:
|
||||
* @brush: a [class@Brush].
|
||||
* @max_width: a maximum width for the returned buffer.
|
||||
* @max_height: a maximum height for the returned buffer.
|
||||
* @format: an optional Babl format.
|
||||
*
|
||||
* Gets mask data of the brush 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 brush 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 brush's
|
||||
* native size.
|
||||
*
|
||||
* Make sure you called [func@Gegl.init] before calling any function using
|
||||
* `GEGL`.
|
||||
*
|
||||
* Returns: (transfer full): a [class@Gegl.Buffer] representing the @brush mask.
|
||||
*/
|
||||
GeglBuffer *
|
||||
pika_brush_get_mask (PikaBrush *brush,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format)
|
||||
{
|
||||
pika_brush_get_data (brush);
|
||||
|
||||
g_return_val_if_fail (brush->mask != NULL, NULL);
|
||||
|
||||
if (max_width == 0 || max_height == 0 ||
|
||||
(gegl_buffer_get_width (brush->mask) <= max_width &&
|
||||
gegl_buffer_get_height (brush->mask) <= max_height))
|
||||
return gegl_buffer_dup (brush->mask);
|
||||
|
||||
return pika_brush_scale (brush->mask, max_width, max_height);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_get_data (PikaBrush *brush)
|
||||
{
|
||||
gint width;
|
||||
gint height;
|
||||
gint mask_bpp;
|
||||
GBytes *mask_bytes;
|
||||
gint color_bpp;
|
||||
GBytes *color_bytes;
|
||||
const guchar *mask;
|
||||
gsize mask_size;
|
||||
const guchar *color;
|
||||
gsize color_size;
|
||||
|
||||
/* We check the mask because the buffer might be NULL.
|
||||
*
|
||||
* This check assumes that the brush contents doesn't change, which is not a
|
||||
* perfect assumption. We could maybe add a PDB call which would return
|
||||
* the new brush 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 (brush->mask != NULL)
|
||||
return;
|
||||
|
||||
g_clear_object (&brush->buffer);
|
||||
g_clear_object (&brush->mask);
|
||||
|
||||
_pika_brush_get_pixels (brush, &width, &height,
|
||||
&mask_bpp, &mask_bytes,
|
||||
&color_bpp, &color_bytes);
|
||||
|
||||
mask = g_bytes_unref_to_data (mask_bytes, &mask_size);
|
||||
color = g_bytes_unref_to_data (color_bytes, &color_size);
|
||||
|
||||
brush->mask = gegl_buffer_linear_new_from_data ((const gpointer) mask,
|
||||
pika_brush_data_get_format (mask_bpp, FALSE),
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
0, g_free, NULL);
|
||||
if (color_bpp > 0)
|
||||
{
|
||||
GeglBufferIterator *gi;
|
||||
GeglBuffer *buffer;
|
||||
|
||||
buffer = gegl_buffer_linear_new_from_data ((const gpointer) color,
|
||||
pika_brush_data_get_format (color_bpp, FALSE),
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
0, g_free, NULL);
|
||||
brush->buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
||||
pika_brush_data_get_format (color_bpp, TRUE));
|
||||
|
||||
gi = gegl_buffer_iterator_new (brush->buffer, NULL, 0, NULL,
|
||||
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 3);
|
||||
gegl_buffer_iterator_add (gi, buffer, GEGL_RECTANGLE (0, 0, width, height),
|
||||
0, NULL, GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
|
||||
gegl_buffer_iterator_add (gi, brush->mask, GEGL_RECTANGLE (0, 0, width, height),
|
||||
0, NULL, GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
|
||||
while (gegl_buffer_iterator_next (gi))
|
||||
{
|
||||
guint8 *out = gi->items[0].data;
|
||||
guint8 *color = gi->items[1].data;
|
||||
guint8 *alpha = gi->items[2].data;
|
||||
|
||||
for (gint i = 0; i < gi->length; i++)
|
||||
{
|
||||
gint c;
|
||||
|
||||
for (c = 0; c < color_bpp; c++)
|
||||
out[c] = color[c];
|
||||
|
||||
out[c] = alpha[0];
|
||||
|
||||
out += color_bpp + 1;
|
||||
color += color_bpp;
|
||||
alpha += 1;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static GeglBuffer *
|
||||
pika_brush_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", PIKA_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;
|
||||
}
|
||||
|
||||
static const Babl *
|
||||
pika_brush_data_get_format (gint bpp,
|
||||
gboolean with_alpha)
|
||||
{
|
||||
/* It's an ugly way to determine the proper format but pika_brush_get_pixels()
|
||||
* doesn't give more info.
|
||||
*/
|
||||
switch (bpp)
|
||||
{
|
||||
case 1:
|
||||
if (! with_alpha)
|
||||
return babl_format ("Y' u8");
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
return babl_format ("Y'A u8");
|
||||
case 3:
|
||||
if (! with_alpha)
|
||||
return babl_format ("R'G'B' u8");
|
||||
/* fallthrough */
|
||||
case 4:
|
||||
return babl_format ("R'G'B'A u8");
|
||||
default:
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
52
libpika/pikabrush.h
Normal file
52
libpika/pikabrush.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikabrush.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 (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_BRUSH_H__
|
||||
#define __PIKA_BRUSH_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
#include <libpika/pikaresource.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRUSH (pika_brush_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaBrush, pika_brush, PIKA, BRUSH, PikaResource)
|
||||
|
||||
|
||||
GeglBuffer * pika_brush_get_buffer (PikaBrush *brush,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GeglBuffer * pika_brush_get_mask (PikaBrush *brush,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_BRUSH_H__ */
|
456
libpika/pikabrushchooser.c
Normal file
456
libpika/pikabrushchooser.c
Normal file
@ -0,0 +1,456 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikabrushchooser.c
|
||||
* Copyright (C) 1998 Andy Thomas
|
||||
*
|
||||
* 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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikabrushchooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikabrushchooser
|
||||
* @title: PikaBrushChooser
|
||||
* @short_description: A button which pops up a brush selection dialog.
|
||||
*
|
||||
* A button which pops up a brush 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 40
|
||||
|
||||
struct _PikaBrushChooser
|
||||
{
|
||||
PikaResourceChooser parent_instance;
|
||||
|
||||
GtkWidget *preview;
|
||||
GtkWidget *popup;
|
||||
|
||||
PikaBrush *brush;
|
||||
gint width;
|
||||
gint height;
|
||||
GeglBuffer *buffer;
|
||||
GeglBuffer *mask;
|
||||
};
|
||||
|
||||
|
||||
static void pika_brush_chooser_finalize (GObject *object);
|
||||
|
||||
static gboolean pika_brush_select_on_preview_events (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
PikaBrushChooser *button);
|
||||
|
||||
static void pika_brush_select_preview_draw (PikaBrushChooser *chooser,
|
||||
PikaPreviewArea *area);
|
||||
|
||||
static void pika_brush_chooser_draw (PikaBrushChooser *self);
|
||||
static void pika_brush_chooser_get_brush_bitmap (PikaBrushChooser *self,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
/* Popup methods. */
|
||||
static void pika_brush_chooser_open_popup (PikaBrushChooser *button,
|
||||
gint x,
|
||||
gint y);
|
||||
static void pika_brush_chooser_close_popup (PikaBrushChooser *button);
|
||||
|
||||
|
||||
static const GtkTargetEntry drag_target = { "application/x-pika-brush-name", 0, 0 };
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaBrushChooser, pika_brush_chooser, PIKA_TYPE_RESOURCE_CHOOSER)
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_chooser_class_init (PikaBrushChooserClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaResourceChooserClass *res_class = PIKA_RESOURCE_CHOOSER_CLASS (klass);
|
||||
|
||||
res_class->draw_interior = (void (*)(PikaResourceChooser *)) pika_brush_chooser_draw;
|
||||
res_class->resource_type = PIKA_TYPE_BRUSH;
|
||||
|
||||
object_class->finalize = pika_brush_chooser_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_chooser_init (PikaBrushChooser *chooser)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
gint scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (chooser));
|
||||
|
||||
chooser->brush = NULL;
|
||||
chooser->buffer = NULL;
|
||||
chooser->mask = NULL;
|
||||
|
||||
widget = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
|
||||
gtk_box_pack_start (GTK_BOX (chooser), widget, FALSE, FALSE, 0);
|
||||
gtk_widget_show (widget);
|
||||
|
||||
chooser->preview = pika_preview_area_new ();
|
||||
gtk_widget_add_events (chooser->preview,
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
gtk_widget_set_size_request (chooser->preview, scale_factor * CELL_SIZE, scale_factor * CELL_SIZE);
|
||||
gtk_container_add (GTK_CONTAINER (widget), chooser->preview);
|
||||
gtk_widget_show (chooser->preview);
|
||||
|
||||
g_signal_connect_swapped (chooser->preview, "size-allocate",
|
||||
G_CALLBACK (pika_brush_chooser_draw),
|
||||
chooser);
|
||||
|
||||
g_signal_connect (chooser->preview, "event",
|
||||
G_CALLBACK (pika_brush_select_on_preview_events),
|
||||
chooser);
|
||||
|
||||
widget = gtk_button_new_with_mnemonic (_("_Browse..."));
|
||||
gtk_box_pack_start (GTK_BOX (chooser), widget, FALSE, FALSE, 0);
|
||||
|
||||
pika_resource_chooser_set_drag_target (PIKA_RESOURCE_CHOOSER (chooser),
|
||||
chooser->preview,
|
||||
&drag_target);
|
||||
|
||||
pika_resource_chooser_set_clickable (PIKA_RESOURCE_CHOOSER (chooser),
|
||||
widget);
|
||||
gtk_widget_show (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_chooser_finalize (GObject *object)
|
||||
{
|
||||
PikaBrushChooser *chooser = PIKA_BRUSH_CHOOSER (object);
|
||||
|
||||
g_clear_object (&chooser->buffer);
|
||||
g_clear_object (&chooser->mask);
|
||||
|
||||
G_OBJECT_CLASS (pika_brush_chooser_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_brush_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @resource: (nullable): Initial brush.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a brush.
|
||||
* You can put this widget in a plug-in dialog.
|
||||
*
|
||||
* When brush is NULL, initial choice is from context.
|
||||
*
|
||||
* Returns: A #GtkWidget that you can use in your UI.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_brush_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource)
|
||||
{
|
||||
GtkWidget *self;
|
||||
|
||||
if (resource == NULL)
|
||||
resource = PIKA_RESOURCE (pika_context_get_brush ());
|
||||
|
||||
if (title)
|
||||
self = g_object_new (PIKA_TYPE_BRUSH_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
else
|
||||
self = g_object_new (PIKA_TYPE_BRUSH_CHOOSER,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_brush_chooser_draw (PikaBrushChooser *chooser)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
|
||||
gtk_widget_get_allocation (chooser->preview, &allocation);
|
||||
|
||||
pika_brush_chooser_get_brush_bitmap (chooser, allocation.width, allocation.height);
|
||||
pika_brush_select_preview_draw (chooser, PIKA_PREVIEW_AREA (chooser->preview));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_chooser_get_brush_bitmap (PikaBrushChooser *chooser,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
PikaBrush *brush;
|
||||
|
||||
g_object_get (chooser, "resource", &brush, NULL);
|
||||
|
||||
if (chooser->brush == brush &&
|
||||
chooser->width == width &&
|
||||
chooser->height == height)
|
||||
{
|
||||
/* Let's assume brush contents is not changing in a single run. */
|
||||
g_object_unref (brush);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_object (&chooser->buffer);
|
||||
g_clear_object (&chooser->mask);
|
||||
chooser->width = chooser->height = 0;
|
||||
|
||||
chooser->brush = brush;
|
||||
chooser->buffer = pika_brush_get_buffer (brush, width, height, NULL);
|
||||
|
||||
if (chooser->buffer)
|
||||
{
|
||||
GeglColor *white_color = gegl_color_new ("rgb(1.0,1.0,1.0)");
|
||||
GeglNode *graph;
|
||||
GeglNode *white;
|
||||
GeglNode *source;
|
||||
GeglNode *op;
|
||||
|
||||
chooser->width = gegl_buffer_get_width (chooser->buffer);
|
||||
chooser->height = gegl_buffer_get_height (chooser->buffer);
|
||||
|
||||
graph = gegl_node_new ();
|
||||
white = gegl_node_new_child (graph,
|
||||
"operation", "gegl:rectangle",
|
||||
"x", 0.0,
|
||||
"y", 0.0,
|
||||
"width", (gdouble) gegl_buffer_get_width (chooser->buffer),
|
||||
"height", (gdouble) gegl_buffer_get_height (chooser->buffer),
|
||||
"color", white_color,
|
||||
NULL);
|
||||
source = gegl_node_new_child (graph,
|
||||
"operation", "gegl:buffer-source",
|
||||
"buffer", chooser->buffer,
|
||||
NULL);
|
||||
op = gegl_node_new_child (graph,
|
||||
"operation", "svg:src-over",
|
||||
NULL);
|
||||
gegl_node_link_many (white, op, NULL);
|
||||
gegl_node_connect (source, "output", op, "aux");
|
||||
gegl_node_blit_buffer (op, chooser->buffer, NULL, 0, GEGL_ABYSS_NONE);
|
||||
|
||||
g_object_unref (graph);
|
||||
g_object_unref (white_color);
|
||||
}
|
||||
else
|
||||
{
|
||||
GeglBufferIterator *iter;
|
||||
|
||||
chooser->mask = pika_brush_get_mask (brush, width, height, NULL);
|
||||
chooser->width = gegl_buffer_get_width (chooser->mask);
|
||||
chooser->height = gegl_buffer_get_height (chooser->mask);
|
||||
|
||||
/* More common to display mask brushes as black on white. */
|
||||
iter = gegl_buffer_iterator_new (chooser->mask, NULL, 0,
|
||||
babl_format ("Y' u8"),
|
||||
GEGL_ACCESS_READWRITE,
|
||||
GEGL_ABYSS_NONE, 1);
|
||||
|
||||
while (gegl_buffer_iterator_next (iter))
|
||||
{
|
||||
guint8 *data = iter->items[0].data;
|
||||
|
||||
for (gint i = 0; i < iter->length; i++)
|
||||
{
|
||||
*data = 255 - *data;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (brush);
|
||||
}
|
||||
|
||||
/* On mouse events in self's preview, popup a zoom view of entire brush */
|
||||
static gboolean
|
||||
pika_brush_select_on_preview_events (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
PikaBrushChooser *self)
|
||||
{
|
||||
GdkEventButton *bevent;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
bevent = (GdkEventButton *) event;
|
||||
|
||||
if (bevent->button == 1)
|
||||
{
|
||||
gtk_grab_add (widget);
|
||||
pika_brush_chooser_open_popup (self,
|
||||
bevent->x, bevent->y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_BUTTON_RELEASE:
|
||||
bevent = (GdkEventButton *) event;
|
||||
|
||||
if (bevent->button == 1)
|
||||
{
|
||||
gtk_grab_remove (widget);
|
||||
pika_brush_chooser_close_popup (self);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Draw a PikaPreviewArea with a given bitmap. */
|
||||
static void
|
||||
pika_brush_select_preview_draw (PikaBrushChooser *chooser,
|
||||
PikaPreviewArea *preview)
|
||||
{
|
||||
PikaPreviewArea *area = PIKA_PREVIEW_AREA (preview);
|
||||
GeglBuffer *src_buffer;
|
||||
const Babl *format;
|
||||
guchar *src;
|
||||
PikaImageType type;
|
||||
gint rowstride;
|
||||
GtkAllocation allocation;
|
||||
gint x = 0;
|
||||
gint y = 0;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (preview), &allocation);
|
||||
|
||||
/* Fill with white. */
|
||||
if (chooser->width < allocation.width ||
|
||||
chooser->height < allocation.height)
|
||||
{
|
||||
pika_preview_area_fill (area,
|
||||
0, 0,
|
||||
allocation.width,
|
||||
allocation.height,
|
||||
0xFF, 0xFF, 0xFF);
|
||||
|
||||
x = ((allocation.width - chooser->width) / 2);
|
||||
y = ((allocation.height - chooser->height) / 2);
|
||||
}
|
||||
|
||||
/* Draw the brush. */
|
||||
if (chooser->buffer)
|
||||
{
|
||||
src_buffer = chooser->buffer;
|
||||
format = gegl_buffer_get_format (src_buffer);
|
||||
rowstride = chooser->width * babl_format_get_bytes_per_pixel (format);
|
||||
if (babl_format_has_alpha (format))
|
||||
type = PIKA_RGBA_IMAGE;
|
||||
else
|
||||
type = PIKA_RGB_IMAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_buffer = chooser->mask;
|
||||
format = babl_format ("Y' u8");
|
||||
rowstride = chooser->width;
|
||||
type = PIKA_GRAY_IMAGE;
|
||||
}
|
||||
|
||||
src = g_try_malloc (sizeof (guchar) * rowstride * chooser->height);
|
||||
|
||||
gegl_buffer_get (src_buffer, NULL, 1.0, format, src, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
pika_preview_area_draw (area, x, y, chooser->width, chooser->height, type, src, rowstride);
|
||||
|
||||
g_free (src);
|
||||
}
|
||||
|
||||
/* popup methods. */
|
||||
|
||||
static void
|
||||
pika_brush_chooser_open_popup (PikaBrushChooser *chooser,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *preview;
|
||||
GdkMonitor *monitor;
|
||||
GdkRectangle workarea;
|
||||
gint x_org;
|
||||
gint y_org;
|
||||
|
||||
if (chooser->popup)
|
||||
pika_brush_chooser_close_popup (chooser);
|
||||
|
||||
if (chooser->width <= CELL_SIZE && chooser->height <= CELL_SIZE)
|
||||
return;
|
||||
|
||||
chooser->popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_window_set_type_hint (GTK_WINDOW (chooser->popup), GDK_WINDOW_TYPE_HINT_DND);
|
||||
gtk_window_set_screen (GTK_WINDOW (chooser->popup),
|
||||
gtk_widget_get_screen (GTK_WIDGET (chooser)));
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
|
||||
gtk_container_add (GTK_CONTAINER (chooser->popup), frame);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
preview = pika_preview_area_new ();
|
||||
gtk_widget_set_size_request (preview, chooser->width, chooser->height);
|
||||
gtk_container_add (GTK_CONTAINER (frame), preview);
|
||||
gtk_widget_show (preview);
|
||||
|
||||
/* decide where to put the popup: near the preview i.e. at mousedown coords */
|
||||
gdk_window_get_origin (gtk_widget_get_window (chooser->preview),
|
||||
&x_org, &y_org);
|
||||
|
||||
monitor = pika_widget_get_monitor (GTK_WIDGET (chooser));
|
||||
gdk_monitor_get_workarea (monitor, &workarea);
|
||||
|
||||
x = x_org + x - (chooser->width / 2);
|
||||
y = y_org + y - (chooser->height / 2);
|
||||
|
||||
x = CLAMP (x, workarea.x, workarea.x + workarea.width - chooser->width);
|
||||
y = CLAMP (y, workarea.y, workarea.y + workarea.height - chooser->height);
|
||||
|
||||
gtk_window_move (GTK_WINDOW (chooser->popup), x, y);
|
||||
|
||||
gtk_widget_show (chooser->popup);
|
||||
|
||||
/* Draw popup now. Usual events do not cause a draw. */
|
||||
pika_brush_select_preview_draw (chooser, PIKA_PREVIEW_AREA (preview));
|
||||
gdk_window_set_transient_for (gtk_widget_get_window (chooser->popup),
|
||||
gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (chooser))));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_chooser_close_popup (PikaBrushChooser *self)
|
||||
{
|
||||
g_clear_pointer (&self->popup, gtk_widget_destroy);
|
||||
}
|
43
libpika/pikabrushchooser.h
Normal file
43
libpika/pikabrushchooser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikabrushchooser.h
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_BRUSH_CHOOSER_H__
|
||||
#define __PIKA_BRUSH_CHOOSER_H__
|
||||
|
||||
#include <libpika/pikaresourcechooser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_BRUSH_CHOOSER (pika_brush_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaBrushChooser, pika_brush_chooser, PIKA, BRUSH_CHOOSER, PikaResourceChooser)
|
||||
|
||||
|
||||
GtkWidget * pika_brush_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_BRUSH_CHOOSER_H__ */
|
615
libpika/pikadrawablechooser.c
Normal file
615
libpika/pikadrawablechooser.c
Normal file
@ -0,0 +1,615 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikadrawablechooser.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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikadrawablechooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikadrawablechooser
|
||||
* @title: PikaDrawableChooser
|
||||
* @short_description: A widget allowing to select a drawable.
|
||||
*
|
||||
* The chooser contains an optional label and a button which queries the core
|
||||
* process to pop up a drawable selection dialog.
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
|
||||
#define CELL_SIZE 40
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TITLE,
|
||||
PROP_LABEL,
|
||||
PROP_DRAWABLE,
|
||||
PROP_DRAWABLE_TYPE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
struct _PikaDrawableChooser
|
||||
{
|
||||
GtkBox parent_instance;
|
||||
|
||||
GType drawable_type;
|
||||
PikaDrawable *drawable;
|
||||
gchar *title;
|
||||
gchar *label;
|
||||
gchar *callback;
|
||||
|
||||
GBytes *thumbnail;
|
||||
PikaDrawable *thumbnail_drawable;
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
|
||||
GtkWidget *label_widget;
|
||||
GtkWidget *preview_frame;
|
||||
GtkWidget *preview;
|
||||
GtkWidget *preview_title;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_drawable_chooser_constructed (GObject *object);
|
||||
static void pika_drawable_chooser_dispose (GObject *object);
|
||||
static void pika_drawable_chooser_finalize (GObject *object);
|
||||
|
||||
static void pika_drawable_chooser_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_drawable_chooser_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_drawable_chooser_clicked (PikaDrawableChooser *chooser);
|
||||
|
||||
static PikaValueArray * pika_temp_callback_run (PikaProcedure *procedure,
|
||||
PikaProcedureConfig *config,
|
||||
PikaDrawableChooser *chooser);
|
||||
static gboolean pika_drawable_select_remove_after_run (const gchar *procedure_name);
|
||||
|
||||
static void pika_drawable_chooser_draw (PikaDrawableChooser *chooser);
|
||||
static void pika_drawable_chooser_get_thumbnail (PikaDrawableChooser *chooser,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
|
||||
static GParamSpec *drawable_button_props[N_PROPS] = { NULL, };
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaDrawableChooser, pika_drawable_chooser, GTK_TYPE_BOX)
|
||||
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_class_init (PikaDrawableChooserClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_drawable_chooser_constructed;
|
||||
object_class->dispose = pika_drawable_chooser_dispose;
|
||||
object_class->finalize = pika_drawable_chooser_finalize;
|
||||
object_class->set_property = pika_drawable_chooser_set_property;
|
||||
object_class->get_property = pika_drawable_chooser_get_property;
|
||||
|
||||
/**
|
||||
* PikaDrawableChooser:title:
|
||||
*
|
||||
* The title to be used for the drawable selection popup dialog.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
drawable_button_props[PROP_TITLE] =
|
||||
g_param_spec_string ("title",
|
||||
"Title",
|
||||
"The title to be used for the drawable selection popup dialog",
|
||||
"Drawable Selection",
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* PikaDrawableChooser:label:
|
||||
*
|
||||
* Label text with mnemonic.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
drawable_button_props[PROP_LABEL] =
|
||||
g_param_spec_string ("label",
|
||||
"Label",
|
||||
"The label to be used next to the button",
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* PikaDrawableChooser:drawable:
|
||||
*
|
||||
* The currently selected drawable.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
drawable_button_props[PROP_DRAWABLE] =
|
||||
pika_param_spec_drawable ("drawable",
|
||||
"Drawable",
|
||||
"The currently selected drawable",
|
||||
TRUE,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* PikaDrawableChooser:drawable-type:
|
||||
*
|
||||
* Allowed drawable types, which must be either PIKA_TYPE_DRAWABLE or a
|
||||
* subtype.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
drawable_button_props[PROP_DRAWABLE_TYPE] =
|
||||
g_param_spec_gtype ("drawable-type",
|
||||
"Allowed drawable Type",
|
||||
"The GType of the drawable property",
|
||||
PIKA_TYPE_DRAWABLE,
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
PIKA_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class,
|
||||
N_PROPS, drawable_button_props);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_init (PikaDrawableChooser *chooser)
|
||||
{
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (chooser),
|
||||
GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_set_spacing (GTK_BOX (chooser), 6);
|
||||
|
||||
chooser->thumbnail_drawable = NULL;
|
||||
chooser->thumbnail = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_constructed (GObject *object)
|
||||
{
|
||||
PikaDrawableChooser *chooser = PIKA_DRAWABLE_CHOOSER (object);
|
||||
GtkWidget *button;
|
||||
GtkWidget *box;
|
||||
gint scale_factor;
|
||||
|
||||
scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (chooser));
|
||||
|
||||
chooser->label_widget = gtk_label_new (NULL);
|
||||
gtk_box_pack_start (GTK_BOX (chooser), chooser->label_widget, FALSE, FALSE, 0);
|
||||
gtk_label_set_text_with_mnemonic (GTK_LABEL (chooser->label_widget), chooser->label);
|
||||
gtk_widget_show (GTK_WIDGET (chooser->label_widget));
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_box_pack_start (GTK_BOX (chooser), button, FALSE, FALSE, 0);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (chooser->label_widget), button);
|
||||
gtk_widget_show (button);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
|
||||
gtk_container_add (GTK_CONTAINER (button), box);
|
||||
gtk_widget_show (box);
|
||||
|
||||
chooser->preview_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (chooser->preview_frame), GTK_SHADOW_IN);
|
||||
gtk_box_pack_start (GTK_BOX (box), chooser->preview_frame, FALSE, FALSE, 0);
|
||||
gtk_widget_show (chooser->preview_frame);
|
||||
|
||||
chooser->preview = pika_preview_area_new ();
|
||||
gtk_widget_set_size_request (chooser->preview, scale_factor * CELL_SIZE, scale_factor * CELL_SIZE);
|
||||
gtk_container_add (GTK_CONTAINER (chooser->preview_frame), chooser->preview);
|
||||
gtk_widget_show (chooser->preview);
|
||||
|
||||
chooser->preview_title = gtk_label_new (_("Browse..."));
|
||||
gtk_box_pack_start (GTK_BOX (box), chooser->preview_title, FALSE, FALSE, 0);
|
||||
gtk_widget_show (chooser->preview_title);
|
||||
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (pika_drawable_chooser_clicked),
|
||||
chooser);
|
||||
|
||||
G_OBJECT_CLASS (pika_drawable_chooser_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_dispose (GObject *object)
|
||||
{
|
||||
PikaDrawableChooser *chooser = PIKA_DRAWABLE_CHOOSER (object);
|
||||
|
||||
if (chooser->callback)
|
||||
{
|
||||
pika_drawables_close_popup (chooser->callback);
|
||||
|
||||
pika_plug_in_remove_temp_procedure (pika_get_plug_in (), chooser->callback);
|
||||
g_clear_pointer (&chooser->callback, g_free);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (pika_drawable_chooser_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_finalize (GObject *object)
|
||||
{
|
||||
PikaDrawableChooser *chooser = PIKA_DRAWABLE_CHOOSER (object);
|
||||
|
||||
g_clear_pointer (&chooser->title, g_free);
|
||||
g_clear_pointer (&chooser->label, g_free);
|
||||
g_clear_pointer (&chooser->thumbnail, g_bytes_unref);
|
||||
|
||||
G_OBJECT_CLASS (pika_drawable_chooser_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *gvalue,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaDrawableChooser *chooser = PIKA_DRAWABLE_CHOOSER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TITLE:
|
||||
chooser->title = g_value_dup_string (gvalue);
|
||||
break;
|
||||
|
||||
case PROP_LABEL:
|
||||
chooser->label = g_value_dup_string (gvalue);
|
||||
break;
|
||||
|
||||
case PROP_DRAWABLE:
|
||||
g_return_if_fail (g_value_get_object (gvalue) == NULL ||
|
||||
g_type_is_a (G_TYPE_FROM_INSTANCE (g_value_get_object (gvalue)),
|
||||
chooser->drawable_type));
|
||||
pika_drawable_chooser_set_drawable (chooser, g_value_get_object (gvalue));
|
||||
break;
|
||||
|
||||
case PROP_DRAWABLE_TYPE:
|
||||
chooser->drawable_type = g_value_get_gtype (gvalue);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaDrawableChooser *chooser = PIKA_DRAWABLE_CHOOSER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, chooser->title);
|
||||
break;
|
||||
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, chooser->label);
|
||||
break;
|
||||
|
||||
case PROP_DRAWABLE:
|
||||
g_value_set_object (value, chooser->drawable);
|
||||
break;
|
||||
|
||||
case PROP_DRAWABLE_TYPE:
|
||||
g_value_set_gtype (value, chooser->drawable_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawable_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @drawable_type: the acceptable subtype of choosable drawables.
|
||||
* @drawable: (nullable): Initial drawable.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a drawable which must be of
|
||||
* type @drawable_type. @drawable_type of values %G_TYPE_NONE and
|
||||
* %PIKA_TYPE_DRAWABLE are equivalent. Otherwise it must be a subtype of
|
||||
* %PIKA_TYPE_DRAWABLE.
|
||||
*
|
||||
* When @drawable is %NULL, initial choice is from context.
|
||||
*
|
||||
* Returns: A [class@GimpUi.DrawableChooser.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_drawable_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
GType drawable_type,
|
||||
PikaDrawable *drawable)
|
||||
{
|
||||
GtkWidget *chooser;
|
||||
|
||||
if (drawable_type == G_TYPE_NONE)
|
||||
drawable_type = PIKA_TYPE_DRAWABLE;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (drawable_type, PIKA_TYPE_DRAWABLE), NULL);
|
||||
g_return_val_if_fail (drawable == NULL ||
|
||||
g_type_is_a (G_TYPE_FROM_INSTANCE (drawable), drawable_type),
|
||||
NULL);
|
||||
|
||||
chooser = g_object_new (PIKA_TYPE_DRAWABLE_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"drawable", drawable,
|
||||
"drawable-type", drawable_type,
|
||||
NULL);
|
||||
|
||||
return chooser;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawable_chooser_get_drawable:
|
||||
* @chooser: A #PikaDrawableChooser
|
||||
*
|
||||
* Gets the currently selected drawable.
|
||||
*
|
||||
* Returns: (transfer none): an internal copy of the drawable which must not be freed.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
PikaDrawable *
|
||||
pika_drawable_chooser_get_drawable (PikaDrawableChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DRAWABLE_CHOOSER (chooser), NULL);
|
||||
|
||||
return chooser->drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawable_chooser_set_drawable:
|
||||
* @chooser: A #PikaDrawableChooser
|
||||
* @drawable: Drawable to set.
|
||||
*
|
||||
* Sets the currently selected drawable.
|
||||
* This will select the drawable in both the button and any chooser popup.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
void
|
||||
pika_drawable_chooser_set_drawable (PikaDrawableChooser *chooser,
|
||||
PikaDrawable *drawable)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DRAWABLE_CHOOSER (chooser));
|
||||
g_return_if_fail (drawable == NULL || PIKA_IS_DRAWABLE (drawable));
|
||||
|
||||
chooser->drawable = drawable;
|
||||
|
||||
if (chooser->callback)
|
||||
pika_drawables_set_popup (chooser->callback, chooser->drawable);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (chooser), drawable_button_props[PROP_DRAWABLE]);
|
||||
|
||||
pika_drawable_chooser_draw (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawable_chooser_get_label:
|
||||
* @widget: A [class@DrawableChooser].
|
||||
*
|
||||
* Returns the label widget.
|
||||
*
|
||||
* Returns: (transfer none): the [class@Gtk.Widget] showing the label text.
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_drawable_chooser_get_label (PikaDrawableChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DRAWABLE_CHOOSER (chooser), NULL);
|
||||
|
||||
return chooser->label_widget;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static PikaValueArray *
|
||||
pika_temp_callback_run (PikaProcedure *procedure,
|
||||
PikaProcedureConfig *config,
|
||||
PikaDrawableChooser *chooser)
|
||||
{
|
||||
PikaDrawable *drawable;
|
||||
gboolean closing;
|
||||
|
||||
g_object_get (config,
|
||||
"drawable", &drawable,
|
||||
"closing", &closing,
|
||||
NULL);
|
||||
|
||||
g_object_set (chooser, "drawable", drawable, NULL);
|
||||
|
||||
if (closing)
|
||||
{
|
||||
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
||||
(GSourceFunc) pika_drawable_select_remove_after_run,
|
||||
g_strdup (pika_procedure_get_name (procedure)),
|
||||
g_free);
|
||||
g_clear_pointer (&chooser->callback, g_free);
|
||||
}
|
||||
|
||||
g_clear_object (&drawable);
|
||||
|
||||
return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_drawable_select_remove_after_run (const gchar *procedure_name)
|
||||
{
|
||||
pika_plug_in_remove_temp_procedure (pika_get_plug_in (), procedure_name);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_clicked (PikaDrawableChooser *chooser)
|
||||
{
|
||||
if (chooser->callback)
|
||||
{
|
||||
/* Popup already created. Calling setter raises the popup. */
|
||||
pika_drawables_set_popup (chooser->callback, chooser->drawable);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaPlugIn *plug_in = pika_get_plug_in ();
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (chooser));
|
||||
GBytes *handle = NULL;
|
||||
gchar *callback_name;
|
||||
PikaProcedure *callback_procedure;
|
||||
|
||||
if (PIKA_IS_DIALOG (toplevel))
|
||||
handle = pika_dialog_get_native_handle (PIKA_DIALOG (toplevel));
|
||||
|
||||
callback_name = pika_pdb_temp_procedure_name (pika_get_pdb ());
|
||||
callback_procedure = pika_procedure_new (plug_in,
|
||||
callback_name,
|
||||
PIKA_PDB_PROC_TYPE_TEMPORARY,
|
||||
(PikaRunFunc) pika_temp_callback_run,
|
||||
g_object_ref (chooser),
|
||||
(GDestroyNotify) g_object_unref);
|
||||
PIKA_PROC_ARG_DRAWABLE (callback_procedure, "drawable",
|
||||
"Drawable", "The selected drawable",
|
||||
TRUE, G_PARAM_READWRITE);
|
||||
PIKA_PROC_ARG_BOOLEAN (callback_procedure, "closing",
|
||||
"Closing", "If the dialog was closing",
|
||||
FALSE, G_PARAM_READWRITE);
|
||||
|
||||
pika_plug_in_add_temp_procedure (plug_in, callback_procedure);
|
||||
g_object_unref (callback_procedure);
|
||||
g_free (callback_name);
|
||||
|
||||
if (pika_drawables_popup (pika_procedure_get_name (callback_procedure), chooser->title,
|
||||
g_type_name (chooser->drawable_type), chooser->drawable, handle))
|
||||
{
|
||||
/* Allow callbacks to be watched */
|
||||
pika_plug_in_extension_enable (plug_in);
|
||||
|
||||
chooser->callback = g_strdup (pika_procedure_get_name (callback_procedure));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("%s: failed to open remote drawable select dialog.", G_STRFUNC);
|
||||
pika_plug_in_remove_temp_procedure (plug_in, pika_procedure_get_name (callback_procedure));
|
||||
return;
|
||||
}
|
||||
pika_drawables_set_popup (chooser->callback, chooser->drawable);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_draw (PikaDrawableChooser *chooser)
|
||||
{
|
||||
PikaPreviewArea *area = PIKA_PREVIEW_AREA (chooser->preview);
|
||||
GtkAllocation allocation;
|
||||
gint x = 0;
|
||||
gint y = 0;
|
||||
|
||||
gtk_widget_get_allocation (chooser->preview, &allocation);
|
||||
|
||||
pika_drawable_chooser_get_thumbnail (chooser, allocation.width, allocation.height);
|
||||
|
||||
if (chooser->width < allocation.width ||
|
||||
chooser->height < allocation.height)
|
||||
{
|
||||
x = ((allocation.width - chooser->width) / 2);
|
||||
y = ((allocation.height - chooser->height) / 2);
|
||||
}
|
||||
pika_preview_area_reset (area);
|
||||
|
||||
if (chooser->thumbnail)
|
||||
{
|
||||
PikaImageType type;
|
||||
gint rowstride;
|
||||
|
||||
rowstride = chooser->width * chooser->bpp;
|
||||
switch (chooser->bpp)
|
||||
{
|
||||
case 1:
|
||||
type = PIKA_GRAY_IMAGE;
|
||||
break;
|
||||
case 2:
|
||||
type = PIKA_GRAYA_IMAGE;
|
||||
break;
|
||||
case 3:
|
||||
type = PIKA_RGB_IMAGE;
|
||||
break;
|
||||
case 4:
|
||||
type = PIKA_RGBA_IMAGE;
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
||||
pika_preview_area_draw (area, x, y, chooser->width, chooser->height, type,
|
||||
g_bytes_get_data (chooser->thumbnail, NULL), rowstride);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_drawable_chooser_get_thumbnail (PikaDrawableChooser *chooser,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
if (chooser->drawable == chooser->thumbnail_drawable &&
|
||||
chooser->width == width &&
|
||||
chooser->height == height)
|
||||
/* Let's assume drawable contents is not changing in a single run. */
|
||||
return;
|
||||
|
||||
g_clear_pointer (&chooser->thumbnail, g_bytes_unref);
|
||||
chooser->width = chooser->height = 0;
|
||||
|
||||
chooser->thumbnail_drawable = chooser->drawable;
|
||||
if (chooser->drawable)
|
||||
chooser->thumbnail = pika_drawable_get_thumbnail_data (chooser->drawable,
|
||||
width, height,
|
||||
&chooser->width,
|
||||
&chooser->height,
|
||||
&chooser->bpp);
|
||||
}
|
48
libpika/pikadrawablechooser.h
Normal file
48
libpika/pikadrawablechooser.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikadrawablechooser.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/>.
|
||||
*/
|
||||
|
||||
#if !defined (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_DRAWABLE_CHOOSER_H__
|
||||
#define __PIKA_DRAWABLE_CHOOSER_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_DRAWABLE_CHOOSER (pika_drawable_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaDrawableChooser, pika_drawable_chooser, PIKA, DRAWABLE_CHOOSER, GtkBox)
|
||||
|
||||
|
||||
GtkWidget * pika_drawable_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
GType drawable_type,
|
||||
PikaDrawable *drawable);
|
||||
|
||||
PikaDrawable * pika_drawable_chooser_get_drawable (PikaDrawableChooser *chooser);
|
||||
void pika_drawable_chooser_set_drawable (PikaDrawableChooser *chooser,
|
||||
PikaDrawable *drawable);
|
||||
GtkWidget * pika_drawable_chooser_get_label (PikaDrawableChooser *widget);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_DRAWABLE_CHOOSER_H__ */
|
151
libpika/pikadrawableselect_pdb.c
Normal file
151
libpika/pikadrawableselect_pdb.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikadrawableselect_pdb.c
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* NOTE: This file is auto-generated by pdbgen.pl */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "stamp-pdbgen.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikadrawableselect
|
||||
* @title: pikadrawableselect
|
||||
* @short_description: Methods of a drawable chooser dialog
|
||||
*
|
||||
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* pika_drawables_popup:
|
||||
* @callback: The callback PDB proc to call when user chooses an drawable.
|
||||
* @popup_title: Title of the drawable selection dialog.
|
||||
* @drawable_type: The name of the PIKA_TYPE_DRAWABLE subtype.
|
||||
* @initial_drawable: The drawable to set as the initial choice.
|
||||
* @parent_window: An optional parent window handle for the popup to be set transient to.
|
||||
*
|
||||
* Invokes the drawable selection dialog.
|
||||
*
|
||||
* Opens a dialog letting a user choose an drawable.
|
||||
*
|
||||
* Returns: TRUE on success.
|
||||
**/
|
||||
gboolean
|
||||
pika_drawables_popup (const gchar *callback,
|
||||
const gchar *popup_title,
|
||||
const gchar *drawable_type,
|
||||
PikaDrawable *initial_drawable,
|
||||
GBytes *parent_window)
|
||||
{
|
||||
PikaValueArray *args;
|
||||
PikaValueArray *return_vals;
|
||||
gboolean success = TRUE;
|
||||
|
||||
args = pika_value_array_new_from_types (NULL,
|
||||
G_TYPE_STRING, callback,
|
||||
G_TYPE_STRING, popup_title,
|
||||
G_TYPE_STRING, drawable_type,
|
||||
PIKA_TYPE_DRAWABLE, initial_drawable,
|
||||
G_TYPE_BYTES, parent_window,
|
||||
G_TYPE_NONE);
|
||||
|
||||
return_vals = _pika_pdb_run_procedure_array (pika_get_pdb (),
|
||||
"pika-drawables-popup",
|
||||
args);
|
||||
pika_value_array_unref (args);
|
||||
|
||||
success = PIKA_VALUES_GET_ENUM (return_vals, 0) == PIKA_PDB_SUCCESS;
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawables_close_popup:
|
||||
* @callback: The name of the callback registered for this pop-up.
|
||||
*
|
||||
* Close the drawable selection dialog.
|
||||
*
|
||||
* Closes an open drawable selection dialog.
|
||||
*
|
||||
* Returns: TRUE on success.
|
||||
**/
|
||||
gboolean
|
||||
pika_drawables_close_popup (const gchar *callback)
|
||||
{
|
||||
PikaValueArray *args;
|
||||
PikaValueArray *return_vals;
|
||||
gboolean success = TRUE;
|
||||
|
||||
args = pika_value_array_new_from_types (NULL,
|
||||
G_TYPE_STRING, callback,
|
||||
G_TYPE_NONE);
|
||||
|
||||
return_vals = _pika_pdb_run_procedure_array (pika_get_pdb (),
|
||||
"pika-drawables-close-popup",
|
||||
args);
|
||||
pika_value_array_unref (args);
|
||||
|
||||
success = PIKA_VALUES_GET_ENUM (return_vals, 0) == PIKA_PDB_SUCCESS;
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_drawables_set_popup:
|
||||
* @callback: The name of the callback registered for this pop-up.
|
||||
* @drawable: The drawable to set as selected.
|
||||
*
|
||||
* Sets the selected drawable in a drawable selection dialog.
|
||||
*
|
||||
* Sets the selected drawable in a drawable selection dialog.
|
||||
*
|
||||
* Returns: TRUE on success.
|
||||
**/
|
||||
gboolean
|
||||
pika_drawables_set_popup (const gchar *callback,
|
||||
PikaDrawable *drawable)
|
||||
{
|
||||
PikaValueArray *args;
|
||||
PikaValueArray *return_vals;
|
||||
gboolean success = TRUE;
|
||||
|
||||
args = pika_value_array_new_from_types (NULL,
|
||||
G_TYPE_STRING, callback,
|
||||
PIKA_TYPE_DRAWABLE, drawable,
|
||||
G_TYPE_NONE);
|
||||
|
||||
return_vals = _pika_pdb_run_procedure_array (pika_get_pdb (),
|
||||
"pika-drawables-set-popup",
|
||||
args);
|
||||
pika_value_array_unref (args);
|
||||
|
||||
success = PIKA_VALUES_GET_ENUM (return_vals, 0) == PIKA_PDB_SUCCESS;
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
return success;
|
||||
}
|
47
libpika/pikadrawableselect_pdb.h
Normal file
47
libpika/pikadrawableselect_pdb.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikadrawableselect_pdb.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* NOTE: This file is auto-generated by pdbgen.pl */
|
||||
|
||||
#if !defined (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_DRAWABLE_SELECT_PDB_H__
|
||||
#define __PIKA_DRAWABLE_SELECT_PDB_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
gboolean pika_drawables_popup (const gchar *callback,
|
||||
const gchar *popup_title,
|
||||
const gchar *drawable_type,
|
||||
PikaDrawable *initial_drawable,
|
||||
GBytes *parent_window);
|
||||
gboolean pika_drawables_close_popup (const gchar *callback);
|
||||
gboolean pika_drawables_set_popup (const gchar *callback,
|
||||
PikaDrawable *drawable);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_DRAWABLE_SELECT_PDB_H__ */
|
86
libpika/pikafont.c
Normal file
86
libpika/pikafont.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikafont.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 <pango/pangofc-fontmap.h>
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikafont.h"
|
||||
|
||||
struct _PikaFont
|
||||
{
|
||||
PikaResource parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PikaFont, pika_font, PIKA_TYPE_RESOURCE);
|
||||
|
||||
|
||||
static void pika_font_class_init (PikaFontClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void pika_font_init (PikaFont *font)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_font_get_pango_font_description:
|
||||
* @font: (transfer none): the [class@Gimp.Font]
|
||||
*
|
||||
* Returns a [class@Pango.Font.Description] representing @font.
|
||||
*
|
||||
* Returns: (transfer full): a %PangoFontDescription representing @font.
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
PangoFontDescription *
|
||||
pika_font_get_pango_font_description (PikaFont *font)
|
||||
{
|
||||
PangoFontDescription *desc = NULL;
|
||||
gchar *name = NULL;
|
||||
gchar *collection_id = NULL;
|
||||
gboolean is_internal;
|
||||
|
||||
is_internal = _pika_resource_get_identifiers (PIKA_RESOURCE (font),
|
||||
&name, &collection_id);
|
||||
/* TODO: we can't create fonts from internal fonts right now, but it should
|
||||
* actually be possible because these are in fact alias to non-internal fonts.
|
||||
* See #9985.
|
||||
*/
|
||||
if (! is_internal)
|
||||
{
|
||||
gchar *expanded_path;
|
||||
|
||||
expanded_path = pika_config_path_expand (collection_id, FALSE, NULL);
|
||||
if (expanded_path != NULL &&
|
||||
FcConfigAppFontAddFile (FcConfigGetCurrent (), (const FcChar8 *) expanded_path))
|
||||
desc = pango_font_description_from_string (name);
|
||||
|
||||
g_free (expanded_path);
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
g_free (collection_id);
|
||||
|
||||
return desc;
|
||||
}
|
46
libpika/pikafont.h
Normal file
46
libpika/pikafont.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikafont.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 (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_FONT_H__
|
||||
#define __PIKA_FONT_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
#include <libpika/pikaresource.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_FONT (pika_font_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaFont, pika_font, PIKA, FONT, PikaResource)
|
||||
|
||||
|
||||
PangoFontDescription * pika_font_get_pango_font_description (PikaFont *font);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_FONT_H__ */
|
158
libpika/pikafontchooser.c
Normal file
158
libpika/pikafontchooser.c
Normal file
@ -0,0 +1,158 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikafontchooser.c
|
||||
* Copyright (C) 2003 Sven Neumann <sven@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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikafontchooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikafontchooser
|
||||
* @title: PikaFontChooser
|
||||
* @short_description: A button which pops up a font selection dialog.
|
||||
*
|
||||
* A button which pops up a font selection dialog.
|
||||
**/
|
||||
|
||||
struct _PikaFontChooser
|
||||
{
|
||||
PikaResourceChooser parent_instance;
|
||||
|
||||
GtkWidget *label;
|
||||
};
|
||||
|
||||
|
||||
static void pika_font_chooser_draw_interior (PikaResourceChooser *self);
|
||||
|
||||
|
||||
static const GtkTargetEntry drag_target = { "application/x-pika-font-name", 0, 0 };
|
||||
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaFontChooser, pika_font_chooser, PIKA_TYPE_RESOURCE_CHOOSER)
|
||||
|
||||
|
||||
static void
|
||||
pika_font_chooser_class_init (PikaFontChooserClass *klass)
|
||||
{
|
||||
PikaResourceChooserClass *superclass = PIKA_RESOURCE_CHOOSER_CLASS (klass);
|
||||
|
||||
superclass->draw_interior = pika_font_chooser_draw_interior;
|
||||
superclass->resource_type = PIKA_TYPE_FONT;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_chooser_init (PikaFontChooser *self)
|
||||
{
|
||||
GtkWidget *button;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *image;
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_container_add (GTK_CONTAINER (self), button);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_container_add (GTK_CONTAINER (button), hbox);
|
||||
|
||||
image = gtk_image_new_from_icon_name (PIKA_ICON_FONT,
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
|
||||
self->label = gtk_label_new ("unknown");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), self->label, TRUE, TRUE, 4);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (self));
|
||||
|
||||
pika_resource_chooser_set_drag_target (PIKA_RESOURCE_CHOOSER (self),
|
||||
hbox, &drag_target);
|
||||
|
||||
pika_resource_chooser_set_clickable (PIKA_RESOURCE_CHOOSER (self), button);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_chooser_draw_interior (PikaResourceChooser *self)
|
||||
{
|
||||
PikaFontChooser *font_select= PIKA_FONT_CHOOSER (self);
|
||||
PikaResource *resource;
|
||||
gchar *name = NULL;
|
||||
|
||||
resource = pika_resource_chooser_get_resource (self);
|
||||
|
||||
if (resource)
|
||||
name = pika_resource_get_name (resource);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (font_select->label), name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pika_font_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @resource: (nullable): Initial font.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a font.
|
||||
* You can put this widget in a plug-in dialog.
|
||||
*
|
||||
* When font is NULL, initial choice is from context.
|
||||
*
|
||||
* Returns: A #GtkWidget that you can use in your UI.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_font_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource)
|
||||
{
|
||||
GtkWidget *chooser;
|
||||
|
||||
g_return_val_if_fail (resource == NULL || PIKA_IS_FONT (resource), NULL);
|
||||
|
||||
if (resource == NULL)
|
||||
resource = PIKA_RESOURCE (pika_context_get_font ());
|
||||
|
||||
if (title)
|
||||
chooser = g_object_new (PIKA_TYPE_FONT_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
else
|
||||
chooser = g_object_new (PIKA_TYPE_FONT_CHOOSER,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
|
||||
pika_font_chooser_draw_interior (PIKA_RESOURCE_CHOOSER (chooser));
|
||||
|
||||
return chooser;
|
||||
}
|
43
libpika/pikafontchooser.h
Normal file
43
libpika/pikafontchooser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikafontchooser.h
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_FONT_CHOOSER_H__
|
||||
#define __PIKA_FONT_CHOOSER_H__
|
||||
|
||||
#include <libpika/pikaresourcechooser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_FONT_CHOOSER (pika_font_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaFontChooser, pika_font_chooser, PIKA, FONT_CHOOSER, PikaResourceChooser)
|
||||
|
||||
|
||||
GtkWidget * pika_font_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_FONT_CHOOSER_H__ */
|
42
libpika/pikagradient.c
Normal file
42
libpika/pikagradient.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikagradient.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 "pika.h"
|
||||
|
||||
#include "pikagradient.h"
|
||||
|
||||
struct _PikaGradient
|
||||
{
|
||||
PikaResource parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PikaGradient, pika_gradient, PIKA_TYPE_RESOURCE);
|
||||
|
||||
|
||||
static void pika_gradient_class_init (PikaGradientClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void pika_gradient_init (PikaGradient *gradient)
|
||||
{
|
||||
}
|
43
libpika/pikagradient.h
Normal file
43
libpika/pikagradient.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikagradient.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 (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_GRADIENT_H__
|
||||
#define __PIKA_GRADIENT_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
#include <libpika/pikaresource.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_GRADIENT (pika_gradient_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaGradient, pika_gradient, PIKA, GRADIENT, PikaResource)
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_GRADIENT_H__ */
|
303
libpika/pikagradientchooser.c
Normal file
303
libpika/pikagradientchooser.c
Normal file
@ -0,0 +1,303 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikagradientchooser.c
|
||||
* Copyright (C) 1998 Andy Thomas
|
||||
*
|
||||
* 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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikagradientchooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikagradientchooser
|
||||
* @title: PikaGradientChooser
|
||||
* @short_description: A button which pops up a gradient select dialog.
|
||||
*
|
||||
* A button which pops up a gradient select dialog.
|
||||
**/
|
||||
|
||||
|
||||
struct _PikaGradientChooser
|
||||
{
|
||||
PikaResourceChooser parent_instance;
|
||||
|
||||
GtkWidget *preview;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_gradient_chooser_draw_interior (PikaResourceChooser *self);
|
||||
|
||||
static void pika_gradient_select_preview_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
PikaGradientChooser *self);
|
||||
static gboolean pika_gradient_select_preview_draw_handler (GtkWidget *preview,
|
||||
cairo_t *cr,
|
||||
PikaGradientChooser *self);
|
||||
|
||||
|
||||
static const GtkTargetEntry drag_target = { "application/x-pika-gradient-name", 0 };
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaGradientChooser,
|
||||
pika_gradient_chooser,
|
||||
PIKA_TYPE_RESOURCE_CHOOSER)
|
||||
|
||||
/* Initial dimensions of widget. */
|
||||
#define CELL_HEIGHT 18
|
||||
#define CELL_WIDTH 84
|
||||
|
||||
static void
|
||||
pika_gradient_chooser_class_init (PikaGradientChooserClass *klass)
|
||||
{
|
||||
PikaResourceChooserClass *superclass = PIKA_RESOURCE_CHOOSER_CLASS (klass);
|
||||
|
||||
superclass->draw_interior = pika_gradient_chooser_draw_interior;
|
||||
superclass->resource_type = PIKA_TYPE_GRADIENT;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_gradient_chooser_init (PikaGradientChooser *self)
|
||||
{
|
||||
GtkWidget *button;
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_container_add (GTK_CONTAINER (self), button);
|
||||
|
||||
self->preview = gtk_drawing_area_new ();
|
||||
gtk_widget_set_size_request (self->preview, CELL_WIDTH, CELL_HEIGHT);
|
||||
gtk_container_add (GTK_CONTAINER (button), self->preview);
|
||||
|
||||
g_signal_connect (self->preview, "size-allocate",
|
||||
G_CALLBACK (pika_gradient_select_preview_size_allocate),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->preview, "draw",
|
||||
G_CALLBACK (pika_gradient_select_preview_draw_handler),
|
||||
self);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (self));
|
||||
|
||||
pika_resource_chooser_set_drag_target (PIKA_RESOURCE_CHOOSER (self),
|
||||
self->preview, &drag_target);
|
||||
|
||||
pika_resource_chooser_set_clickable (PIKA_RESOURCE_CHOOSER (self), button);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_gradient_chooser_draw_interior (PikaResourceChooser *self)
|
||||
{
|
||||
PikaGradientChooser *gradient_select = PIKA_GRADIENT_CHOOSER (self);
|
||||
|
||||
gtk_widget_queue_draw (gradient_select->preview);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pika_gradient_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @gradient: (nullable): Initial gradient.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a gradient.
|
||||
* You can use this widget in a table in a plug-in dialog.
|
||||
*
|
||||
* Returns: A #GtkWidget that you can use in your UI.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_gradient_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *gradient)
|
||||
{
|
||||
GtkWidget *self;
|
||||
|
||||
if (gradient == NULL)
|
||||
gradient = PIKA_RESOURCE (pika_context_get_gradient ());
|
||||
|
||||
if (title)
|
||||
self = g_object_new (PIKA_TYPE_GRADIENT_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"resource", gradient,
|
||||
NULL);
|
||||
else
|
||||
self = g_object_new (PIKA_TYPE_GRADIENT_CHOOSER,
|
||||
"label", label,
|
||||
"resource", gradient,
|
||||
NULL);
|
||||
|
||||
pika_gradient_chooser_draw_interior (PIKA_RESOURCE_CHOOSER (self));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
/* Get array of samples from self's gradient.
|
||||
* Return array and size at given handles.
|
||||
* Return success.
|
||||
*/
|
||||
static gboolean
|
||||
get_gradient_data (PikaGradientChooser *self,
|
||||
gint allocation_width,
|
||||
gint *sample_count,
|
||||
gdouble **sample_array)
|
||||
{
|
||||
PikaGradient *gradient;
|
||||
gboolean result;
|
||||
gdouble *samples;
|
||||
gint n_samples;
|
||||
|
||||
g_object_get (self, "resource", &gradient, NULL);
|
||||
|
||||
result = pika_gradient_get_uniform_samples (gradient,
|
||||
allocation_width,
|
||||
FALSE, /* not reversed. */
|
||||
&n_samples,
|
||||
&samples);
|
||||
|
||||
if (result)
|
||||
{
|
||||
/* Return array of samples to dereferenced handles. */
|
||||
*sample_array = samples;
|
||||
*sample_count = n_samples;
|
||||
}
|
||||
|
||||
g_object_unref (gradient);
|
||||
|
||||
/* When result is true, caller must free the array. */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Called on widget resized. */
|
||||
static void
|
||||
pika_gradient_select_preview_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
PikaGradientChooser *self)
|
||||
{
|
||||
/* Do nothing.
|
||||
*
|
||||
* In former code, we cached the gradient data in self, on allocate event.
|
||||
* But allocate event always seems to be paired with a draw event,
|
||||
* so there is no point in caching the gradient data.
|
||||
* And caching gradient data is a premature optimization,
|
||||
* without deep knowledge of Gtk and actual performance testing,
|
||||
* you can't know caching helps performance.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Draw array of samples.
|
||||
* This understands mostly cairo, and little about gradient.
|
||||
*/
|
||||
static void
|
||||
pika_gradient_select_preview_draw (cairo_t *cr,
|
||||
gint src_width,
|
||||
gint dest_width,
|
||||
gdouble *src)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_surface_t *surface;
|
||||
guchar *dest;
|
||||
gint x;
|
||||
|
||||
pattern = pika_cairo_checkerboard_create (cr, PIKA_CHECK_SIZE_SM, NULL, NULL);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_paint (cr);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, src_width, 1);
|
||||
|
||||
for (x = 0, dest = cairo_image_surface_get_data (surface);
|
||||
x < src_width;
|
||||
x++, src += 4, dest += 4)
|
||||
{
|
||||
PikaRGB color;
|
||||
guchar r, g, b, a;
|
||||
|
||||
pika_rgba_set (&color, src[0], src[1], src[2], src[3]);
|
||||
pika_rgba_get_uchar (&color, &r, &g, &b, &a);
|
||||
|
||||
PIKA_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a);
|
||||
}
|
||||
|
||||
cairo_surface_mark_dirty (surface);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_scale (cr, (gdouble) dest_width / (gdouble) src_width, 1.0);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_paint (cr);
|
||||
}
|
||||
|
||||
/* Handles a draw signal.
|
||||
* Draw self, i.e. interior of button.
|
||||
*
|
||||
* Always returns FALSE, but doesn't draw when fail to get gradient data.
|
||||
*
|
||||
* Is passed neither gradient nor attributes of gradient: get them now from self.
|
||||
*/
|
||||
static gboolean
|
||||
pika_gradient_select_preview_draw_handler (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
PikaGradientChooser *self)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
|
||||
/* Attributes of the source.*/
|
||||
gdouble *src;
|
||||
gint n_samples;
|
||||
gint src_width;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
if (!get_gradient_data (self, allocation.width, &n_samples, &src))
|
||||
return FALSE;
|
||||
|
||||
/* Width in pixels of src, since BPP is 4. */
|
||||
src_width = n_samples / 4;
|
||||
|
||||
pika_gradient_select_preview_draw (cr, src_width, allocation.width, src);
|
||||
|
||||
g_free (src);
|
||||
|
||||
return FALSE;
|
||||
}
|
43
libpika/pikagradientchooser.h
Normal file
43
libpika/pikagradientchooser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikagradientchooser.h
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_GRADIENT_CHOOSER_H__
|
||||
#define __PIKA_GRADIENT_CHOOSER_H__
|
||||
|
||||
#include <libpika/pikaresourcechooser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_GRADIENT_CHOOSER (pika_gradient_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaGradientChooser, pika_gradient_chooser, PIKA, GRADIENT_CHOOSER, PikaResourceChooser)
|
||||
|
||||
|
||||
GtkWidget * pika_gradient_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *gradient);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_GRADIENT_CHOOSER_H__ */
|
42
libpika/pikapalette.c
Normal file
42
libpika/pikapalette.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapalette.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 "pika.h"
|
||||
|
||||
#include "pikapalette.h"
|
||||
|
||||
struct _PikaPalette
|
||||
{
|
||||
PikaResource parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PikaPalette, pika_palette, PIKA_TYPE_RESOURCE);
|
||||
|
||||
|
||||
static void pika_palette_class_init (PikaPaletteClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void pika_palette_init (PikaPalette *palette)
|
||||
{
|
||||
}
|
43
libpika/pikapalette.h
Normal file
43
libpika/pikapalette.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapalette.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 (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_PALETTE_H__
|
||||
#define __PIKA_PALETTE_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
#include <libpika/pikaresource.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_PALETTE (pika_palette_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaPalette, pika_palette, PIKA, PALETTE, PikaResource)
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_PALETTE_H__ */
|
154
libpika/pikapalettechooser.c
Normal file
154
libpika/pikapalettechooser.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapalettechooser.c
|
||||
* Copyright (C) 2004 Michael Natterer <mitch@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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikapalettechooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikapalettechooser
|
||||
* @title: PikaPaletteChooser
|
||||
* @short_description: A button which pops up a palette selection dialog.
|
||||
*
|
||||
* A button which pops up a palette selection dialog.
|
||||
**/
|
||||
|
||||
struct _PikaPaletteChooser
|
||||
{
|
||||
PikaResourceChooser parent_instance;
|
||||
|
||||
GtkWidget *label;
|
||||
GtkWidget *button;
|
||||
};
|
||||
|
||||
|
||||
static void pika_palette_chooser_draw_interior (PikaResourceChooser *self);
|
||||
|
||||
|
||||
static const GtkTargetEntry drag_target = { "application/x-pika-palette-name", 0, 0 };
|
||||
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaPaletteChooser, pika_palette_chooser, PIKA_TYPE_RESOURCE_CHOOSER)
|
||||
|
||||
|
||||
static void
|
||||
pika_palette_chooser_class_init (PikaPaletteChooserClass *klass)
|
||||
{
|
||||
PikaResourceChooserClass *superclass = PIKA_RESOURCE_CHOOSER_CLASS (klass);
|
||||
|
||||
superclass->draw_interior = pika_palette_chooser_draw_interior;
|
||||
superclass->resource_type = PIKA_TYPE_PALETTE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_palette_chooser_init (PikaPaletteChooser *self)
|
||||
{
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *image;
|
||||
|
||||
self->button = gtk_button_new ();
|
||||
gtk_container_add (GTK_CONTAINER (self), self->button);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_container_add (GTK_CONTAINER (self->button), hbox);
|
||||
|
||||
image = gtk_image_new_from_icon_name (PIKA_ICON_PALETTE,
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
|
||||
self->label = gtk_label_new ("unknown");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), self->label, TRUE, TRUE, 4);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (self));
|
||||
|
||||
pika_resource_chooser_set_drag_target (PIKA_RESOURCE_CHOOSER (self),
|
||||
hbox, &drag_target);
|
||||
pika_resource_chooser_set_clickable (PIKA_RESOURCE_CHOOSER (self), self->button);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_palette_chooser_draw_interior (PikaResourceChooser *self)
|
||||
{
|
||||
PikaPaletteChooser *palette_select= PIKA_PALETTE_CHOOSER (self);
|
||||
PikaResource *resource;
|
||||
gchar *name = NULL;
|
||||
|
||||
resource = pika_resource_chooser_get_resource (self);
|
||||
|
||||
if (resource)
|
||||
name = pika_resource_get_name (resource);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (palette_select->label), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_palette_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @resource: (nullable): Initial palette.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a palette.
|
||||
* You can put this widget in a table in a plug-in dialog.
|
||||
*
|
||||
* When palette is NULL, initial choice is from context.
|
||||
*
|
||||
* Returns: A #GtkWidget that you can use in your UI.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_palette_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource)
|
||||
{
|
||||
GtkWidget *self;
|
||||
|
||||
if (resource == NULL)
|
||||
resource = PIKA_RESOURCE (pika_context_get_palette ());
|
||||
|
||||
if (title)
|
||||
self = g_object_new (PIKA_TYPE_PALETTE_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
else
|
||||
self = g_object_new (PIKA_TYPE_PALETTE_CHOOSER,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
|
||||
pika_palette_chooser_draw_interior (PIKA_RESOURCE_CHOOSER (self));
|
||||
|
||||
return self;
|
||||
}
|
43
libpika/pikapalettechooser.h
Normal file
43
libpika/pikapalettechooser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapaletteselectbutton.h
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_PALETTE_CHOOSER_H__
|
||||
#define __PIKA_PALETTE_CHOOSER_H__
|
||||
|
||||
#include <libpika/pikaresourcechooser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_PALETTE_CHOOSER (pika_palette_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaPaletteChooser, pika_palette_chooser, PIKA, PALETTE_CHOOSER, PikaResourceChooser)
|
||||
|
||||
|
||||
GtkWidget * pika_palette_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_PALETTE_CHOOSER_H__ */
|
207
libpika/pikapattern.c
Normal file
207
libpika/pikapattern.c
Normal file
@ -0,0 +1,207 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapattern.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 "pika.h"
|
||||
|
||||
#include "pikapattern.h"
|
||||
|
||||
struct _PikaPattern
|
||||
{
|
||||
PikaResource parent_instance;
|
||||
|
||||
/* Native size buffer of the pattern contents. */
|
||||
GeglBuffer *buffer;
|
||||
};
|
||||
|
||||
static void pika_pattern_finalize (GObject *object);
|
||||
static void pika_pattern_get_data (PikaPattern *pattern);
|
||||
static GeglBuffer * pika_pattern_scale (GeglBuffer *buffer,
|
||||
gint max_width,
|
||||
gint max_height);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaPattern, pika_pattern, PIKA_TYPE_RESOURCE);
|
||||
|
||||
|
||||
static void pika_pattern_class_init (PikaPatternClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_pattern_finalize;
|
||||
}
|
||||
|
||||
static void pika_pattern_init (PikaPattern *pattern)
|
||||
{
|
||||
pattern->buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_pattern_finalize (GObject *object)
|
||||
{
|
||||
PikaPattern *pattern = PIKA_PATTERN (object);
|
||||
|
||||
g_clear_object (&pattern->buffer);
|
||||
|
||||
G_OBJECT_CLASS (pika_pattern_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pika_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 [class@Gegl.Buffer].
|
||||
*/
|
||||
GeglBuffer *
|
||||
pika_pattern_get_buffer (PikaPattern *pattern,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format)
|
||||
{
|
||||
pika_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 pika_pattern_scale (pattern->buffer, max_width, max_height);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_pattern_get_data (PikaPattern *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);
|
||||
|
||||
_pika_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 pika_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 *
|
||||
pika_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", PIKA_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
libpika/pikapattern.h
Normal file
49
libpika/pikapattern.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapattern.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 (__PIKA_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pika.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_PATTERN_H__
|
||||
#define __PIKA_PATTERN_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* For information look into the C source or the html documentation */
|
||||
|
||||
|
||||
#include <libpika/pikaresource.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_PATTERN (pika_pattern_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaPattern, pika_pattern, PIKA, PATTERN, PikaResource)
|
||||
|
||||
|
||||
|
||||
GeglBuffer * pika_pattern_get_buffer (PikaPattern *pattern,
|
||||
gint max_width,
|
||||
gint max_height,
|
||||
const Babl *format) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_PATTERN_H__ */
|
381
libpika/pikapatternchooser.c
Normal file
381
libpika/pikapatternchooser.c
Normal file
@ -0,0 +1,381 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapatternchooser.c
|
||||
* Copyright (C) 1998 Andy Thomas
|
||||
*
|
||||
* 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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikapatternchooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikapatternchooser
|
||||
* @title: PikaPatternChooser
|
||||
* @short_description: 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 40
|
||||
|
||||
struct _PikaPatternChooser
|
||||
{
|
||||
PikaResourceChooser parent_instance;
|
||||
|
||||
GtkWidget *preview;
|
||||
GtkWidget *popup;
|
||||
|
||||
PikaPattern *pattern;
|
||||
GeglBuffer *buffer;
|
||||
gint width;
|
||||
gint height;
|
||||
};
|
||||
|
||||
/* local */
|
||||
|
||||
static gboolean pika_pattern_select_on_preview_events (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
PikaPatternChooser *button);
|
||||
|
||||
/* local drawing methods. */
|
||||
static void pika_pattern_select_preview_fill_draw (PikaPatternChooser *chooser,
|
||||
PikaPreviewArea *area);
|
||||
|
||||
static void pika_pattern_chooser_draw (PikaResourceChooser *self);
|
||||
static void pika_pattern_chooser_get_pattern_image (PikaPatternChooser *self,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
/* Popup methods. */
|
||||
static void pika_pattern_chooser_open_popup (PikaPatternChooser *button,
|
||||
gint x,
|
||||
gint y);
|
||||
static void pika_pattern_chooser_close_popup (PikaPatternChooser *button);
|
||||
|
||||
|
||||
/* A GtkTargetEntry has a string and two ints.
|
||||
* This is one, but we treat it as an array.
|
||||
*/
|
||||
static const GtkTargetEntry drag_target = { "application/x-pika-pattern-name", 0, 0 };
|
||||
|
||||
G_DEFINE_FINAL_TYPE (PikaPatternChooser, pika_pattern_chooser, PIKA_TYPE_RESOURCE_CHOOSER)
|
||||
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_class_init (PikaPatternChooserClass *klass)
|
||||
{
|
||||
PikaResourceChooserClass *superclass = PIKA_RESOURCE_CHOOSER_CLASS (klass);
|
||||
|
||||
superclass->draw_interior = pika_pattern_chooser_draw;
|
||||
superclass->resource_type = PIKA_TYPE_PATTERN;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_init (PikaPatternChooser *self)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *button;
|
||||
|
||||
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_box_pack_start (GTK_BOX (self), frame, FALSE, FALSE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
self->preview = pika_preview_area_new ();
|
||||
gtk_widget_add_events (self->preview,
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
gtk_widget_set_size_request (self->preview, CELL_SIZE, CELL_SIZE);
|
||||
gtk_container_add (GTK_CONTAINER (frame), self->preview);
|
||||
gtk_widget_show (self->preview);
|
||||
|
||||
g_signal_connect_swapped (self->preview, "size-allocate",
|
||||
G_CALLBACK (pika_pattern_chooser_draw),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->preview, "event",
|
||||
G_CALLBACK (pika_pattern_select_on_preview_events),
|
||||
self);
|
||||
|
||||
button = gtk_button_new_with_mnemonic (_("_Browse..."));
|
||||
gtk_box_pack_start (GTK_BOX (self), button, FALSE, FALSE, 0);
|
||||
|
||||
pika_resource_chooser_set_drag_target (PIKA_RESOURCE_CHOOSER (self),
|
||||
self->preview, &drag_target);
|
||||
|
||||
pika_resource_chooser_set_clickable (PIKA_RESOURCE_CHOOSER (self), button);
|
||||
gtk_widget_show (button);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_pattern_chooser_new:
|
||||
* @title: (nullable): Title of the dialog to use or %NULL to use the default title.
|
||||
* @label: (nullable): Button label or %NULL for no label.
|
||||
* @resource: (nullable): Initial pattern.
|
||||
*
|
||||
* Creates a new #GtkWidget that lets a user choose a pattern.
|
||||
* You can put this widget in a table in a plug-in dialog.
|
||||
*
|
||||
* When pattern is NULL, initial choice is from context.
|
||||
*
|
||||
* Returns: A #GtkWidget that you can use in your UI.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_pattern_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource)
|
||||
{
|
||||
GtkWidget *self;
|
||||
|
||||
if (resource == NULL)
|
||||
resource = PIKA_RESOURCE (pika_context_get_pattern ());
|
||||
g_return_val_if_fail (PIKA_IS_PATTERN (resource), NULL);
|
||||
|
||||
if (title)
|
||||
self = g_object_new (PIKA_TYPE_PATTERN_CHOOSER,
|
||||
"title", title,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
else
|
||||
self = g_object_new (PIKA_TYPE_PATTERN_CHOOSER,
|
||||
"label", label,
|
||||
"resource", resource,
|
||||
NULL);
|
||||
|
||||
pika_pattern_chooser_draw (PIKA_RESOURCE_CHOOSER (self));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_draw (PikaResourceChooser *chooser)
|
||||
{
|
||||
PikaPatternChooser *pchooser = PIKA_PATTERN_CHOOSER (chooser);
|
||||
GtkAllocation allocation;
|
||||
|
||||
gtk_widget_get_allocation (pchooser->preview, &allocation);
|
||||
|
||||
pika_pattern_chooser_get_pattern_image (pchooser, allocation.width, allocation.height);
|
||||
pika_pattern_select_preview_fill_draw (pchooser, PIKA_PREVIEW_AREA (pchooser->preview));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_get_pattern_image (PikaPatternChooser *chooser,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
PikaPattern *pattern;
|
||||
|
||||
g_object_get (chooser, "resource", &pattern, NULL);
|
||||
|
||||
if (chooser->pattern == pattern &&
|
||||
chooser->width == width &&
|
||||
chooser->height == height)
|
||||
{
|
||||
/* Let's assume pattern contents is not changing in a single run. */
|
||||
g_object_unref (pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_object (&chooser->buffer);
|
||||
|
||||
chooser->pattern = pattern;
|
||||
chooser->buffer = pika_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);
|
||||
}
|
||||
|
||||
/* On mouse events in self's preview, popup a zoom view of entire pattern */
|
||||
static gboolean
|
||||
pika_pattern_select_on_preview_events (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
PikaPatternChooser *self)
|
||||
{
|
||||
GdkEventButton *bevent;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
bevent = (GdkEventButton *) event;
|
||||
|
||||
if (bevent->button == 1)
|
||||
{
|
||||
gtk_grab_add (widget);
|
||||
pika_pattern_chooser_open_popup (self,
|
||||
bevent->x, bevent->y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_BUTTON_RELEASE:
|
||||
bevent = (GdkEventButton *) event;
|
||||
|
||||
if (bevent->button == 1)
|
||||
{
|
||||
gtk_grab_remove (widget);
|
||||
pika_pattern_chooser_close_popup (self);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Fill a PikaPreviewArea with a image then draw. */
|
||||
static void
|
||||
pika_pattern_select_preview_fill_draw (PikaPatternChooser *chooser,
|
||||
PikaPreviewArea *area)
|
||||
{
|
||||
GeglBuffer *src_buffer;
|
||||
const Babl *format;
|
||||
const Babl *model;
|
||||
guchar *src;
|
||||
PikaImageType type;
|
||||
gint rowstride;
|
||||
GtkAllocation allocation;
|
||||
gint x = 0;
|
||||
gint y = 0;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
|
||||
|
||||
/* Fill with white. */
|
||||
if (chooser->width < allocation.width ||
|
||||
chooser->height < allocation.height)
|
||||
{
|
||||
pika_preview_area_fill (area,
|
||||
0, 0,
|
||||
allocation.width,
|
||||
allocation.height,
|
||||
0xFF, 0xFF, 0xFF);
|
||||
|
||||
x = ((allocation.width - chooser->width) / 2);
|
||||
y = ((allocation.height - chooser->height) / 2);
|
||||
}
|
||||
|
||||
/* Draw the pattern. */
|
||||
src_buffer = chooser->buffer;
|
||||
format = gegl_buffer_get_format (src_buffer);
|
||||
rowstride = chooser->width * babl_format_get_bytes_per_pixel (format);
|
||||
model = babl_format_get_model (format);
|
||||
|
||||
if (model == babl_model ("R'G'B'"))
|
||||
type = PIKA_RGB_IMAGE;
|
||||
else if (model == babl_model ("R'G'B'A"))
|
||||
type = PIKA_RGBA_IMAGE;
|
||||
else if (model == babl_model ("Y'"))
|
||||
type = PIKA_GRAY_IMAGE;
|
||||
else if (model == babl_model ("Y'A"))
|
||||
type = PIKA_GRAYA_IMAGE;
|
||||
else
|
||||
/* I just know that we can't have other formats because I set it up this way
|
||||
* in pika_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);
|
||||
pika_preview_area_draw (area, x, y, chooser->width, chooser->height, type, src, rowstride);
|
||||
|
||||
g_free (src);
|
||||
}
|
||||
|
||||
/* popup methods. */
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_open_popup (PikaPatternChooser *chooser,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *preview;
|
||||
GdkMonitor *monitor;
|
||||
GdkRectangle workarea;
|
||||
gint x_org;
|
||||
gint y_org;
|
||||
|
||||
if (chooser->popup)
|
||||
pika_pattern_chooser_close_popup (chooser);
|
||||
|
||||
if (chooser->width <= CELL_SIZE && chooser->height <= CELL_SIZE)
|
||||
return;
|
||||
|
||||
chooser->popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_window_set_type_hint (GTK_WINDOW (chooser->popup), GDK_WINDOW_TYPE_HINT_DND);
|
||||
gtk_window_set_screen (GTK_WINDOW (chooser->popup),
|
||||
gtk_widget_get_screen (GTK_WIDGET (chooser)));
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
|
||||
gtk_container_add (GTK_CONTAINER (chooser->popup), frame);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
preview = pika_preview_area_new ();
|
||||
gtk_widget_set_size_request (preview, chooser->width, chooser->height);
|
||||
gtk_container_add (GTK_CONTAINER (frame), preview);
|
||||
gtk_widget_show (preview);
|
||||
|
||||
/* decide where to put the popup: near the preview i.e. at mousedown coords */
|
||||
gdk_window_get_origin (gtk_widget_get_window (chooser->preview),
|
||||
&x_org, &y_org);
|
||||
|
||||
monitor = pika_widget_get_monitor (GTK_WIDGET (chooser));
|
||||
gdk_monitor_get_workarea (monitor, &workarea);
|
||||
|
||||
x = x_org + x - (chooser->width / 2);
|
||||
y = y_org + y - (chooser->height / 2);
|
||||
|
||||
x = CLAMP (x, workarea.x, workarea.x + workarea.width - chooser->width);
|
||||
y = CLAMP (y, workarea.y, workarea.y + workarea.height - chooser->height);
|
||||
|
||||
gtk_window_move (GTK_WINDOW (chooser->popup), x, y);
|
||||
|
||||
gtk_widget_show (chooser->popup);
|
||||
|
||||
/* Draw popup now. Usual events do not cause a draw. */
|
||||
pika_pattern_select_preview_fill_draw (chooser, PIKA_PREVIEW_AREA (preview));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_pattern_chooser_close_popup (PikaPatternChooser *self)
|
||||
{
|
||||
g_clear_pointer (&self->popup, gtk_widget_destroy);
|
||||
}
|
43
libpika/pikapatternchooser.h
Normal file
43
libpika/pikapatternchooser.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapatternchooser.h
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_PATTERN_CHOOSER_H__
|
||||
#define __PIKA_PATTERN_CHOOSER_H__
|
||||
|
||||
#include <libpika/pikaresourcechooser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_PATTERN_CHOOSER (pika_pattern_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (PikaPatternChooser, pika_pattern_chooser, PIKA, PATTERN_CHOOSER, PikaResourceChooser)
|
||||
|
||||
|
||||
GtkWidget * pika_pattern_chooser_new (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *resource);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_PATTERN_CHOOSER_H__ */
|
273
libpika/pikapropwidgets.c
Normal file
273
libpika/pikapropwidgets.c
Normal file
@ -0,0 +1,273 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapropwidgets.c
|
||||
* Copyright (C) 2023 Jehan
|
||||
*
|
||||
* 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 "libpika/pikaui.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
/*
|
||||
* This is a complement of libpikawidgets/pikapropwidgets.c
|
||||
* These are property functions for types from libpika, such as
|
||||
* [class@Gimp.Resource] or [class@Gimp.Item] subclasses.
|
||||
*/
|
||||
|
||||
|
||||
typedef GtkWidget* (*PikaResourceWidgetCreator) (const gchar *title,
|
||||
const gchar *label,
|
||||
PikaResource *initial_resource);
|
||||
|
||||
|
||||
/* utility function prototypes */
|
||||
|
||||
static GtkWidget * pika_prop_resource_chooser_factory (PikaResourceWidgetCreator widget_creator_func,
|
||||
GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
static gchar * pika_utils_make_canonical_menu_label (const gchar *path);
|
||||
|
||||
|
||||
/**
|
||||
* pika_prop_brush_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Brush] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@Gimp.Brush.Chooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.BrushChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_brush_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
return pika_prop_resource_chooser_factory (pika_brush_chooser_new,
|
||||
config, property_name, chooser_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_prop_font_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Font] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@GimpUi.FontChooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.FontChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_font_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
return pika_prop_resource_chooser_factory (pika_font_chooser_new,
|
||||
config, property_name, chooser_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_prop_gradient_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Gradient] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@GimpUi.GradientChooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.GradientChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_gradient_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
return pika_prop_resource_chooser_factory (pika_gradient_chooser_new,
|
||||
config, property_name, chooser_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_prop_palette_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Palette] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@GimpUi.PaletteChooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.PaletteChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_palette_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
return pika_prop_resource_chooser_factory (pika_palette_chooser_new,
|
||||
config, property_name, chooser_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_prop_pattern_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Pattern] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@GimpUi.PatternChooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.PatternChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_pattern_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
return pika_prop_resource_chooser_factory (pika_pattern_chooser_new,
|
||||
config, property_name, chooser_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_prop_drawable_chooser_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of a [class@Gimp.Drawable] property.
|
||||
* @chooser_title: (nullable): title for the poppable dialog.
|
||||
*
|
||||
* Creates a [class@GimpUi.DrawableChooser] controlled by the specified property.
|
||||
*
|
||||
* Returns: (transfer full): A new [class@GimpUi.DrawableChooser].
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_prop_drawable_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
GParamSpec *param_spec;
|
||||
GtkWidget *prop_chooser;
|
||||
PikaDrawable *initial_drawable = NULL;
|
||||
gchar *title = NULL;
|
||||
const gchar *label;
|
||||
|
||||
param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
|
||||
property_name);
|
||||
|
||||
g_return_val_if_fail (param_spec != NULL, NULL);
|
||||
g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec), G_TYPE_PARAM_OBJECT) &&
|
||||
g_type_is_a (param_spec->value_type, PIKA_TYPE_DRAWABLE), NULL);
|
||||
|
||||
g_object_get (config,
|
||||
property_name, &initial_drawable,
|
||||
NULL);
|
||||
|
||||
label = g_param_spec_get_nick (param_spec);
|
||||
|
||||
if (chooser_title == NULL)
|
||||
{
|
||||
gchar *canonical;
|
||||
|
||||
canonical = pika_utils_make_canonical_menu_label (label);
|
||||
if (g_type_is_a (param_spec->value_type, PIKA_TYPE_LAYER))
|
||||
title = g_strdup_printf (_("Choose layer: %s"), canonical);
|
||||
if (g_type_is_a (param_spec->value_type, PIKA_TYPE_CHANNEL))
|
||||
title = g_strdup_printf (_("Choose channel: %s"), canonical);
|
||||
else
|
||||
title = g_strdup_printf (_("Choose drawable: %s"), canonical);
|
||||
g_free (canonical);
|
||||
}
|
||||
else
|
||||
{
|
||||
title = g_strdup (chooser_title);
|
||||
}
|
||||
|
||||
prop_chooser = pika_drawable_chooser_new (title, label, param_spec->value_type, initial_drawable);
|
||||
g_clear_object (&initial_drawable);
|
||||
g_free (title);
|
||||
|
||||
g_object_bind_property (prop_chooser, "drawable",
|
||||
config, property_name,
|
||||
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
return prop_chooser;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
/* private utility functions */
|
||||
/*******************************/
|
||||
|
||||
static GtkWidget *
|
||||
pika_prop_resource_chooser_factory (PikaResourceWidgetCreator widget_creator_func,
|
||||
GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title)
|
||||
{
|
||||
GParamSpec *param_spec;
|
||||
GtkWidget *prop_chooser;
|
||||
PikaResource *initial_resource;
|
||||
const gchar *label;
|
||||
|
||||
param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
|
||||
property_name);
|
||||
|
||||
g_return_val_if_fail (param_spec != NULL, NULL);
|
||||
g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec), G_TYPE_PARAM_OBJECT) &&
|
||||
g_type_is_a (param_spec->value_type, PIKA_TYPE_RESOURCE), NULL);
|
||||
|
||||
g_object_get (config,
|
||||
property_name, &initial_resource,
|
||||
NULL);
|
||||
|
||||
label = g_param_spec_get_nick (param_spec);
|
||||
|
||||
/* Create the wrapped widget. For example, call pika_font_chooser_new.
|
||||
* When initial_resource is NULL, the widget creator will set it's resource
|
||||
* property from context.
|
||||
*/
|
||||
prop_chooser = widget_creator_func (chooser_title, label, initial_resource);
|
||||
g_clear_object (&initial_resource);
|
||||
|
||||
g_object_bind_property (prop_chooser, "resource",
|
||||
config, property_name,
|
||||
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
return prop_chooser;
|
||||
}
|
||||
|
||||
/* This is a copy of the similarly-named function in app/widgets/pikawidgets-utils.c
|
||||
* I hesitated to put this maybe in libpikawidgets/pikawidgetsutils.h but for
|
||||
* now, let's not. If it's useful to more people, it's always easier to move the
|
||||
* function in rather than deprecating it.
|
||||
*/
|
||||
static gchar *
|
||||
pika_utils_make_canonical_menu_label (const gchar *path)
|
||||
{
|
||||
gchar **split_path;
|
||||
gchar *canon_path;
|
||||
|
||||
/* The first underscore of each path item is a mnemonic. */
|
||||
split_path = g_strsplit (path, "_", 2);
|
||||
canon_path = g_strjoinv ("", split_path);
|
||||
g_strfreev (split_path);
|
||||
|
||||
return canon_path;
|
||||
}
|
58
libpika/pikapropwidgets.h
Normal file
58
libpika/pikapropwidgets.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* pikapropwidgets.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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __PIKA_PROP_WIDGETS_H__
|
||||
#define __PIKA_PROP_WIDGETS_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
/* PikaParamResource */
|
||||
|
||||
GtkWidget * pika_prop_brush_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
GtkWidget * pika_prop_font_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
GtkWidget * pika_prop_gradient_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
GtkWidget * pika_prop_palette_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
GtkWidget * pika_prop_pattern_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
|
||||
GtkWidget * pika_prop_drawable_chooser_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
const gchar *chooser_title);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_PROP_WIDGETS_H__ */
|
622
libpika/pikaresourcechooser.c
Normal file
622
libpika/pikaresourcechooser.c
Normal file
@ -0,0 +1,622 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* 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
|
||||
* Library 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 "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "pika.h"
|
||||
|
||||
#include "pikauitypes.h"
|
||||
#include "pikaresourcechooser.h"
|
||||
#include "pikauimarshal.h"
|
||||
|
||||
#include "libpika-intl.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: pikaresourcechooser
|
||||
* @title: PikaResourceChooser
|
||||
* @short_description: Base class for buttons that popup a resource
|
||||
* selection dialog.
|
||||
*
|
||||
* A button which pops up a resource selection dialog.
|
||||
*
|
||||
* Responsibilities:
|
||||
*
|
||||
* - implementing outer container widget,
|
||||
* - managing clicks and popping up a remote chooser,
|
||||
* - having a resource property,
|
||||
* - signaling when user selects resource
|
||||
* - receiving drag,
|
||||
* - triggering draws of the button interior (by subclass) and draws of remote popup chooser.
|
||||
*
|
||||
* Collaborations:
|
||||
*
|
||||
* - owned by PikaProcedureDialog via PikaPropWidget
|
||||
* - resource property usually bound to a PikaConfig for a PikaPluginProcedure.
|
||||
* - communicates using PikaResourceSelect with remote PikaPDBDialog,
|
||||
* to choose an installed PikaResource owned by core.
|
||||
*
|
||||
* Subclass responsibilities:
|
||||
*
|
||||
* - creating interior widgets
|
||||
* - drawing the interior (a preview of the chosen resource)
|
||||
* - declaring which interior widgets are drag destinations
|
||||
* - declaring which interior widgets are clickable (generate "clicked" signal)
|
||||
* - generate "clicked" (delegating to GtkButton or implementing from mouse events)
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
RESOURCE_SET,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TITLE,
|
||||
PROP_LABEL,
|
||||
PROP_RESOURCE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaResource *resource;
|
||||
gchar *title;
|
||||
gchar *label;
|
||||
gchar *callback;
|
||||
|
||||
GtkWidget *label_widget;
|
||||
} PikaResourceChooserPrivate;
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_resource_chooser_constructed (GObject *object);
|
||||
static void pika_resource_chooser_dispose (GObject *object);
|
||||
static void pika_resource_chooser_finalize (GObject *object);
|
||||
|
||||
static void pika_resource_chooser_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_resource_chooser_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_resource_chooser_clicked (PikaResourceChooser *self);
|
||||
|
||||
static void pika_resource_chooser_callback (PikaResource *resource,
|
||||
gboolean dialog_closing,
|
||||
gpointer user_data);
|
||||
|
||||
static void pika_resource_select_drag_data_received (PikaResourceChooser *self,
|
||||
GdkDragContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
GtkSelectionData *selection,
|
||||
guint info,
|
||||
guint time);
|
||||
|
||||
static void pika_resource_chooser_set_remote_dialog (PikaResourceChooser *self,
|
||||
PikaResource *resource);
|
||||
|
||||
|
||||
static guint resource_button_signals[LAST_SIGNAL] = { 0 };
|
||||
static GParamSpec *resource_button_props[N_PROPS] = { NULL, };
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PikaResourceChooser, pika_resource_chooser, GTK_TYPE_BOX)
|
||||
|
||||
|
||||
static void
|
||||
pika_resource_chooser_class_init (PikaResourceChooserClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_resource_chooser_constructed;
|
||||
object_class->dispose = pika_resource_chooser_dispose;
|
||||
object_class->finalize = pika_resource_chooser_finalize;
|
||||
object_class->set_property = pika_resource_chooser_set_property;
|
||||
object_class->get_property = pika_resource_chooser_get_property;
|
||||
|
||||
klass->resource_set = NULL;
|
||||
|
||||
/**
|
||||
* PikaResourceChooser:title:
|
||||
*
|
||||
* The title to be used for the resource selection popup dialog.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
resource_button_props[PROP_TITLE] =
|
||||
g_param_spec_string ("title",
|
||||
"Title",
|
||||
"The title to be used for the resource selection popup dialog",
|
||||
"Resource Selection",
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* PikaResourceChooser:label:
|
||||
*
|
||||
* Label text with mnemonic.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
resource_button_props[PROP_LABEL] =
|
||||
g_param_spec_string ("label",
|
||||
"Label",
|
||||
"The label to be used next to the button",
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* PikaResourceChooser:resource:
|
||||
*
|
||||
* The currently selected resource.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
resource_button_props[PROP_RESOURCE] =
|
||||
pika_param_spec_resource ("resource",
|
||||
"Resource",
|
||||
"The currently selected resource",
|
||||
TRUE, /* none_ok */
|
||||
PIKA_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class,
|
||||
N_PROPS, resource_button_props);
|
||||
|
||||
/**
|
||||
* PikaResourceChooser::resource-set:
|
||||
* @widget: the object which received the signal.
|
||||
* @resource: the currently selected resource.
|
||||
* @dialog_closing: whether the dialog was closed or not.
|
||||
*
|
||||
* The ::resource-set signal is emitted when the user selects a resource.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
resource_button_signals[RESOURCE_SET] =
|
||||
g_signal_new ("resource-set",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaResourceChooserClass, resource_set),
|
||||
NULL, NULL,
|
||||
_pikaui_marshal_VOID__POINTER_BOOLEAN,
|
||||
G_TYPE_NONE, 2,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_init (PikaResourceChooser *self)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (PIKA_RESOURCE_CHOOSER (self));
|
||||
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self),
|
||||
GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_set_spacing (GTK_BOX (self), 6);
|
||||
|
||||
priv->label_widget = gtk_label_new (NULL);
|
||||
gtk_box_pack_start (GTK_BOX (self), priv->label_widget, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_constructed (GObject *object)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (PIKA_RESOURCE_CHOOSER (object));
|
||||
gtk_label_set_text_with_mnemonic (GTK_LABEL (priv->label_widget), priv->label);
|
||||
gtk_widget_show (GTK_WIDGET (priv->label_widget));
|
||||
|
||||
G_OBJECT_CLASS (pika_resource_chooser_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_dispose (GObject *self)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
PikaResourceChooserClass *klass;
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (PIKA_RESOURCE_CHOOSER (self));
|
||||
klass = PIKA_RESOURCE_CHOOSER_GET_CLASS (self);
|
||||
|
||||
if (priv->callback)
|
||||
{
|
||||
GType resource_type = klass->resource_type;
|
||||
|
||||
if (resource_type == PIKA_TYPE_FONT)
|
||||
pika_fonts_close_popup (priv->callback);
|
||||
else if (resource_type == PIKA_TYPE_GRADIENT)
|
||||
pika_gradients_close_popup (priv->callback);
|
||||
else if (resource_type == PIKA_TYPE_BRUSH)
|
||||
pika_brushes_close_popup (priv->callback);
|
||||
else if (resource_type == PIKA_TYPE_PALETTE)
|
||||
pika_palettes_close_popup (priv->callback);
|
||||
else if (resource_type == PIKA_TYPE_PATTERN)
|
||||
pika_patterns_close_popup (priv->callback);
|
||||
else
|
||||
g_warning ("%s: unhandled resource type", G_STRFUNC);
|
||||
|
||||
pika_plug_in_remove_temp_procedure (pika_get_plug_in (), priv->callback);
|
||||
g_clear_pointer (&priv->callback, g_free);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (pika_resource_chooser_parent_class)->dispose (self);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_finalize (GObject *object)
|
||||
{
|
||||
PikaResourceChooser *self = PIKA_RESOURCE_CHOOSER (object);
|
||||
PikaResourceChooserPrivate *priv = pika_resource_chooser_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->title, g_free);
|
||||
g_clear_pointer (&priv->label, g_free);
|
||||
|
||||
G_OBJECT_CLASS (pika_resource_chooser_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_resource_chooser_set_drag_target:
|
||||
* @chooser: A [class@ResourceChooser]
|
||||
* @drag_region_widget: An interior widget to be a droppable region
|
||||
* and emit "drag-data-received" signal
|
||||
* @drag_target: The drag target to accept
|
||||
*
|
||||
* Called by a subclass init to specialize the instance.
|
||||
*
|
||||
* Subclass knows its interior widget whose region is a drop zone.
|
||||
* Subclass knows what things can be dropped (target.)
|
||||
* Self (super) handles the drop.
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
void
|
||||
pika_resource_chooser_set_drag_target (PikaResourceChooser *chooser,
|
||||
GtkWidget *drag_region_widget,
|
||||
const GtkTargetEntry *drag_target)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_RESOURCE_CHOOSER (chooser));
|
||||
g_return_if_fail (drag_target != NULL);
|
||||
g_return_if_fail (drag_region_widget != NULL);
|
||||
|
||||
gtk_drag_dest_set (drag_region_widget,
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
drag_target, 1, /* Pass array of size 1 */
|
||||
GDK_ACTION_COPY);
|
||||
|
||||
/* connect drag_region_widget's drag_received signal to chooser's callback. */
|
||||
g_signal_connect_swapped (drag_region_widget, "drag-data-received",
|
||||
G_CALLBACK (pika_resource_select_drag_data_received),
|
||||
chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_resource_chooser_set_clickable:
|
||||
* @chooser: A [class@ResourceChooser]
|
||||
* @widget: An interior widget that emits "clicked" signal
|
||||
*
|
||||
* Called by a subclass init to specialize the instance.
|
||||
*
|
||||
* Subclass knows its interior widget whose region when clicked
|
||||
* should popup remote chooser.
|
||||
* Self handles the click event.
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
void
|
||||
pika_resource_chooser_set_clickable (PikaResourceChooser *chooser,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_RESOURCE_CHOOSER (chooser));
|
||||
g_return_if_fail (widget != NULL);
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
/* Require the widget have a signal "clicked", usually a button. */
|
||||
g_signal_connect_swapped (widget, "clicked",
|
||||
G_CALLBACK (pika_resource_chooser_clicked),
|
||||
chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_resource_chooser_get_resource:
|
||||
* @chooser: A #PikaResourceChooser
|
||||
*
|
||||
* Gets the currently selected resource.
|
||||
*
|
||||
* Returns: (transfer none): an internal copy of the resource which must not be freed.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
PikaResource *
|
||||
pika_resource_chooser_get_resource (PikaResourceChooser *chooser)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_RESOURCE_CHOOSER (chooser), NULL);
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (chooser);
|
||||
|
||||
return priv->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_resource_chooser_set_resource:
|
||||
* @chooser: A #PikaResourceChooser
|
||||
* @resource: Resource to set.
|
||||
*
|
||||
* Sets the currently selected resource.
|
||||
* This will select the resource in both the button and any chooser popup.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
void
|
||||
pika_resource_chooser_set_resource (PikaResourceChooser *chooser,
|
||||
PikaResource *resource)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
|
||||
g_return_if_fail (PIKA_IS_RESOURCE_CHOOSER (chooser));
|
||||
g_return_if_fail (resource != NULL);
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (chooser);
|
||||
|
||||
if (priv->callback)
|
||||
{
|
||||
/* A popup chooser dialog is already shown.
|
||||
* Call its setter to change the selection there
|
||||
* (since all views of the resource must be consistent.)
|
||||
* That will call back, which will change our own view of the resource.
|
||||
*/
|
||||
pika_resource_chooser_set_remote_dialog (chooser, resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call our own setter. */
|
||||
pika_resource_chooser_callback (resource, FALSE, chooser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_resource_chooser_get_label:
|
||||
* @widget: A [class@ResourceChooser].
|
||||
*
|
||||
* Returns the label widget.
|
||||
*
|
||||
* Returns: (transfer none): the [class@Gtk.Widget] showing the label text.
|
||||
* Since: 3.0
|
||||
*/
|
||||
GtkWidget *
|
||||
pika_resource_chooser_get_label (PikaResourceChooser *widget)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_RESOURCE_CHOOSER (widget), NULL);
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (widget);
|
||||
return priv->label_widget;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_resource_chooser_set_remote_dialog (PikaResourceChooser *self,
|
||||
PikaResource *resource)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv;
|
||||
PikaResourceChooserClass *klass;
|
||||
|
||||
g_return_if_fail (PIKA_IS_RESOURCE_CHOOSER (self));
|
||||
g_return_if_fail (resource != NULL);
|
||||
|
||||
priv = pika_resource_chooser_get_instance_private (self);
|
||||
klass = PIKA_RESOURCE_CHOOSER_GET_CLASS (self);
|
||||
|
||||
g_return_if_fail (klass->resource_type != G_TYPE_INVALID);
|
||||
g_return_if_fail (klass->resource_type == G_TYPE_FROM_INSTANCE (resource));
|
||||
|
||||
pika_resource_select_set (priv->callback, resource);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *gvalue,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaResourceChooser *self = PIKA_RESOURCE_CHOOSER (object);
|
||||
PikaResourceChooserPrivate *priv = pika_resource_chooser_get_instance_private (self);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TITLE:
|
||||
priv->title = g_value_dup_string (gvalue);
|
||||
break;
|
||||
|
||||
case PROP_LABEL:
|
||||
priv->label = g_value_dup_string (gvalue);
|
||||
break;
|
||||
|
||||
case PROP_RESOURCE:
|
||||
priv->resource = g_value_get_object (gvalue);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaResourceChooser *self = PIKA_RESOURCE_CHOOSER (object);
|
||||
PikaResourceChooserPrivate *priv = pika_resource_chooser_get_instance_private (self);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, priv->title);
|
||||
break;
|
||||
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, priv->label);
|
||||
break;
|
||||
|
||||
case PROP_RESOURCE:
|
||||
g_value_set_object (value, priv->resource);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* A callback from the remote resource select popup.
|
||||
* When user chooses a resource.
|
||||
* Via a temporary PDB procedure.
|
||||
*
|
||||
* Set self's model (priv->resource)
|
||||
* Notify any parent widget subscribed on the "resource" property
|
||||
* typically a prop widget.
|
||||
* Update the view, since model changed.
|
||||
*/
|
||||
static void
|
||||
pika_resource_chooser_callback (PikaResource *resource,
|
||||
gboolean dialog_closing,
|
||||
gpointer user_data)
|
||||
{
|
||||
PikaResourceChooser *self = PIKA_RESOURCE_CHOOSER (user_data);
|
||||
PikaResourceChooserPrivate *priv = pika_resource_chooser_get_instance_private (self);
|
||||
|
||||
priv->resource = resource;
|
||||
|
||||
PIKA_RESOURCE_CHOOSER_GET_CLASS (self)->draw_interior (self);
|
||||
|
||||
if (dialog_closing)
|
||||
g_clear_pointer (&priv->callback, g_free);
|
||||
|
||||
g_signal_emit (self, resource_button_signals[RESOURCE_SET], 0, resource, dialog_closing);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), resource_button_props[PROP_RESOURCE]);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_resource_chooser_clicked (PikaResourceChooser *self)
|
||||
{
|
||||
PikaResourceChooserPrivate *priv = pika_resource_chooser_get_instance_private (self);
|
||||
PikaResourceChooserClass *klass = PIKA_RESOURCE_CHOOSER_GET_CLASS (self);
|
||||
|
||||
if (priv->callback)
|
||||
{
|
||||
/* Popup already created. Calling setter raises the popup. */
|
||||
pika_resource_chooser_set_remote_dialog (self, priv->resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
|
||||
GBytes *handle = NULL;
|
||||
|
||||
if (PIKA_IS_DIALOG (toplevel))
|
||||
handle = pika_dialog_get_native_handle (PIKA_DIALOG (toplevel));
|
||||
|
||||
priv->callback = g_strdup (pika_resource_select_new (priv->title,
|
||||
handle,
|
||||
priv->resource,
|
||||
klass->resource_type,
|
||||
pika_resource_chooser_callback,
|
||||
self,
|
||||
NULL));
|
||||
pika_resource_chooser_set_remote_dialog (self, priv->resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Drag methods. */
|
||||
|
||||
static void
|
||||
pika_resource_select_drag_data_received (PikaResourceChooser *self,
|
||||
GdkDragContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
GtkSelectionData *selection,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
gint length = gtk_selection_data_get_length (selection);
|
||||
gchar *str;
|
||||
|
||||
PikaResourceChooserClass *klass;
|
||||
|
||||
klass = PIKA_RESOURCE_CHOOSER_GET_CLASS (self);
|
||||
/* Require class resource_type was initialized. */
|
||||
g_assert (klass->resource_type != 0);
|
||||
|
||||
/* Drag data is a string that is the ID of the resource. */
|
||||
|
||||
if (gtk_selection_data_get_format (selection) != 8 || length < 1)
|
||||
{
|
||||
g_warning ("%s: received invalid resource data", G_STRFUNC);
|
||||
return;
|
||||
}
|
||||
|
||||
str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection),
|
||||
length);
|
||||
|
||||
if (g_utf8_validate (str, -1, NULL))
|
||||
{
|
||||
gint pid;
|
||||
gpointer unused;
|
||||
gint name_offset = 0;
|
||||
|
||||
if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 &&
|
||||
pid == pika_getpid () && name_offset > 0)
|
||||
{
|
||||
gchar *name = str + name_offset;
|
||||
PikaResource *resource;
|
||||
|
||||
resource = pika_resource_get_by_name (klass->resource_type, name);
|
||||
pika_resource_chooser_set_resource (self, resource);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (str);
|
||||
}
|
65
libpika/pikaresourcechooser.h
Normal file
65
libpika/pikaresourcechooser.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* LIBPIKA - The PIKA Library
|
||||
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||
*
|
||||
* 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 (__PIKA_UI_H_INSIDE__) && !defined (PIKA_COMPILATION)
|
||||
#error "Only <libpika/pikaui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __PIKA_RESOURCE_CHOOSER_H__
|
||||
#define __PIKA_RESOURCE_CHOOSER_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIKA_TYPE_RESOURCE_CHOOSER (pika_resource_chooser_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (PikaResourceChooser, pika_resource_chooser, PIKA, RESOURCE_CHOOSER, GtkBox)
|
||||
|
||||
struct _PikaResourceChooserClass
|
||||
{
|
||||
GtkBoxClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* resource_set) (PikaResourceChooser *chooser,
|
||||
PikaResource *resource,
|
||||
gboolean dialog_closing);
|
||||
|
||||
/* Abstract methods and class variables */
|
||||
void (*draw_interior) (PikaResourceChooser *chooser);
|
||||
|
||||
GType resource_type;
|
||||
|
||||
/* Padding for future expansion */
|
||||
gpointer padding[8];
|
||||
};
|
||||
|
||||
PikaResource * pika_resource_chooser_get_resource (PikaResourceChooser *chooser);
|
||||
void pika_resource_chooser_set_resource (PikaResourceChooser *chooser,
|
||||
PikaResource *resource);
|
||||
GtkWidget * pika_resource_chooser_get_label (PikaResourceChooser *widget);
|
||||
|
||||
|
||||
/* API from below, used by subclasses e.g. PikaBrushChooser */
|
||||
|
||||
void pika_resource_chooser_set_drag_target (PikaResourceChooser *chooser,
|
||||
GtkWidget *drag_region_widget,
|
||||
const GtkTargetEntry *drag_target);
|
||||
void pika_resource_chooser_set_clickable (PikaResourceChooser *chooser,
|
||||
GtkWidget *widget);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIKA_RESOURCE_CHOOSER_H__ */
|
Reference in New Issue
Block a user