Updated new files from upstream

This commit is contained in:
Cassowary 2023-10-30 15:56:43 -07:00
parent 3bbdd873ef
commit 852cbfc1fb
44 changed files with 7719 additions and 0 deletions

View File

@ -0,0 +1,243 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. 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 <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libpikabase/pikabase.h"
#include "pdb-types.h"
#include "core/pika.h"
#include "core/pikadatafactory.h"
#include "core/pikadrawable.h"
#include "core/pikaparamspecs.h"
#include "pikapdb.h"
#include "pikaprocedure.h"
#include "internal-procs.h"
static PikaValueArray *
drawables_popup_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
const gchar *callback;
const gchar *popup_title;
const gchar *drawable_type;
PikaDrawable *initial_drawable;
GBytes *parent_window;
callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1));
drawable_type = g_value_get_string (pika_value_array_index (args, 2));
initial_drawable = g_value_get_object (pika_value_array_index (args, 3));
parent_window = g_value_get_boxed (pika_value_array_index (args, 4));
if (success)
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_new (pika, context, progress,
g_type_from_name (drawable_type),
parent_window, popup_title, callback,
PIKA_OBJECT (initial_drawable),
NULL))
success = FALSE;
}
return pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
}
static PikaValueArray *
drawables_close_popup_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
const gchar *callback;
callback = g_value_get_string (pika_value_array_index (args, 0));
if (success)
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_close (pika, PIKA_TYPE_DRAWABLE, callback))
success = FALSE;
}
return pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
}
static PikaValueArray *
drawables_set_popup_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
const gchar *callback;
PikaDrawable *drawable;
callback = g_value_get_string (pika_value_array_index (args, 0));
drawable = g_value_get_object (pika_value_array_index (args, 1));
if (success)
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_set (pika, PIKA_TYPE_DRAWABLE, callback, PIKA_OBJECT (drawable), NULL))
success = FALSE;
}
return pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
}
void
register_drawable_select_procs (PikaPDB *pdb)
{
PikaProcedure *procedure;
/*
* pika-drawables-popup
*/
procedure = pika_procedure_new (drawables_popup_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-drawables-popup");
pika_procedure_set_static_help (procedure,
"Invokes the drawable selection dialog.",
"Opens a dialog letting a user choose an drawable.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan",
"Jehan",
"2023");
pika_procedure_add_argument (procedure,
pika_param_spec_string ("callback",
"callback",
"The callback PDB proc to call when user chooses an drawable",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("popup-title",
"popup title",
"Title of the drawable selection dialog",
FALSE, FALSE, FALSE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("drawable-type",
"drawable type",
"The name of the PIKA_TYPE_DRAWABLE subtype",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_drawable ("initial-drawable",
"initial drawable",
"The drawable to set as the initial choice",
FALSE,
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/*
* pika-drawables-close-popup
*/
procedure = pika_procedure_new (drawables_close_popup_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-drawables-close-popup");
pika_procedure_set_static_help (procedure,
"Close the drawable selection dialog.",
"Closes an open drawable selection dialog.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan",
"Jehan",
"2023");
pika_procedure_add_argument (procedure,
pika_param_spec_string ("callback",
"callback",
"The name of the callback registered for this pop-up",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/*
* pika-drawables-set-popup
*/
procedure = pika_procedure_new (drawables_set_popup_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-drawables-set-popup");
pika_procedure_set_static_help (procedure,
"Sets the selected drawable in a drawable selection dialog.",
"Sets the selected drawable in a drawable selection dialog.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan",
"Jehan",
"2023");
pika_procedure_add_argument (procedure,
pika_param_spec_string ("callback",
"callback",
"The name of the callback registered for this pop-up",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_drawable ("drawable",
"drawable",
"The drawable to set as selected",
FALSE,
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
}

View File

@ -0,0 +1,589 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikapickablechooser.c
* Copyright (C) 2023 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "widgets-types.h"
#include "core/pika.h"
#include "core/pikachannel.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikapickable.h"
#include "core/pikaviewable.h"
#include "pikacontainertreeview.h"
#include "pikacontainerview.h"
#include "pikapickablechooser.h"
#include "pikaviewrenderer.h"
#include "pika-intl.h"
enum
{
ACTIVATE,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_CONTEXT,
PROP_PICKABLE_TYPE,
PROP_PICKABLE,
PROP_VIEW_SIZE,
PROP_VIEW_BORDER_WIDTH
};
struct _PikaPickableChooserPrivate
{
GType pickable_type;
PikaPickable *pickable;
PikaContext *context;
gint view_size;
gint view_border_width;
GtkWidget *image_view;
GtkWidget *layer_view;
GtkWidget *channel_view;
GtkWidget *layer_label;
};
static void pika_pickable_chooser_constructed (GObject *object);
static void pika_pickable_chooser_finalize (GObject *object);
static void pika_pickable_chooser_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_pickable_chooser_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_pickable_chooser_image_changed (PikaContext *context,
PikaImage *image,
PikaPickableChooser *chooser);
static void pika_pickable_chooser_item_activate (PikaContainerView *view,
PikaPickable *pickable,
gpointer unused,
PikaPickableChooser *chooser);
static void pika_pickable_chooser_items_selected (PikaContainerView *view,
GList *items,
GList *paths,
PikaPickableChooser *chooser);
G_DEFINE_TYPE_WITH_PRIVATE (PikaPickableChooser, pika_pickable_chooser, GTK_TYPE_FRAME)
#define parent_class pika_pickable_chooser_parent_class
static guint signals[LAST_SIGNAL];
static void
pika_pickable_chooser_class_init (PikaPickableChooserClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_pickable_chooser_constructed;
object_class->finalize = pika_pickable_chooser_finalize;
object_class->get_property = pika_pickable_chooser_get_property;
object_class->set_property = pika_pickable_chooser_set_property;
/**
* PikaPickableChooser::activate:
* @chooser:
*
* Emitted when a pickable is activated, which is mostly forwarding when
* "activate-item" signal is emitted from any of either the image, layer or
* channel view. E.g. this happens when one double-click on one of the
* pickables.
*/
signals[ACTIVATE] =
g_signal_new ("activate",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaPickableChooserClass, activate),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_OBJECT);
g_object_class_install_property (object_class, PROP_CONTEXT,
g_param_spec_object ("context",
NULL, NULL,
PIKA_TYPE_CONTEXT,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_PICKABLE_TYPE,
g_param_spec_gtype ("pickable-type",
NULL, NULL,
PIKA_TYPE_PICKABLE,
PIKA_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_PICKABLE,
g_param_spec_object ("pickable",
NULL, NULL,
PIKA_TYPE_PICKABLE,
PIKA_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY));
g_object_class_install_property (object_class, PROP_VIEW_SIZE,
g_param_spec_int ("view-size",
NULL, NULL,
1, PIKA_VIEWABLE_MAX_PREVIEW_SIZE,
PIKA_VIEW_SIZE_MEDIUM,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_VIEW_BORDER_WIDTH,
g_param_spec_int ("view-border-width",
NULL, NULL,
0,
PIKA_VIEW_MAX_BORDER_WIDTH,
1,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
pika_pickable_chooser_init (PikaPickableChooser *chooser)
{
chooser->priv = pika_pickable_chooser_get_instance_private (chooser);
chooser->priv->view_size = PIKA_VIEW_SIZE_SMALL;
chooser->priv->view_border_width = 1;
chooser->priv->layer_view = NULL;
chooser->priv->channel_view = NULL;
}
static void
pika_pickable_chooser_constructed (GObject *object)
{
PikaPickableChooser *chooser = PIKA_PICKABLE_CHOOSER (object);
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *notebook;
PikaImage *image;
G_OBJECT_CLASS (parent_class)->constructed (object);
pika_assert (PIKA_IS_CONTEXT (chooser->priv->context));
gtk_frame_set_shadow_type (GTK_FRAME (chooser), GTK_SHADOW_OUT);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
gtk_container_add (GTK_CONTAINER (chooser), hbox);
gtk_widget_show (hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
label = gtk_label_new (_("Images"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
chooser->priv->image_view =
pika_container_tree_view_new (chooser->priv->context->pika->images,
chooser->priv->context,
chooser->priv->view_size,
chooser->priv->view_border_width);
pika_container_box_set_size_request (PIKA_CONTAINER_BOX (chooser->priv->image_view),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width));
gtk_box_pack_start (GTK_BOX (vbox), chooser->priv->image_view, TRUE, TRUE, 0);
gtk_widget_show (chooser->priv->image_view);
g_signal_connect_object (chooser->priv->image_view, "activate-item",
G_CALLBACK (pika_pickable_chooser_item_activate),
G_OBJECT (chooser), 0);
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
chooser->priv->layer_label = label =
gtk_label_new (_("Select an image in the left pane"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
notebook = gtk_notebook_new ();
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
gtk_widget_show (notebook);
if (g_type_is_a (PIKA_TYPE_LAYER, chooser->priv->pickable_type))
{
chooser->priv->layer_view =
pika_container_tree_view_new (NULL,
chooser->priv->context,
chooser->priv->view_size,
chooser->priv->view_border_width);
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (PIKA_CONTAINER_TREE_VIEW (chooser->priv->layer_view)->view),
TRUE);
pika_container_box_set_size_request (PIKA_CONTAINER_BOX (chooser->priv->layer_view),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
chooser->priv->layer_view,
gtk_label_new (_("Layers")));
gtk_widget_show (chooser->priv->layer_view);
g_signal_connect_object (chooser->priv->layer_view, "activate-item",
G_CALLBACK (pika_pickable_chooser_item_activate),
G_OBJECT (chooser), 0);
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
if (g_type_is_a (PIKA_TYPE_CHANNEL, chooser->priv->pickable_type))
{
chooser->priv->channel_view =
pika_container_tree_view_new (NULL,
chooser->priv->context,
chooser->priv->view_size,
chooser->priv->view_border_width);
pika_container_box_set_size_request (PIKA_CONTAINER_BOX (chooser->priv->channel_view),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width),
4 * (chooser->priv->view_size +
2 * chooser->priv->view_border_width));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
chooser->priv->channel_view,
gtk_label_new (_("Channels")));
gtk_widget_show (chooser->priv->channel_view);
g_signal_connect_object (chooser->priv->channel_view, "activate-item",
G_CALLBACK (pika_pickable_chooser_item_activate),
G_OBJECT (chooser), 0);
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
g_signal_connect_object (chooser->priv->context, "image-changed",
G_CALLBACK (pika_pickable_chooser_image_changed),
G_OBJECT (chooser), 0);
image = pika_context_get_image (chooser->priv->context);
pika_pickable_chooser_image_changed (chooser->priv->context, image, chooser);
}
static void
pika_pickable_chooser_finalize (GObject *object)
{
PikaPickableChooser *chooser = PIKA_PICKABLE_CHOOSER (object);
g_clear_object (&chooser->priv->pickable);
g_clear_object (&chooser->priv->context);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_pickable_chooser_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaPickableChooser *chooser = PIKA_PICKABLE_CHOOSER (object);
switch (property_id)
{
case PROP_CONTEXT:
if (chooser->priv->context)
g_object_unref (chooser->priv->context);
chooser->priv->context = g_value_dup_object (value);
break;
case PROP_VIEW_SIZE:
chooser->priv->view_size = g_value_get_int (value);
break;
case PROP_VIEW_BORDER_WIDTH:
chooser->priv->view_border_width = g_value_get_int (value);
break;
case PROP_PICKABLE_TYPE:
g_return_if_fail (g_value_get_gtype (value) == PIKA_TYPE_LAYER ||
g_value_get_gtype (value) == PIKA_TYPE_CHANNEL ||
g_value_get_gtype (value) == PIKA_TYPE_DRAWABLE ||
g_value_get_gtype (value) == PIKA_TYPE_IMAGE ||
g_value_get_gtype (value) == PIKA_TYPE_PICKABLE);
chooser->priv->pickable_type = g_value_get_gtype (value);
break;
case PROP_PICKABLE:
g_return_if_fail (g_value_get_object (value) == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (g_value_get_object (value)),
chooser->priv->pickable_type));
pika_pickable_chooser_set_pickable (chooser, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_pickable_chooser_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaPickableChooser *chooser = PIKA_PICKABLE_CHOOSER (object);
switch (property_id)
{
case PROP_CONTEXT:
g_value_set_object (value, chooser->priv->context);
break;
case PROP_PICKABLE_TYPE:
g_value_set_gtype (value, chooser->priv->pickable_type);
break;
case PROP_PICKABLE:
g_value_set_object (value, chooser->priv->pickable);
break;
case PROP_VIEW_SIZE:
g_value_set_int (value, chooser->priv->view_size);
break;
case PROP_VIEW_BORDER_WIDTH:
g_value_set_int (value, chooser->priv->view_border_width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_pickable_chooser_new (PikaContext *context,
GType pickable_type,
gint view_size,
gint view_border_width)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (view_size > 0 &&
view_size <= PIKA_VIEWABLE_MAX_POPUP_SIZE, NULL);
g_return_val_if_fail (view_border_width >= 0 &&
view_border_width <= PIKA_VIEW_MAX_BORDER_WIDTH,
NULL);
return g_object_new (PIKA_TYPE_PICKABLE_CHOOSER,
"context", context,
"pickable-type", pickable_type,
"view-size", view_size,
"view-border-width", view_border_width,
NULL);
}
PikaPickable *
pika_pickable_chooser_get_pickable (PikaPickableChooser *chooser)
{
g_return_val_if_fail (PIKA_IS_PICKABLE_CHOOSER (chooser), NULL);
return chooser->priv->pickable;
}
void
pika_pickable_chooser_set_pickable (PikaPickableChooser *chooser,
PikaPickable *pickable)
{
if (! gtk_widget_in_destruction (GTK_WIDGET (chooser)))
{
g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
if (chooser->priv->layer_view != NULL)
g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
else
g_return_if_fail (! PIKA_IS_LAYER (pickable));
if (chooser->priv->channel_view != NULL)
g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
else
g_return_if_fail (! PIKA_IS_CHANNEL (pickable));
if (PIKA_IS_IMAGE (pickable))
{
pika_container_view_select_item (PIKA_CONTAINER_VIEW (chooser->priv->image_view),
PIKA_VIEWABLE (pickable));
pika_context_set_image (chooser->priv->context, PIKA_IMAGE (pickable));
}
else if (PIKA_IS_LAYER (pickable))
{
pika_context_set_image (chooser->priv->context, pika_item_get_image (PIKA_ITEM (pickable)));
pika_container_view_select_item (PIKA_CONTAINER_VIEW (chooser->priv->layer_view),
PIKA_VIEWABLE (pickable));
}
else if (PIKA_IS_CHANNEL (pickable))
{
pika_context_set_image (chooser->priv->context, pika_item_get_image (PIKA_ITEM (pickable)));
pika_container_view_select_item (PIKA_CONTAINER_VIEW (chooser->priv->channel_view),
PIKA_VIEWABLE (pickable));
}
else
{
g_return_if_fail (pickable == NULL);
pika_container_view_select_item (PIKA_CONTAINER_VIEW (chooser->priv->image_view), NULL);
pika_context_set_image (chooser->priv->context, NULL);
}
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
if (chooser->priv->layer_view != NULL)
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
if (chooser->priv->channel_view != NULL)
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
if (pickable != chooser->priv->pickable)
{
g_clear_object (&chooser->priv->pickable);
chooser->priv->pickable = (pickable != NULL ? g_object_ref (pickable) : NULL);
g_object_notify (G_OBJECT (chooser), "pickable");
}
}
/* private functions */
static void
pika_pickable_chooser_image_changed (PikaContext *context,
PikaImage *image,
PikaPickableChooser *chooser)
{
PikaContainer *layers = NULL;
PikaContainer *channels = NULL;
if (image)
{
gchar *desc;
layers = pika_image_get_layers (image);
channels = pika_image_get_channels (image);
desc = pika_viewable_get_description (PIKA_VIEWABLE (image), NULL);
gtk_label_set_text (GTK_LABEL (chooser->priv->layer_label), desc);
g_free (desc);
}
else
{
gtk_label_set_text (GTK_LABEL (chooser->priv->layer_label),
_("Select an image in the left pane"));
}
g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
if (chooser->priv->layer_view != NULL)
{
g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
pika_container_view_set_container (PIKA_CONTAINER_VIEW (chooser->priv->layer_view),
layers);
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
if (chooser->priv->channel_view != NULL)
{
g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
G_CALLBACK (pika_pickable_chooser_items_selected),
chooser);
pika_container_view_set_container (PIKA_CONTAINER_VIEW (chooser->priv->channel_view),
channels);
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (pika_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
static void
pika_pickable_chooser_item_activate (PikaContainerView *view,
PikaPickable *pickable,
gpointer unused,
PikaPickableChooser *chooser)
{
g_signal_emit (chooser, signals[ACTIVATE], 0, pickable);
}
static void
pika_pickable_chooser_items_selected (PikaContainerView *view,
GList *items,
GList *paths,
PikaPickableChooser *chooser)
{
PikaPickable *pickable = NULL;
g_return_if_fail (g_list_length (items) <= 1);
if (items != NULL)
pickable = items->data;
pika_pickable_chooser_set_pickable (chooser, pickable);
}

View File

@ -0,0 +1,70 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikapickablechooser.h
* Copyright (C) 2023 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_PICKABLE_CHOOSER_H__
#define __PIKA_PICKABLE_CHOOSER_H__
#define PIKA_TYPE_PICKABLE_CHOOSER (pika_pickable_chooser_get_type ())
#define PIKA_PICKABLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PICKABLE_CHOOSER, PikaPickableChooser))
#define PIKA_PICKABLE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PICKABLE_CHOOSER, PikaPickableChooserClass))
#define PIKA_IS_PICKABLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PICKABLE_CHOOSER))
#define PIKA_IS_PICKABLE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PICKABLE_CHOOSER))
#define PIKA_PICKABLE_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_PICKABLE_CHOOSER, PikaPickableChooserClass))
typedef struct _PikaPickableChooserPrivate PikaPickableChooserPrivate;
typedef struct _PikaPickableChooserClass PikaPickableChooserClass;
struct _PikaPickableChooser
{
GtkFrame parent_instance;
PikaPickableChooserPrivate *priv;
};
struct _PikaPickableChooserClass
{
GtkFrameClass parent_instance;
/* Signals. */
void (* activate) (PikaPickableChooser *view,
PikaPickable *pickable);
};
GType pika_pickable_chooser_get_type (void) G_GNUC_CONST;
GtkWidget * pika_pickable_chooser_new (PikaContext *context,
GType pickable_type,
gint view_size,
gint view_border_width);
PikaPickable * pika_pickable_chooser_get_pickable (PikaPickableChooser *chooser);
void pika_pickable_chooser_set_pickable (PikaPickableChooser *chooser,
PikaPickable *pickable);
#endif /* __PIKA_PICKABLE_CHOOSER_H__ */

View File

@ -0,0 +1,164 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikapickableselect.c
* Copyright (C) 2023 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "widgets-types.h"
#include "gegl/pika-babl-compat.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikadrawable.h"
#include "core/pikapickable.h"
#include "core/pikaparamspecs.h"
#include "core/pikatempbuf.h"
#include "pdb/pikapdb.h"
#include "pikapickablechooser.h"
#include "pikapickableselect.h"
#include "pikacontainerbox.h"
#include "pika-intl.h"
static void pika_pickable_select_constructed (GObject *object);
static PikaValueArray * pika_pickable_select_run_callback (PikaPdbDialog *dialog,
PikaObject *object,
gboolean closing,
GError **error);
static PikaObject * pika_pickable_select_get_object (PikaPdbDialog *dialog);
static void pika_pickable_select_set_object (PikaPdbDialog *dialog,
PikaObject *object);
static void pika_pickable_select_activate (PikaPickableSelect *select);
static void pika_pickable_select_notify_pickable (PikaPickableSelect *select);
G_DEFINE_TYPE (PikaPickableSelect, pika_pickable_select, PIKA_TYPE_PDB_DIALOG)
#define parent_class pika_pickable_select_parent_class
static void
pika_pickable_select_class_init (PikaPickableSelectClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaPdbDialogClass *pdb_class = PIKA_PDB_DIALOG_CLASS (klass);
object_class->constructed = pika_pickable_select_constructed;
pdb_class->run_callback = pika_pickable_select_run_callback;
pdb_class->get_object = pika_pickable_select_get_object;
pdb_class->set_object = pika_pickable_select_set_object;
}
static void
pika_pickable_select_init (PikaPickableSelect *select)
{
}
static void
pika_pickable_select_constructed (GObject *object)
{
PikaPdbDialog *dialog = PIKA_PDB_DIALOG (object);
PikaPickableSelect *select = PIKA_PICKABLE_SELECT (object);
GtkWidget *content_area;
G_OBJECT_CLASS (parent_class)->constructed (object);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
select->chooser = pika_pickable_chooser_new (dialog->context, dialog->select_type,
PIKA_VIEW_SIZE_LARGE, 1);
pika_pickable_chooser_set_pickable (PIKA_PICKABLE_CHOOSER (select->chooser),
PIKA_PICKABLE (dialog->initial_object));
g_signal_connect_swapped (select->chooser, "notify::pickable",
G_CALLBACK (pika_pickable_select_notify_pickable),
select);
g_signal_connect_swapped (select->chooser, "activate",
G_CALLBACK (pika_pickable_select_activate),
select);
gtk_box_pack_start (GTK_BOX (content_area), select->chooser, TRUE, TRUE, 0);
gtk_widget_show (select->chooser);
}
static PikaValueArray *
pika_pickable_select_run_callback (PikaPdbDialog *dialog,
PikaObject *object,
gboolean closing,
GError **error)
{
PikaPickable *pickable = PIKA_PICKABLE (object);
PikaValueArray *return_vals;
return_vals =
pika_pdb_execute_procedure_by_name (dialog->pdb,
dialog->caller_context,
NULL, error,
dialog->callback_name,
PIKA_TYPE_DRAWABLE, pickable,
G_TYPE_BOOLEAN, closing,
G_TYPE_NONE);
return return_vals;
}
static PikaObject *
pika_pickable_select_get_object (PikaPdbDialog *dialog)
{
PikaPickableSelect *select = PIKA_PICKABLE_SELECT (dialog);
return (PikaObject *) pika_pickable_chooser_get_pickable (PIKA_PICKABLE_CHOOSER (select->chooser));
}
static void
pika_pickable_select_set_object (PikaPdbDialog *dialog,
PikaObject *object)
{
PikaPickableSelect *select = PIKA_PICKABLE_SELECT (dialog);
pika_pickable_chooser_set_pickable (PIKA_PICKABLE_CHOOSER (select->chooser), PIKA_PICKABLE (object));
}
static void
pika_pickable_select_activate (PikaPickableSelect *select)
{
pika_pdb_dialog_run_callback ((PikaPdbDialog **) &select, TRUE);
gtk_widget_destroy (GTK_WIDGET (select));
}
static void
pika_pickable_select_notify_pickable (PikaPickableSelect *select)
{
pika_pdb_dialog_run_callback ((PikaPdbDialog **) &select, FALSE);
}

View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikapickableselect.h
* Copyright (C) 2023 Jehan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_PICKABLE_SELECT_H__
#define __PIKA_PICKABLE_SELECT_H__
#include "pikapdbdialog.h"
G_BEGIN_DECLS
#define PIKA_TYPE_PICKABLE_SELECT (pika_pickable_select_get_type ())
#define PIKA_PICKABLE_SELECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PICKABLE_SELECT, PikaPickableSelect))
#define PIKA_PICKABLE_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PICKABLE_SELECT, PikaPickableSelectClass))
#define PIKA_IS_PICKABLE_SELECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PICKABLE_SELECT))
#define PIKA_IS_PICKABLE_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PICKABLE_SELECT))
#define PIKA_PICKABLE_SELECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_PICKABLE_SELECT, PikaPickableSelectClass))
typedef struct _PikaPickableSelectClass PikaPickableSelectClass;
struct _PikaPickableSelect
{
PikaPdbDialog parent_instance;
GtkWidget *chooser;
};
struct _PikaPickableSelectClass
{
PikaPdbDialogClass parent_class;
};
GType pika_pickable_select_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __PIKA_PICKABLE_SELECT_H__ */

View File

@ -0,0 +1,24 @@
diff -urN pika-2.10.30-orig/build/windows/pika-plug-ins.rc.in pika-2.10.30/build/windows/pika-plug-ins.rc.in
--- pika-2.10.30-orig/build/windows/pika-plug-ins.rc.in 2021-12-20 04:48:33.000000000 +0800
+++ pika-2.10.30/build/windows/pika-plug-ins.rc.in 2022-01-05 20:54:00.814712400 +0800
@@ -63,5 +63,5 @@
END
#include "winuser.h"
-1 ICON QUOTE(TOP_SRCDIR) "/build/windows/plug-ins.ico"
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST QUOTE(TOP_SRCDIR) "/build/windows/pika.manifest"
+1 ICON "./build/windows/plug-ins.ico"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "./build/windows/pika.manifest"
diff -urN pika-2.10.30-orig/build/windows/pika.rc.in pika-2.10.30/build/windows/pika.rc.in
--- pika-2.10.30-orig/build/windows/pika.rc.in 2021-12-20 04:48:33.000000000 +0800
+++ pika-2.10.30/build/windows/pika.rc.in 2022-01-05 20:52:37.741960900 +0800
@@ -64,6 +64,6 @@
END
#include "winuser.h"
-1 ICON QUOTE(TOP_SRCDIR) "/build/windows/wilber.ico"
-2 ICON QUOTE(TOP_SRCDIR) "/build/windows/fileicon.ico"
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST QUOTE(TOP_SRCDIR) "/build/windows/pika.manifest"
+1 ICON "./build/windows/wilber.ico"
+2 ICON "./build/windows/fileicon.ico"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "./build/windows/pika.manifest"

View File

@ -0,0 +1,600 @@
diff -bur pika-2.99.12-c/app/meson.build pika-2.99.12/app/meson.build
--- pika-2.99.12-c/app/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/app/meson.build 2022-08-26 11:05:18.272156800 -0600
@@ -151,9 +151,9 @@
console_rc_file = windows.compile_resources(
pika_app_console_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(console_rc_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(console_rc_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(console_rc_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(console_rc_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
@@ -169,9 +169,9 @@
gui_rc_file = windows.compile_resources(
pika_app_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(gui_rc_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(gui_rc_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(gui_rc_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(gui_rc_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/extensions/goat-exercises/meson.build pika-2.99.12/extensions/goat-exercises/meson.build
--- pika-2.99.12-c/extensions/goat-exercises/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/extensions/goat-exercises/meson.build 2022-08-26 11:05:21.367326100 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plug_in_name + '-c.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plug_in_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plug_in_name + '-c.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plug_in_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/common/meson.build pika-2.99.12/plug-ins/common/meson.build
--- pika-2.99.12-c/plug-ins/common/meson.build 2022-08-26 10:58:35.055807300 -0600
+++ pika-2.99.12/plug-ins/common/meson.build 2022-08-26 11:05:18.323293100 -0600
@@ -178,9 +178,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-bmp/meson.build pika-2.99.12/plug-ins/file-bmp/meson.build
--- pika-2.99.12-c/plug-ins/file-bmp/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-bmp/meson.build 2022-08-26 11:05:18.326295200 -0600
@@ -10,9 +10,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-dds/meson.build pika-2.99.12/plug-ins/file-dds/meson.build
--- pika-2.99.12-c/plug-ins/file-dds/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-dds/meson.build 2022-08-26 11:05:18.328294700 -0600
@@ -14,9 +14,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-exr/meson.build pika-2.99.12/plug-ins/file-exr/meson.build
--- pika-2.99.12-c/plug-ins/file-exr/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-exr/meson.build 2022-08-26 11:05:18.330294400 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-faxg3/meson.build pika-2.99.12/plug-ins/file-faxg3/meson.build
--- pika-2.99.12-c/plug-ins/file-faxg3/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-faxg3/meson.build 2022-08-26 11:05:18.332294000 -0600
@@ -9,9 +9,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
--- pika-2.99.16/plug-ins/file-fits/meson.build.orig 2023-07-06 07:48:46.078752900 +0200
+++ pika-2.99.16/plug-ins/file-fits/meson.build 2023-07-06 07:49:41.120861200 +0200
@@ -9,9 +9,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-fli/meson.build pika-2.99.12/plug-ins/file-fli/meson.build
--- pika-2.99.12-c/plug-ins/file-fli/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-fli/meson.build 2022-08-26 11:05:18.336295400 -0600
@@ -9,9 +9,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-ico/meson.build pika-2.99.12/plug-ins/file-ico/meson.build
--- pika-2.99.12-c/plug-ins/file-ico/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-ico/meson.build 2022-08-26 11:05:18.338293600 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-jpeg/meson.build pika-2.99.12/plug-ins/file-jpeg/meson.build
--- pika-2.99.12-c/plug-ins/file-jpeg/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-jpeg/meson.build 2022-08-26 11:05:18.340292800 -0600
@@ -13,9 +13,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-psd/meson.build pika-2.99.12/plug-ins/file-psd/meson.build
--- pika-2.99.12-c/plug-ins/file-psd/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-psd/meson.build 2022-08-26 11:05:18.342293000 -0600
@@ -14,9 +14,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-raw/meson.build pika-2.99.12/plug-ins/file-raw/meson.build
--- pika-2.99.12-c/plug-ins/file-raw/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-raw/meson.build 2022-08-26 11:05:18.344293200 -0600
@@ -21,9 +21,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-sgi/meson.build pika-2.99.12/plug-ins/file-sgi/meson.build
--- pika-2.99.12-c/plug-ins/file-sgi/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-sgi/meson.build 2022-08-26 11:05:18.346292800 -0600
@@ -9,9 +9,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-tiff/meson.build pika-2.99.12/plug-ins/file-tiff/meson.build
--- pika-2.99.12-c/plug-ins/file-tiff/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-tiff/meson.build 2022-08-26 11:05:18.348293500 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/file-webp/meson.build pika-2.99.12/plug-ins/file-webp/meson.build
--- pika-2.99.12-c/plug-ins/file-webp/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/file-webp/meson.build 2022-08-26 11:05:18.350294300 -0600
@@ -13,9 +13,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/flame/meson.build pika-2.99.12/plug-ins/flame/meson.build
--- pika-2.99.12-c/plug-ins/flame/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/flame/meson.build 2022-08-26 11:05:18.353294700 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/fractal-explorer/meson.build pika-2.99.12/plug-ins/fractal-explorer/meson.build
--- pika-2.99.12-c/plug-ins/fractal-explorer/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/fractal-explorer/meson.build 2022-08-26 11:05:18.355294200 -0600
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/gfig/meson.build pika-2.99.12/plug-ins/gfig/meson.build
--- pika-2.99.12-c/plug-ins/gfig/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/gfig/meson.build 2022-08-26 11:05:18.358466600 -0600
@@ -27,9 +27,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/pikaressionist/meson.build pika-2.99.12/plug-ins/pikaressionist/meson.build
--- pika-2.99.12-c/plug-ins/pikaressionist/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/pikaressionist/meson.build 2022-08-26 11:05:18.361592500 -0600
@@ -29,9 +29,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/gradient-flare/meson.build pika-2.99.12/plug-ins/gradient-flare/meson.build
--- pika-2.99.12-c/plug-ins/gradient-flare/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/gradient-flare/meson.build 2022-08-26 11:05:18.365447800 -0600
@@ -10,9 +10,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/help/meson.build pika-2.99.12/plug-ins/help/meson.build
--- pika-2.99.12-c/plug-ins/help/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/help/meson.build 2022-08-26 11:05:18.367447200 -0600
@@ -13,9 +13,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/help-browser/meson.build pika-2.99.12/plug-ins/help-browser/meson.build
--- pika-2.99.12-c/plug-ins/help-browser/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/help-browser/meson.build 2022-08-26 11:05:18.369447300 -0600
@@ -12,9 +12,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/ifs-compose/meson.build pika-2.99.12/plug-ins/ifs-compose/meson.build
--- pika-2.99.12-c/plug-ins/ifs-compose/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/ifs-compose/meson.build 2022-08-26 11:05:18.371447900 -0600
@@ -10,9 +10,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/imagemap/meson.build pika-2.99.12/plug-ins/imagemap/meson.build
--- pika-2.99.12-c/plug-ins/imagemap/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/imagemap/meson.build 2022-08-26 11:05:18.373620200 -0600
@@ -73,9 +73,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/lighting/meson.build pika-2.99.12/plug-ins/lighting/meson.build
--- pika-2.99.12-c/plug-ins/lighting/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/lighting/meson.build 2022-08-26 11:05:18.376619900 -0600
@@ -17,9 +17,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/map-object/meson.build pika-2.99.12/plug-ins/map-object/meson.build
--- pika-2.99.12-c/plug-ins/map-object/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/map-object/meson.build 2022-08-26 11:05:18.378618900 -0600
@@ -16,9 +16,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/metadata/meson.build pika-2.99.12/plug-ins/metadata/meson.build
--- pika-2.99.12-c/plug-ins/metadata/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/metadata/meson.build 2022-08-26 11:05:18.381620300 -0600
@@ -17,9 +17,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
@@ -55,9 +55,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/pagecurl/meson.build pika-2.99.12/plug-ins/pagecurl/meson.build
--- pika-2.99.12-c/plug-ins/pagecurl/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/pagecurl/meson.build 2022-08-26 11:05:18.383620200 -0600
@@ -41,9 +41,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/print/meson.build pika-2.99.12/plug-ins/print/meson.build
--- pika-2.99.12-c/plug-ins/print/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/print/meson.build 2022-08-26 11:05:18.385620400 -0600
@@ -17,9 +17,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/script-fu/interpreter/meson.build pika-2.99.12/plug-ins/script-fu/interpreter/meson.build
--- pika-2.99.12-c/plug-ins/script-fu/interpreter/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/script-fu/interpreter/meson.build 2022-08-26 11:05:18.388620100 -0600
@@ -12,9 +12,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(executable_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(executable_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/script-fu/meson.build pika-2.99.12/plug-ins/script-fu/meson.build
--- pika-2.99.12-c/plug-ins/script-fu/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/script-fu/meson.build 2022-08-26 11:05:18.392620300 -0600
@@ -31,9 +31,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(executable_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(executable_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/script-fu/server/meson.build pika-2.99.12/plug-ins/script-fu/server/meson.build
--- pika-2.99.12-c/plug-ins/script-fu/server/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/script-fu/server/meson.build 2022-08-26 11:05:18.394619900 -0600
@@ -12,9 +12,9 @@
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(executable_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(executable_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/selection-to-path/meson.build pika-2.99.12/plug-ins/selection-to-path/meson.build
--- pika-2.99.12-c/plug-ins/selection-to-path/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/selection-to-path/meson.build 2022-08-26 11:05:18.396618000 -0600
@@ -16,9 +16,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
diff -bur pika-2.99.12-c/plug-ins/twain/meson.build pika-2.99.12/plug-ins/twain/meson.build
--- pika-2.99.12-c/plug-ins/twain/meson.build 2022-08-21 13:21:38.000000000 -0600
+++ pika-2.99.12/plug-ins/twain/meson.build 2022-08-26 11:05:18.398619200 -0600
@@ -14,9 +14,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
--- pika-2.99.14/plug-ins/file-icns/meson.build.orig 2022-11-14 00:04:38.000000000 +0100
+++ pika-2.99.14/plug-ins/file-icns/meson.build 2022-11-19 21:03:14.665912600 +0100
@@ -11,9 +11,9 @@
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
- '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
- '--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
- '--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
+ '--define', 'ORIGINALFILENAME_STR=@0@'.format(plugin_name+'.exe'),
+ '--define', 'INTERNALNAME_STR=@0@' .format(plugin_name),
+ '--define', 'TOP_SRCDIR=@0@' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,

312
libpika/pikabrush.c Normal file
View 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
View 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
View 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);
}

View 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__ */

View 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);
}

View 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__ */

View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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__ */

View 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;
}

View 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
View 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
View 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__ */

View 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;
}

View 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
View 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
View 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__ */

View 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);
}

View 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
View 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
View 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__ */

View 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);
}

View 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__ */

398
libpikabase/pikachoice.c Normal file
View File

@ -0,0 +1,398 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
*
* pikachoice.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/>.
*/
#include "config.h"
#include <glib-object.h>
#include "pikabasetypes.h"
#include "pikachoice.h"
#include "pikaparamspecs.h"
typedef struct _PikaChoiceDesc
{
gchar *label;
gchar *help;
gint id;
gboolean sensitive;
} PikaChoiceDesc;
enum
{
SENSITIVITY_CHANGED,
LAST_SIGNAL
};
struct _PikaChoice
{
GObject parent_instance;
GHashTable *choices;
GList *keys;
};
static void pika_choice_finalize (GObject *object);
static void pika_choice_desc_free (PikaChoiceDesc *desc);
G_DEFINE_TYPE (PikaChoice, pika_choice, G_TYPE_OBJECT)
#define parent_class pika_choice_parent_class
static guint pika_choice_signals[LAST_SIGNAL] = { 0 };
static void
pika_choice_class_init (PikaChoiceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
pika_choice_signals[SENSITIVITY_CHANGED] =
g_signal_new ("sensitivity-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, /*G_STRUCT_OFFSET (PikaChoiceClass, sensitivity_changed),*/
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_STRING);
object_class->finalize = pika_choice_finalize;
}
static void
pika_choice_init (PikaChoice *choice)
{
choice->choices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) pika_choice_desc_free);
}
static void
pika_choice_finalize (GObject *object)
{
PikaChoice *choice = PIKA_CHOICE (object);
g_hash_table_unref (choice->choices);
g_list_free_full (choice->keys, (GDestroyNotify) g_free);
}
/* Public API */
/**
* pika_choice_new:
*
* Returns: (transfer full): a #PikaChoice.
*
* Since: 3.0
**/
PikaChoice *
pika_choice_new (void)
{
PikaChoice *choice;
choice = g_object_new (PIKA_TYPE_CHOICE, NULL);
return choice;
}
/**
* pika_choice_new_with_values:
* @nick: the first value.
* @id: integer ID for @nick.
* @label: the label of @nick.
* @help: longer help text for @nick.
* ...: more triplets of string to pre-fill the created %PikaChoice.
*
* Returns: (transfer full): a #PikaChoice.
*
* Since: 3.0
**/
PikaChoice *
pika_choice_new_with_values (const gchar *nick,
gint id,
const gchar *label,
const gchar *help,
...)
{
PikaChoice *choice;
va_list va_args;
g_return_val_if_fail (nick != NULL, NULL);
g_return_val_if_fail (label != NULL, NULL);
choice = pika_choice_new ();
va_start (va_args, help);
do
{
pika_choice_add (choice, nick, id, label, help);
nick = va_arg (va_args, const gchar *);
if (nick == NULL)
break;
id = va_arg (va_args, gint);
label = va_arg (va_args, const gchar *);
if (label == NULL)
{
g_critical ("%s: nick '%s' cannot have a NULL label.", G_STRFUNC, nick);
break;
}
help = va_arg (va_args, const gchar *);
}
while (TRUE);
va_end (va_args);
return choice;
}
/**
* pika_choice_add:
* @choice: the %PikaChoice.
* @nick: the nick of @choice.
* @id: optional integer ID for @nick.
* @label: the label of @choice.
* @help: optional longer help text for @nick.
*
* This procedure adds a new possible value to @choice list of values.
* The @id is an optional integer identifier. This can be useful for instance
* when you want to work with different enum values mapped to each @nick.
*
* Since: 3.0
**/
void
pika_choice_add (PikaChoice *choice,
const gchar *nick,
gint id,
const gchar *label,
const gchar *help)
{
PikaChoiceDesc *desc;
GList *duplicate;
g_return_if_fail (label != NULL);
desc = g_new0 (PikaChoiceDesc, 1);
desc->id = id;
desc->label = g_strdup (label);
desc->help = help != NULL ? g_strdup (help) : NULL;
desc->sensitive = TRUE;
g_hash_table_insert (choice->choices, g_strdup (nick), desc);
duplicate = g_list_find_custom (choice->keys, nick, (GCompareFunc) g_strcmp0);
if (duplicate != NULL)
{
choice->keys = g_list_remove_link (choice->keys, duplicate);
pika_choice_desc_free (duplicate->data);
g_list_free (duplicate);
}
choice->keys = g_list_append (choice->keys, g_strdup (nick));
}
/**
* pika_choice_is_valid:
* @choice: a %PikaChoice.
* @nick: the nick to check.
*
* This procedure checks if the given @nick is valid and refers to
* an existing choice.
*
* Returns: Whether the choice is valid.
*
* Since: 3.0
**/
gboolean
pika_choice_is_valid (PikaChoice *choice,
const gchar *nick)
{
PikaChoiceDesc *desc;
g_return_val_if_fail (PIKA_IS_CHOICE (choice), FALSE);
g_return_val_if_fail (nick != NULL, FALSE);
desc = g_hash_table_lookup (choice->choices, nick);
return (desc != NULL && desc->sensitive);
}
/**
* pika_choice_list_nicks:
* @choice: a %PikaChoice.
* @nick: the nick to check.
*
* This procedure returns the list of nicks allowed for @choice.
*
* Returns: (element-type gchar*) (transfer none): The list of @choice's nicks.
*
* Since: 3.0
**/
GList *
pika_choice_list_nicks (PikaChoice *choice)
{
/* I don't use g_hash_table_get_keys() on purpose, because I want to retain
* the adding-time order.
*/
return choice->keys;
}
/**
* pika_choice_get_id:
* @choice: a %PikaChoice.
* @nick: the nick to lookup.
*
* Returns: the ID of @nick.
*
* Since: 3.0
**/
gint
pika_choice_get_id (PikaChoice *choice,
const gchar *nick)
{
PikaChoiceDesc *desc;
desc = g_hash_table_lookup (choice->choices, nick);
if (desc)
return desc->id;
else
return 0;
}
/**
* pika_choice_get_label:
* @choice: a %PikaChoice.
* @nick: the nick to lookup.
*
* Returns: (transfer none): the label of @nick.
*
* Since: 3.0
**/
const gchar *
pika_choice_get_label (PikaChoice *choice,
const gchar *nick)
{
PikaChoiceDesc *desc;
desc = g_hash_table_lookup (choice->choices, nick);
if (desc)
return desc->label;
else
return NULL;
}
/**
* pika_choice_get_help:
* @choice: a %PikaChoice.
* @nick: the nick to lookup.
*
* Returns the longer documentation for @nick.
*
* Returns: (transfer none): the help text of @nick.
*
* Since: 3.0
**/
const gchar *
pika_choice_get_help (PikaChoice *choice,
const gchar *nick)
{
PikaChoiceDesc *desc;
desc = g_hash_table_lookup (choice->choices, nick);
if (desc)
return desc->help;
else
return NULL;
}
/**
* pika_choice_get_documentation:
* @choice: the %PikaChoice.
* @nick: the possible value's nick you need documentation for.
* @label: (transfer none): the label of @nick.
* @help: (transfer none): the help text of @nick.
*
* Returns the documentation strings for @nick.
*
* Returns: %TRUE if @nick is found, %FALSE otherwise.
*
* Since: 3.0
**/
gboolean
pika_choice_get_documentation (PikaChoice *choice,
const gchar *nick,
const gchar **label,
const gchar **help)
{
PikaChoiceDesc *desc;
desc = g_hash_table_lookup (choice->choices, nick);
if (desc)
{
*label = desc->label;
*help = desc->help;
return TRUE;
}
return FALSE;
}
/**
* pika_choice_set_sensitive:
* @choice: the %PikaChoice.
* @nick: the nick to lookup.
*
* Change the sensitivity of a possible @nick. Technically a non-sensitive @nick
* means it cannot be chosen anymore (so [method@Gimp.Choice.is_valid] will
* return %FALSE; nevertheless [method@Gimp.Choice.list_nicks] and other
* functions to get information about a choice will still function).
*
* Returns: %TRUE if @nick is found, %FALSE otherwise.
*
* Since: 3.0
**/
void
pika_choice_set_sensitive (PikaChoice *choice,
const gchar *nick,
gboolean sensitive)
{
PikaChoiceDesc *desc;
g_return_if_fail (PIKA_IS_CHOICE (choice));
g_return_if_fail (nick != NULL);
desc = g_hash_table_lookup (choice->choices, nick);
g_return_if_fail (desc != NULL);
if (desc->sensitive != sensitive)
{
desc->sensitive = sensitive;
g_signal_emit (choice, pika_choice_signals[SENSITIVITY_CHANGED], 0, nick);
}
}
/* Private functions */
static void
pika_choice_desc_free (PikaChoiceDesc *desc)
{
g_free (desc->label);
g_free (desc->help);
g_free (desc);
}

73
libpikabase/pikachoice.h Normal file
View File

@ -0,0 +1,73 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
*
* pikachoice.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_BASE_H_INSIDE__) && !defined (PIKA_BASE_COMPILATION)
#error "Only <libpikabase/pikabase.h> can be included directly."
#endif
#ifndef __PIKA_CHOICE_H__
#define __PIKA_CHOICE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_CHOICE (pika_choice_get_type ())
G_DECLARE_FINAL_TYPE (PikaChoice, pika_choice, PIKA, CHOICE, GObject)
PikaChoice * pika_choice_new (void);
PikaChoice * pika_choice_new_with_values (const gchar *nick,
gint id,
const gchar *label,
const gchar *help,
...) G_GNUC_NULL_TERMINATED;
void pika_choice_add (PikaChoice *choice,
const gchar *nick,
gint id,
const gchar *label,
const gchar *help);
gboolean pika_choice_is_valid (PikaChoice *choice,
const gchar *nick);
GList * pika_choice_list_nicks (PikaChoice *choice);
gint pika_choice_get_id (PikaChoice *choice,
const gchar *nick);
const gchar * pika_choice_get_label (PikaChoice *choice,
const gchar *nick);
const gchar * pika_choice_get_help (PikaChoice *choice,
const gchar *nick);
gboolean pika_choice_get_documentation (PikaChoice *choice,
const gchar *nick,
const gchar **label,
const gchar **help);
void pika_choice_set_sensitive (PikaChoice *choice,
const gchar *nick,
gboolean sensitive);
G_END_DECLS
#endif /* __PIKA_CHOICE_H__ */

View File

@ -0,0 +1,291 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelstringwidget.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
* 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 "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikalabelstringwidget.h"
/**
* SECTION: pikalabelstringwidget
* @title: PikaLabelStringWidget
* @short_description: Widget containing a label and a widget with a
* string "value" property.
*
* This widget is a subclass of #PikaLabeled.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_VALUE,
PROP_WIDGET,
};
typedef struct _PikaLabelStringWidgetPrivate
{
PikaLabeled parent_instance;
GtkWidget *widget;
gchar *value;
} PikaLabelStringWidgetPrivate;
static void pika_label_string_widget_constructed (GObject *object);
static void pika_label_string_widget_finalize (GObject *object);
static void pika_label_string_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_label_string_widget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * pika_label_string_widget_populate (PikaLabeled *widget,
gint *x,
gint *y,
gint *width,
gint *height);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabelStringWidget, pika_label_string_widget, PIKA_TYPE_LABELED)
#define parent_class pika_label_string_widget_parent_class
static guint pika_label_string_widget_signals[LAST_SIGNAL] = { 0 };
static void
pika_label_string_widget_class_init (PikaLabelStringWidgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaLabeledClass *labeled_class = PIKA_LABELED_CLASS (klass);
pika_label_string_widget_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabelStringWidgetClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_label_string_widget_constructed;
object_class->finalize = pika_label_string_widget_finalize;
object_class->set_property = pika_label_string_widget_set_property;
object_class->get_property = pika_label_string_widget_get_property;
labeled_class->populate = pika_label_string_widget_populate;
/**
* PikaLabelStringWidget:value:
*
* The currently set value.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_string ("value", NULL,
"Current value",
NULL,
PIKA_PARAM_READWRITE));
/**
* PikaLabelStringWidget:widget:
*
* The widget holding a string property named "value".
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_WIDGET,
g_param_spec_object ("widget", NULL,
"String widget",
GTK_TYPE_WIDGET,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
pika_label_string_widget_init (PikaLabelStringWidget *widget)
{
}
static void
pika_label_string_widget_constructed (GObject *object)
{
PikaLabelStringWidget *widget = PIKA_LABEL_STRING_WIDGET (object);
PikaLabelStringWidgetPrivate *priv = pika_label_string_widget_get_instance_private (widget);
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
/* This is important to make this object into a property widget. It
* will allow config object to bind the "value" property of this
* widget, and therefore be updated automatically.
*/
g_object_bind_property (G_OBJECT (priv->widget), "value",
object, "value",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
}
static void
pika_label_string_widget_finalize (GObject *object)
{
PikaLabelStringWidget *widget = PIKA_LABEL_STRING_WIDGET (object);
PikaLabelStringWidgetPrivate *priv = pika_label_string_widget_get_instance_private (widget);
g_free (priv->value);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_label_string_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabelStringWidget *widget = PIKA_LABEL_STRING_WIDGET (object);
PikaLabelStringWidgetPrivate *priv = pika_label_string_widget_get_instance_private (widget);
switch (property_id)
{
case PROP_VALUE:
if (g_strcmp0 (priv->value, g_value_get_string (value)) != 0)
{
g_free (priv->value);
priv->value = g_value_dup_string (value);
g_signal_emit (object, pika_label_string_widget_signals[VALUE_CHANGED], 0);
}
break;
case PROP_WIDGET:
priv->widget = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_label_string_widget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabelStringWidget *widget = PIKA_LABEL_STRING_WIDGET (object);
PikaLabelStringWidgetPrivate *priv = pika_label_string_widget_get_instance_private (widget);
switch (property_id)
{
case PROP_VALUE:
g_value_set_string (value, priv->value);
break;
case PROP_WIDGET:
g_value_set_object (value, priv->widget);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GtkWidget *
pika_label_string_widget_populate (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height)
{
PikaLabelStringWidget *widget = PIKA_LABEL_STRING_WIDGET (labeled);
PikaLabelStringWidgetPrivate *priv = pika_label_string_widget_get_instance_private (widget);
gtk_grid_attach (GTK_GRID (widget), priv->widget, 1, 0, 1, 1);
gtk_widget_show (priv->widget);
return priv->widget;
}
/* Public Functions */
/**
* pika_label_string_widget_new:
* @text: The text for the #GtkLabel.
* @widget: (transfer full): The #GtkWidget to use.
*
* Creates a new #PikaLabelStringWidget whose "value" property is bound to
* that of @widget (which must therefore have such a string property).
*
* Returns: (transfer full): The new #PikaLabelStringWidget widget.
**/
GtkWidget *
pika_label_string_widget_new (const gchar *text,
GtkWidget *widget)
{
GtkWidget *string_widget;
GParamSpec *pspec;
g_return_val_if_fail ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (widget),
"value")) &&
(G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_STRING ||
G_PARAM_SPEC_TYPE (pspec) == PIKA_TYPE_PARAM_CHOICE),
NULL);
string_widget = g_object_new (PIKA_TYPE_LABEL_STRING_WIDGET,
"label", text,
"widget", widget,
NULL);
return string_widget;
}
/**
* pika_label_string_widget_get_widget:
* @widget: the #PikaLabelStringWidget.
*
* Returns: (transfer none): The new #GtkWidget packed next to the label.
**/
GtkWidget *
pika_label_string_widget_get_widget (PikaLabelStringWidget *widget)
{
PikaLabelStringWidgetPrivate *priv;
g_return_val_if_fail (PIKA_IS_LABEL_STRING_WIDGET (widget), NULL);
priv = pika_label_string_widget_get_instance_private (widget);
return priv->widget;
}

View File

@ -0,0 +1,62 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelstringwidget.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_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABEL_STRING_WIDGET_H__
#define __PIKA_LABEL_STRING_WIDGET_H__
#include <libpikawidgets/pikalabeled.h>
G_BEGIN_DECLS
#define PIKA_TYPE_LABEL_STRING_WIDGET (pika_label_string_widget_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabelStringWidget, pika_label_string_widget, PIKA, LABEL_STRING_WIDGET, PikaLabeled)
struct _PikaLabelStringWidgetClass
{
PikaLabeledClass parent_class;
/* Signals */
void (* value_changed) (GtkWidget *string_widget);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_label_string_widget_new (const gchar *text,
GtkWidget *widget);
GtkWidget * pika_label_string_widget_get_widget (PikaLabelStringWidget *widget);
G_END_DECLS
#endif /* __PIKA_LABEL_STRING_WIDGET_H__ */

View File

@ -0,0 +1,113 @@
# PIKA - Photo and Image Kooker Application
# Copyright (C) 1995 Spencer Kimball and Peter Mattis
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
sub drawables_popup {
$blurb = 'Invokes the drawable selection dialog.';
$help = 'Opens a dialog letting a user choose an drawable.';
&jehan_pdb_misc('2023');
@inargs = (
{ name => 'callback', type => 'string', non_empty => 1,
desc => 'The callback PDB proc to call when user chooses an drawable' },
{ name => 'popup_title', type => 'string',
desc => 'Title of the drawable selection dialog' },
{ name => 'drawable_type', type => 'string', non_empty => 1,
desc => 'The name of the PIKA_TYPE_DRAWABLE subtype' },
{ name => 'initial_drawable', type => 'drawable', null_ok => 1, no_validate => 1,
desc => 'The drawable to set as the initial choice' },
{ name => 'parent_window', type => 'bytes', null_ok => 1,
desc => 'An optional parent window handle for the popup to be set transient to' }
);
%invoke = (
code => <<'CODE'
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_new (pika, context, progress,
g_type_from_name (drawable_type),
parent_window, popup_title, callback,
PIKA_OBJECT (initial_drawable),
NULL))
success = FALSE;
}
CODE
);
}
sub drawables_close_popup {
$blurb = 'Close the drawable selection dialog.';
$help = 'Closes an open drawable selection dialog.';
&jehan_pdb_misc('2023');
@inargs = (
{ name => 'callback', type => 'string', non_empty => 1,
desc => 'The name of the callback registered for this pop-up' }
);
%invoke = (
code => <<'CODE'
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_close (pika, PIKA_TYPE_DRAWABLE, callback))
success = FALSE;
}
CODE
);
}
sub drawables_set_popup {
$blurb = 'Sets the selected drawable in a drawable selection dialog.';
$help = $blurb;
&jehan_pdb_misc('2023');
@inargs = (
{ name => 'callback', type => 'string', non_empty => 1,
desc => 'The name of the callback registered for this pop-up' },
{ name => 'drawable', type => 'drawable', no_validate => 1,
desc => 'The drawable to set as selected' }
);
%invoke = (
code => <<'CODE'
{
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
! pika_pdb_dialog_set (pika, PIKA_TYPE_DRAWABLE, callback, PIKA_OBJECT (drawable), NULL))
success = FALSE;
}
CODE
);
}
@headers = qw("core/pika.h"
"core/pikadatafactory.h");
@procs = qw(drawables_popup
drawables_close_popup
drawables_set_popup);
%exports = (app => [@procs], lib => [@procs]);
$desc = 'Drawables UI';
$doc_title = 'pikadrawableselect';
$doc_short_desc = 'Methods of a drawable chooser dialog';
1;

19
pdb/meson-enumcode.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/sh
PERL="$1"
top_srcdir="$2"
top_builddir="$3"
# Environment for the pdbgen.pl file.
destdir=`cd "$top_srcdir" && pwd`
export destdir
builddir=`cd "$top_builddir" && pwd`
export BUILD builddir
cd "$top_srcdir"/
$PERL -I "$top_builddir/pdb" -I "$top_srcdir/pdb" pdb/enumcode.pl
RET=$?
if [ $RET -eq 0 ]; then
echo "/* Generated on `date`. */" > $top_builddir/pdb/stamp-enumcode.h
fi
exit $RET

20
pdb/meson-enumgen.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/sh
PERL="$1"
top_srcdir="$2"
top_builddir="$3"
# Environment for the pdbgen.pl file.
destdir=`cd "$top_srcdir" && pwd`
export destdir
builddir=`cd "$top_builddir" && pwd`
export BUILD builddir
cd "$top_srcdir"/pdb
shift 3
$PERL enumgen.pl "${@}"
RET=$?
if [ $RET -eq 0 ]; then
echo "/* Generated on `date`. */" > $top_builddir/pdb/stamp-enumgen.h
fi
exit $RET

View File

@ -0,0 +1,126 @@
#!/usr/bin/env pika-script-fu-interpreter-3.0
; A script that fails at query/registration time: ill-formed args in registration data
; Tests the fix for #6157
; Incomplete: FUTURE add more test cases.
; One script can't test all cases.
; Several cases are tested here, but you must edit the script,
; putting each case to the top: the failing top case stops interpretation.
; Install this script.
; Start Gimp
; Expect:
; - an error in the stderr console, errors from SF re args
; e.g. "adjustment default must be list"
; - plugin should not install to the menus
; - the interpreter must not crash !!!
; - the procedure is not in ProcedureBrowser
; Note errors come before Pika Error Console is ready
; moot run func
(define (script-fu-test-registration-fail ) ())
; Case SF-ENUM not a list of two strings
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: 1 is not a string
SF-ENUM "foo" '("InterpolationType" 1)
)
; This should be moot (since it should fail earlier.)
; But leave this here so when it does succeed,
; you know earlier test failed to fail.
(script-fu-menu-register "script-fu-test-registration-fail"
"<Image>/Test")
; More tests below.
; Copy them to above, and retest.
; Can't test them all at once.
; Case SF-ADJUSTMENT default not a list
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed : 0 is not a list
SF-ADJUSTMENT "foo" 0
)
; Case: SF-ADJUSTMENT wrong list length
; At query time, SF throws error.
; At query time, a critical from Pika re arg default not in range
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: a list, but not proper length
; Expect SF error
SF-ADJUSTMENT "foo" '(0 )
)
; Case SF-OPTIONS not a list
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: a list, but not proper length
SF-OPTION "foo" "bar"
)
; Case SF-OPTIONS default an empty list
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; semantics : empty list makes no sense
SF-OPTION "foo" '()
)
; Case SF-OPTIONS list contains non-string
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; 1 is not a string
SF-OPTION "foo" '("foo" 1)
)
; Case SF-COLOR not a list or a string
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: 1 is not a list or a string
SF-COLOR "foo" 1 4 5
)
; FUTURE more test cases for SF-COLOR
; Case SF-ENUM not a list
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: "bar" is not a list
SF-ENUM "foo" "bar"
)
; Case SF-ENUM not a list of two strings
(script-fu-register "script-fu-test-registration-fail"
"Moot" "Moot" "lkk" "lkk" "2023" "" ; requires no image
; ill-formed arg spec: 1 is not a string
SF-ENUM "foo" '("InterpolationType" 1)
)
; FUTURE more test cases for SF-ENUM

398
po-windows-installer/be.po Normal file
View File

@ -0,0 +1,398 @@
# Belarusian translation for pika.
# Copyright (C) 2023 pika's COPYRIGHT HOLDER
# This file is distributed under the same license as the pika package.
# Yuras Shumovich <shumovichy@gmail.com>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: pika master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/pika/issues\n"
"POT-Creation-Date: 2023-09-26 14:33+0000\n"
"PO-Revision-Date: 2023-09-26 17:54+0300\n"
"Last-Translator: Yuras Shumovich <shumovichy@gmail.com>\n"
"Language-Team: Belarusian <i18n-bel-gnome@googlegroups.com>\n"
"Language: be\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 3.3.2\n"
#: build/windows/installer/lang/setup.isl.xml.in:7
msgid "License Agreement"
msgstr "Ліцэнзійнае пагадненне"
#: build/windows/installer/lang/setup.isl.xml.in:10
msgid "Setup built by Jernej Simonèiè, jernej-pika@ena.si"
msgstr ""
"Праграму ўсталявання сабраў Ерней Сімончыч (Jernej Simončič), jernej-"
"pika@ena.si"
#: build/windows/installer/lang/setup.isl.xml.in:13
#: build/windows/installer/lang/setup.isl.xml.in:16
msgid "This version of PIKA requires Windows 7, or a newer version of Windows."
msgstr ""
"Гэтай версіі PIKA патрабуецца Windows 7 або любая пазнейшая версія Windows."
#: build/windows/installer/lang/setup.isl.xml.in:23
msgid "Development version"
msgstr "Версія для распрацоўкі"
#: build/windows/installer/lang/setup.isl.xml.in:28
msgid ""
"This is a development version of PIKA where some features may not be "
"finished, or it may be unstable.%nThis version of PIKA is not intended for "
"day-to-day work as it may be unstable, and you could lose your work.%nIf you "
"encounter any problems, first verify that they haven't already been fixed in "
"GIT before you contact the developers or report it in PIKA gitlab:%n_https://"
"gitlab.gnome.org/GNOME/pika/issues%n%nDo you wish to continue with "
"installation anyway?"
msgstr ""
"Гэта версія для распрацоўкі PIKA, некаторыя функцыі могуць быць "
"незавершанымі або нестабільнымі.%nГэтая версія PIKA не прызначана для "
"штодзённай працы, бо з-за нестабільнасці, вынікі працы могуць быць страчаны."
"%nКалі вы сутыкнуліся з нейкімі праблемамі, спачатку трэба ўпэўніцца, што іх "
"не выправілі на GIT і толькі пасля паведамляць аб праблемах распрацоўшчыкам "
"PIKA на gitlab:%n_https://gitlab.gnome.org/GNOME/pika/issues%n%nУсё роўна "
"працягваць усталяванне?"
#: build/windows/installer/lang/setup.isl.xml.in:31
#: build/windows/installer/lang/setup.isl.xml.in:54
msgid "&Continue"
msgstr "&Працягнуць"
#: build/windows/installer/lang/setup.isl.xml.in:34
msgid "Exit"
msgstr "Выйсці"
#: build/windows/installer/lang/setup.isl.xml.in:44
msgid ""
"This version of PIKA requires a processor that supports SSE instructions."
msgstr "Гэтай версіі PIKA патрабуецца працэсар з падтрымкай інструкцый SSE."
#: build/windows/installer/lang/setup.isl.xml.in:48
msgid "Display settings problem"
msgstr "Праблема з наладамі дысплэя"
#: build/windows/installer/lang/setup.isl.xml.in:51
msgid ""
"Setup has detected that your Windows is not running in 32 bits-per-pixel "
"display mode. This has been known to cause stability problems with PIKA, so "
"it's recommended to change the display colour depth to 32BPP before "
"continuing."
msgstr ""
"Праграма ўсталявання выявіла, што ваша сістэма Windows запушчана не ў рэжыме "
"адлюстравання 32bpp. вядома, што гэта можа выклікаць нестабільную працу "
"PIKA, таму, перш чым працягваць, рэкамендуецца змяніць глыбіню колеру на "
"32bpp."
#: build/windows/installer/lang/setup.isl.xml.in:57
msgid "E&xit"
msgstr "&Выхад"
#: build/windows/installer/lang/setup.isl.xml.in:61
msgid ""
"PIKA is now ready to be installed. Click the Install now button to install "
"using the default settings, or click the Customize button if you'd like to "
"have more control over what gets installed."
msgstr ""
"Цяпер PIKA гатовы да ўсталявання. Каб усталяваць праграму з прадвызначанымі "
"наладамі, націсніце кнопку «Усталяваць», або націсніце «Наладзіць», каб "
"выбраць пэўныя кампаненты."
#: build/windows/installer/lang/setup.isl.xml.in:64
msgid "&Install"
msgstr "&Усталяваць"
#: build/windows/installer/lang/setup.isl.xml.in:67
msgid "&Customize"
msgstr "&Наладзіць"
#: build/windows/installer/lang/setup.isl.xml.in:72
msgid "Compact installation"
msgstr "Кампактнае ўсталяванне"
#: build/windows/installer/lang/setup.isl.xml.in:76
msgid "Custom installation"
msgstr "Выбарачнае ўсталяванне"
#: build/windows/installer/lang/setup.isl.xml.in:80
msgid "Full installation"
msgstr "Поўнае ўсталяванне"
#: build/windows/installer/lang/setup.isl.xml.in:85
msgid "Description"
msgstr "Апісанне"
#: build/windows/installer/lang/setup.isl.xml.in:89
msgid "PIKA"
msgstr "PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:93
msgid "PIKA and all default plug-ins"
msgstr "PIKA і ўсе прадвызначаныя ўбудовы"
#: build/windows/installer/lang/setup.isl.xml.in:97
msgid "Run-time libraries"
msgstr "Бібліятэкі праграмы"
#: build/windows/installer/lang/setup.isl.xml.in:101
msgid "Run-time libraries used by PIKA, including GTK Run-time Environment"
msgstr ""
"Бібліятэкі, якія выкарыстоўвае PIKA, у тым ліку асяроддзе выканання GTK"
#: build/windows/installer/lang/setup.isl.xml.in:105
msgid "Debug symbols"
msgstr "Адладачныя сімвалы"
#: build/windows/installer/lang/setup.isl.xml.in:109
msgid "Include information to help with debugging PIKA"
msgstr "Уключыць інфармацыю, якая дапамагае з адладкай PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:113
msgid "MS-Windows engine for GTK"
msgstr "Рухавік MS Windows для GTK"
#: build/windows/installer/lang/setup.isl.xml.in:117
msgid "Native Windows look for PIKA"
msgstr "Уласнасістэмны выгляд Windows для PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:121
msgid "Support for old plug-ins"
msgstr "Падтрымка старых убудоў"
#: build/windows/installer/lang/setup.isl.xml.in:125
msgid "Install libraries needed by old third-party plug-ins"
msgstr "Усталяваць бібліятэкі, патрэбныя старым убудовам з пабочных крыніц"
#: build/windows/installer/lang/setup.isl.xml.in:129
#: build/windows/installer/lang/setup.isl.xml.in:133
msgid "Translations"
msgstr "Пераклады"
#: build/windows/installer/lang/setup.isl.xml.in:137
msgid "Python scripting"
msgstr "Скрыпты Python"
#: build/windows/installer/lang/setup.isl.xml.in:141
msgid "Allows you to use PIKA plugins written in Python scripting language."
msgstr "Дазваляе выкарыстоўваць убудовы напісаныя на мове скрыптоў Python."
#: build/windows/installer/lang/setup.isl.xml.in:145
msgid "Lua scripting"
msgstr "Скрыпты Lua"
#: build/windows/installer/lang/setup.isl.xml.in:149
msgid "Allows you to use PIKA plugins written in Lua scripting language."
msgstr "Дазваляе выкарыстоўваць убудовы напісаныя на мове скрыптоў Lua."
#: build/windows/installer/lang/setup.isl.xml.in:153
msgid "MyPaint brushes"
msgstr "Пэндзлі MyPaint"
#: build/windows/installer/lang/setup.isl.xml.in:157
msgid "Install the default set of MyPaint brushes"
msgstr "Усталяваць прадвызначаны набор пэндзляў MyPaint"
#: build/windows/installer/lang/setup.isl.xml.in:161
msgid "PostScript support"
msgstr "Падтрымка PostScript"
#: build/windows/installer/lang/setup.isl.xml.in:165
msgid "Allow PIKA to load PostScript files"
msgstr "Дазваляе PIKA загружаць файлы PostScript"
#: build/windows/installer/lang/setup.isl.xml.in:169
msgid "Support for 32-bit plug-ins"
msgstr "Падтрымка 32-бітных убудоў"
#: build/windows/installer/lang/setup.isl.xml.in:173
msgid ""
"Include files necessary for using 32-bit plug-ins.%nRequired for Python "
"support."
msgstr ""
"Уключыць файлы, неабходныя для выкарыстання 32-бітных плагінаў.%nПатрабуюцца "
"для падтрымкі Python."
#: build/windows/installer/lang/setup.isl.xml.in:178
msgid "Additional icons:"
msgstr "Дадатковыя значкі:"
#: build/windows/installer/lang/setup.isl.xml.in:182
msgid "Create a &desktop icon"
msgstr "Стварыць значок на працоўным &стале"
#: build/windows/installer/lang/setup.isl.xml.in:186
msgid "Create a &Quick Launch icon"
msgstr "Стварыць значок на &панэлі хуткага запуску"
#: build/windows/installer/lang/setup.isl.xml.in:190
msgid "Remove previous PIKA version"
msgstr "Выдаліць папярэднюю версію PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:195
msgid ""
"There was a problem updating PIKA's environment in %1. If you get any errors "
"loading the plug-ins, try uninstalling and re-installing PIKA."
msgstr ""
"Узнікла праблема падчас абнаўлення асяроддзя PIKA у %1. Калі вы атрымаеце "
"памылкі падчас загрузкі ўбудоў, паспрабуйце выдаліць PIKA і потым зноў "
"ўсталяваць."
#: build/windows/installer/lang/setup.isl.xml.in:199
msgid "Error extracting temporary data."
msgstr "Памылка вымання часовых даных."
#: build/windows/installer/lang/setup.isl.xml.in:203
msgid "Error updating Python interpreter info."
msgstr "Памылка абнаўлення інфармацыі пра інтэрпрэтатар Python."
#: build/windows/installer/lang/setup.isl.xml.in:207
msgid "Error updating MyPaint brushes info."
msgstr "Памылка абнаўлення інфармацыі пра пэндзлі MyPaint."
#: build/windows/installer/lang/setup.isl.xml.in:211
msgid "There was an error updating %1."
msgstr "Узнікла памылка падчас абнаўлення %1."
#: build/windows/installer/lang/setup.isl.xml.in:215
msgid "There was an error updating PIKA's configuration file %1."
msgstr "Узнікла памылка падчас абнаўлення файла канфігурацыі PIKA %1."
#: build/windows/installer/lang/setup.isl.xml.in:220
msgid "Edit with PIKA"
msgstr "Змяніць праз PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:225
msgid "Select file associations"
msgstr "Суаднясенне з файламі"
#: build/windows/installer/lang/setup.isl.xml.in:229
msgid "Extensions:"
msgstr "Пашырэнні:"
#: build/windows/installer/lang/setup.isl.xml.in:233
msgid "Select the file types you wish to associate with PIKA"
msgstr "Выберыце тыпы файлаў, якія вы хочаце суаднесці з PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:237
msgid ""
"This will make selected files open in PIKA when you double-click them in "
"Explorer."
msgstr ""
"Такім чынам выбраныя файлы, пры падвойным націсканні ў Правадніку, будуць "
"адкрывацца праз PIKA."
#: build/windows/installer/lang/setup.isl.xml.in:241
msgid "Select &All"
msgstr "Вылучыць &усе"
#: build/windows/installer/lang/setup.isl.xml.in:245
msgid "Unselect &All"
msgstr "Зняць вылучэнне з &усіх"
#: build/windows/installer/lang/setup.isl.xml.in:249
msgid "Select &Unused"
msgstr "Вылучыць &нявыкарыстаныя"
#: build/windows/installer/lang/setup.isl.xml.in:254
msgid "File types to associate with PIKA:"
msgstr "Тыпы файлаў, суаднесеныя PIKA:"
#: build/windows/installer/lang/setup.isl.xml.in:258
msgid "Removing previous version of PIKA:"
msgstr "Выдаленне папярэдняй версіі PIKA:"
#: build/windows/installer/lang/setup.isl.xml.in:262
msgid ""
"PIKA %1 cannot be installed over your currently installed PIKA version, and "
"the automatic uninstall of old version has failed.%n%nPlease remove the "
"previous version of PIKA yourself before installing this version in %2, or "
"choose a Custom install, and select a different installation folder.%n%nThe "
"Setup will now exit."
msgstr ""
"Немагчыма ўсталяваць PIKA %1 на ўсталяваную ў цяперашні час версію, і не "
"ўдалося выдаліць старую версію аўтаматычна.%n%nПерш чым усталяваць у %2 "
"гэтую версію PIKA, выдаліце ўручную папярэднюю, або націсніце кнопку "
"«Наладзіць» і выберыце іншую папку ўсталявання.%n%nЗараз праграма "
"ўсталявання завершыць працу."
#: build/windows/installer/lang/setup.isl.xml.in:266
msgid ""
"PIKA %1 cannot be installed over your currently installed PIKA version, and "
"Setup couldn't determine how to remove the old version automatically."
"%n%nPlease remove the previous version of PIKA and any add-ons yourself "
"before installing this version in %2, or choose a Custom install, and select "
"a different installation folder.%n%nThe Setup will now exit."
msgstr ""
"Немагчыма ўсталяваць PIKA %1 на ўсталяваную ў цяперашні час версію, і "
"праграма ўсталявання не можа вызначыць як выдаліць старую версію аўтаматычна."
"%n%nПерш чым усталяваць у %2 гэтую версію PIKA, выдаліце ўручную папярэднюю "
"версію і ўсе ўбудовы,, або націсніце кнопку «Наладзіць» і выберыце іншую "
"папку ўсталявання.%n%nЗараз праграма ўсталявання завершыць працу."
#: build/windows/installer/lang/setup.isl.xml.in:270
msgid ""
"Previous PIKA version was removed successfully, but Windows has to be "
"restarted before the Setup can continue.%n%nAfter restarting your computer, "
"Setup will continue next time an administrator logs in."
msgstr ""
"Папярэдняя версія PIKA паспяхова выдалена, але патрабуецца перазапусціць "
"Windows, каб працягнуць ўсталяванне.%n%nПасля перазапуску камп'ютара, "
"ўсталяванне працягнецца, калі адміністратар увойдзе ў сістэму."
#: build/windows/installer/lang/setup.isl.xml.in:275
msgid "There was an error restarting the Setup. (%1)"
msgstr "Узнікла памылка падчас паўторнага запуску праграмы ўсталявання (%1)"
#: build/windows/installer/lang/setup.isl.xml.in:279
msgid "Cleaning up old files..."
msgstr "Ачыстка старых файлаў..."
#: build/windows/installer/lang/setup.isl.xml.in:284
msgid "Remember: PIKA is Free Software.%n%nPlease visit"
msgstr "Помніце, PIKA свабоднае праграмнае забеспячэнне.%n%nНаведайце сайт"
#: build/windows/installer/lang/setup.isl.xml.in:288
msgid "for free updates."
msgstr "дзеля бясплатных абнаўленняў."
#: build/windows/installer/lang/setup.isl.xml.in:292
msgid "Setting up file associations..."
msgstr "Наладжваецца суаднясенне з тыпамі файлаў..."
#: build/windows/installer/lang/setup.isl.xml.in:295
msgid "Setting up environment for PIKA Python extension..."
msgstr "Наладжваецца асяроддзе для ўбудоў PIKA, напісаных на Python..."
#: build/windows/installer/lang/setup.isl.xml.in:298
msgid "Setting up MyPaint brushes..."
msgstr "Наладжваюцца пэндзлі MyPaint."
#: build/windows/installer/lang/setup.isl.xml.in:301
msgid "Setting up PIKA environment..."
msgstr "Наладжваецца асяроддзе PIKA..."
#: build/windows/installer/lang/setup.isl.xml.in:304
msgid "Setting up PIKA configuration for 32-bit plug-in support..."
msgstr "Наладжваецца канфігурацыя PIKA для падтрымкі 32-бітных убудоў..."
#: build/windows/installer/lang/setup.isl.xml.in:309
msgid "Launch PIKA"
msgstr "Запусціць PIKA"
#: build/windows/installer/lang/setup.isl.xml.in:314
msgid "Removing add-on"
msgstr "Выдаленне дадатковых кампанентаў"
#: build/windows/installer/lang/setup.isl.xml.in:318
msgid "Internal error (%1)."
msgstr "Унутраная памылка (%1)."
#: build/windows/installer/lang/setup.isl.xml.in:323
msgid ""
"PIKA does not appear to be installed in the selected directory. Continue "
"anyway?"
msgstr ""
"Падобна, што PIKA не ўсталяваны ў выбраным каталогу. Усё роўна працягнуць?"