mirror of https://github.com/GNOME/gimp.git
825 lines
28 KiB
C
825 lines
28 KiB
C
/* Plug-in to load and export .gih (GIMP Brush Pipe) files.
|
|
*
|
|
* Copyright (C) 1999 Tor Lillqvist
|
|
* Copyright (C) 2000 Jens Lautenbacher, Sven Neumann
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
/* Example of how to call file-gih-export from script-fu:
|
|
|
|
(let ((ranks (cons-array 1 'byte)))
|
|
(aset ranks 0 12)
|
|
(file-gih-export 1
|
|
img
|
|
"foo.gih"
|
|
"foo.gih"
|
|
100
|
|
"test brush"
|
|
125
|
|
125
|
|
3
|
|
4
|
|
1
|
|
ranks
|
|
1
|
|
'("random")))
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
#include <libgimpbase/gimpparasiteio.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
|
#define EXPORT_PROC "file-gih-export"
|
|
#define PLUG_IN_BINARY "file-gih"
|
|
#define PLUG_IN_ROLE "gimp-file-gih"
|
|
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *rank_entry[GIMP_PIXPIPE_MAXDIM];
|
|
GtkWidget *mode_entry[GIMP_PIXPIPE_MAXDIM];
|
|
} SizeAdjustmentData;
|
|
|
|
|
|
typedef struct _Gih Gih;
|
|
typedef struct _GihClass GihClass;
|
|
|
|
struct _Gih
|
|
{
|
|
GimpPlugIn parent_instance;
|
|
};
|
|
|
|
struct _GihClass
|
|
{
|
|
GimpPlugInClass parent_class;
|
|
};
|
|
|
|
|
|
#define GIH_TYPE (gih_get_type ())
|
|
#define GIH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIH_TYPE, Gih))
|
|
|
|
GType gih_get_type (void) G_GNUC_CONST;
|
|
|
|
static GList * gih_query_procedures (GimpPlugIn *plug_in);
|
|
static GimpProcedure * gih_create_procedure (GimpPlugIn *plug_in,
|
|
const gchar *name);
|
|
|
|
static GimpValueArray * gih_export (GimpProcedure *procedure,
|
|
GimpRunMode run_mode,
|
|
GimpImage *image,
|
|
GFile *file,
|
|
GimpMetadata *metadata,
|
|
GimpProcedureConfig *config,
|
|
gpointer run_data);
|
|
|
|
static void gih_remove_guides (GimpProcedureConfig *config,
|
|
GimpImage *image);
|
|
static void gih_cell_width_notify (GimpProcedureConfig *config,
|
|
const GParamSpec *pspec,
|
|
GimpProcedureDialog *dialog);
|
|
|
|
static gboolean gih_save_dialog (GimpImage *image,
|
|
GimpProcedure *procedure,
|
|
GimpProcedureConfig *config);
|
|
|
|
|
|
G_DEFINE_TYPE (Gih, gih, GIMP_TYPE_PLUG_IN)
|
|
|
|
GIMP_MAIN (GIH_TYPE)
|
|
DEFINE_STD_SET_I18N
|
|
|
|
|
|
static const gchar * const selection_modes[] = { "incremental",
|
|
"angular",
|
|
"random",
|
|
"velocity",
|
|
"pressure",
|
|
"xtilt",
|
|
"ytilt" };
|
|
|
|
|
|
static void
|
|
gih_class_init (GihClass *klass)
|
|
{
|
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
|
|
|
plug_in_class->query_procedures = gih_query_procedures;
|
|
plug_in_class->create_procedure = gih_create_procedure;
|
|
plug_in_class->set_i18n = STD_SET_I18N;
|
|
}
|
|
|
|
static void
|
|
gih_init (Gih *gih)
|
|
{
|
|
}
|
|
|
|
static GList *
|
|
gih_query_procedures (GimpPlugIn *plug_in)
|
|
{
|
|
return g_list_append (NULL, g_strdup (EXPORT_PROC));
|
|
}
|
|
|
|
static GimpProcedure *
|
|
gih_create_procedure (GimpPlugIn *plug_in,
|
|
const gchar *name)
|
|
{
|
|
GimpProcedure *procedure = NULL;
|
|
|
|
if (! strcmp (name, EXPORT_PROC))
|
|
{
|
|
procedure = gimp_export_procedure_new (plug_in, name,
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
FALSE, gih_export, NULL, NULL);
|
|
|
|
gimp_procedure_set_image_types (procedure, "RGB*, GRAY*");
|
|
|
|
gimp_procedure_set_menu_label (procedure, _("GIMP brush (animated)"));
|
|
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
|
_("Exports images in GIMP Brush Pipe "
|
|
"format"),
|
|
_("This plug-in exports an image in "
|
|
"the GIMP brush pipe format. For a "
|
|
"colored brush pipe, RGBA layers are "
|
|
"used, otherwise the layers should be "
|
|
"grayscale masks. The image can be "
|
|
"multi-layered, and additionally the "
|
|
"layers can be divided into a "
|
|
"rectangular array of brushes."),
|
|
EXPORT_PROC);
|
|
gimp_procedure_set_attribution (procedure,
|
|
"Tor Lillqvist",
|
|
"Tor Lillqvist",
|
|
"1999");
|
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
"image/x-gimp-gih");
|
|
gimp_file_procedure_set_format_name (GIMP_FILE_PROCEDURE (procedure),
|
|
_("Brush Pipe"));
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
"gih");
|
|
gimp_file_procedure_set_handles_remote (GIMP_FILE_PROCEDURE (procedure),
|
|
TRUE);
|
|
|
|
gimp_procedure_add_int_argument (procedure, "spacing",
|
|
_("Spacing (_percent)"),
|
|
_("Spacing of the brush"),
|
|
1, 1000, 20,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_string_argument (procedure, "description",
|
|
_("_Description"),
|
|
_("Short description of the GIH brush pipe"),
|
|
"GIMP Brush Pipe",
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int_argument (procedure, "cell-width",
|
|
_("Cell _width"),
|
|
_("Width of the brush cells in pixels"),
|
|
1, 1000, 1,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int_argument (procedure, "cell-height",
|
|
_("Cell _height"),
|
|
_("Height of the brush cells in pixels"),
|
|
1, 1000, 1,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int_argument (procedure, "num-cells",
|
|
_("_Number of cells"),
|
|
_("Number of cells to cut up"),
|
|
1, 1000, 1,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_bytes_argument (procedure, "ranks",
|
|
_("_Rank"),
|
|
_("Ranks of the dimensions"),
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_string_array_argument (procedure, "selection-modes",
|
|
_("Selection modes"),
|
|
_("Selection modes"),
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
/* Auxiliary arguments. Only useful for the GUI, to pass info around. */
|
|
|
|
gimp_procedure_add_string_aux_argument (procedure, "info-text",
|
|
_("Display as"),
|
|
_("Describe how the layers will be split"),
|
|
"", GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int_aux_argument (procedure, "dimension",
|
|
_("D_imension"),
|
|
_("How many dimensions the animated brush has"),
|
|
1, 1000, 1,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
gimp_procedure_add_int32_array_aux_argument (procedure, "guides",
|
|
"Guides",
|
|
"Guides to show how the layers will be split in cells",
|
|
GIMP_PARAM_READWRITE);
|
|
}
|
|
|
|
return procedure;
|
|
}
|
|
|
|
static GimpValueArray *
|
|
gih_export (GimpProcedure *procedure,
|
|
GimpRunMode run_mode,
|
|
GimpImage *image,
|
|
GFile *file,
|
|
GimpMetadata *metadata,
|
|
GimpProcedureConfig *config,
|
|
gpointer run_data)
|
|
{
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
GimpExportReturn export = GIMP_EXPORT_IGNORE;
|
|
GList *layers = NULL;
|
|
gint n_drawables;
|
|
GimpParasite *parasite;
|
|
GimpImage *orig_image;
|
|
GError *error = NULL;
|
|
|
|
GimpPixPipeParams gihparams = { 0, };
|
|
gchar *description = NULL;
|
|
gint spacing;
|
|
GBytes *rank_bytes;
|
|
const guint8 *rank;
|
|
gchar **selection;
|
|
|
|
orig_image = image;
|
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
{
|
|
GParamSpec *spec;
|
|
gint image_width;
|
|
gint image_height;
|
|
gint cell_width;
|
|
gint cell_height;
|
|
|
|
gimp_pixpipe_params_init (&gihparams);
|
|
|
|
/* Possibly retrieve data */
|
|
parasite = gimp_image_get_parasite (orig_image,
|
|
"gimp-brush-pipe-name");
|
|
if (parasite)
|
|
{
|
|
gchar *parasite_data;
|
|
guint32 parasite_size;
|
|
|
|
parasite_data = (gchar *) gimp_parasite_get_data (parasite, ¶site_size);
|
|
|
|
g_object_set (config, "description", parasite_data , NULL);
|
|
|
|
gimp_parasite_free (parasite);
|
|
}
|
|
else
|
|
{
|
|
gchar *name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
|
|
|
if (g_str_has_suffix (name, ".gih"))
|
|
name[strlen (name) - 4] = '\0';
|
|
|
|
if (strlen (name))
|
|
g_object_set (config, "description", name, NULL);
|
|
|
|
g_free (name);
|
|
}
|
|
|
|
parasite = gimp_image_get_parasite (orig_image,
|
|
"gimp-brush-pipe-parameters");
|
|
if (parasite)
|
|
{
|
|
gchar *parasite_data;
|
|
guint32 parasite_size;
|
|
|
|
parasite_data = (gchar *) gimp_parasite_get_data (parasite,
|
|
¶site_size);
|
|
parasite_data = g_strndup (parasite_data, parasite_size);
|
|
|
|
gimp_pixpipe_params_parse (parasite_data, &gihparams);
|
|
g_object_set (config,
|
|
"num-cells", gihparams.ncells,
|
|
"dimension", gihparams.dim,
|
|
"selection-modes", gihparams.selection,
|
|
NULL);
|
|
|
|
if (gihparams.dim > 0)
|
|
{
|
|
GBytes *ranks = NULL;
|
|
guint8 rank_int[gihparams.dim];
|
|
|
|
for (gint i = 0; i < gihparams.dim; i++)
|
|
rank_int[i] = (guint8) gihparams.rank[i];
|
|
|
|
ranks =
|
|
g_bytes_new (rank_int, sizeof (guint8) * gihparams.dim);
|
|
g_object_set (config, "ranks", ranks, NULL);
|
|
|
|
g_bytes_unref (ranks);
|
|
}
|
|
|
|
gimp_parasite_free (parasite);
|
|
g_free (parasite_data);
|
|
}
|
|
|
|
g_object_get (config,
|
|
"cell-width", &cell_width,
|
|
"cell-height", &cell_height,
|
|
NULL);
|
|
|
|
image_width = gimp_image_get_width (image);
|
|
image_height = gimp_image_get_height (image);
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-width");
|
|
G_PARAM_SPEC_INT (spec)->default_value = image_width;
|
|
G_PARAM_SPEC_INT (spec)->maximum = image_width;
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-height");
|
|
G_PARAM_SPEC_INT (spec)->default_value = image_height;
|
|
G_PARAM_SPEC_INT (spec)->maximum = image_height;
|
|
|
|
if (cell_width == 1 && cell_height == 1)
|
|
{
|
|
g_object_set (config,
|
|
"cell-width", image_width,
|
|
"cell-height", image_height,
|
|
NULL);
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "num-cells");
|
|
G_PARAM_SPEC_INT (spec)->maximum = 1;
|
|
}
|
|
|
|
gimp_ui_init (PLUG_IN_BINARY);
|
|
|
|
if (! gih_save_dialog (image, procedure, config))
|
|
{
|
|
status = GIMP_PDB_CANCEL;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
export = gimp_export_image (&image,
|
|
GIMP_EXPORT_CAN_HANDLE_RGB |
|
|
GIMP_EXPORT_CAN_HANDLE_GRAY |
|
|
GIMP_EXPORT_CAN_HANDLE_ALPHA |
|
|
GIMP_EXPORT_CAN_HANDLE_LAYERS);
|
|
layers = gimp_image_list_layers (image);
|
|
n_drawables = g_list_length (layers);
|
|
|
|
g_object_get (config,
|
|
"spacing", &spacing,
|
|
"description", &description,
|
|
"cell-width", &gihparams.cellwidth,
|
|
"cell-height", &gihparams.cellheight,
|
|
"num-cells", &gihparams.ncells,
|
|
"ranks", &rank_bytes,
|
|
"selection-modes", &selection,
|
|
NULL);
|
|
|
|
gihparams.cols = gimp_image_get_width (image) / gihparams.cellwidth;
|
|
gihparams.rows = gimp_image_get_height (image) / gihparams.cellheight;
|
|
|
|
rank = g_bytes_get_data (rank_bytes, NULL);
|
|
gihparams.dim = g_bytes_get_size (rank_bytes);
|
|
|
|
for (gint i = 0; i < gihparams.dim; i++)
|
|
{
|
|
gihparams.rank[i] = rank[i];
|
|
gihparams.selection[i] = g_strdup (selection[i]);
|
|
}
|
|
|
|
g_strfreev (selection);
|
|
g_bytes_unref (rank_bytes);
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
{
|
|
GimpProcedure *procedure;
|
|
GimpValueArray *save_retvals;
|
|
GimpDrawable **drawables = NULL;
|
|
GimpObjectArray *drawables_array;
|
|
GList *iter;
|
|
gint i;
|
|
gchar *paramstring;
|
|
|
|
paramstring = gimp_pixpipe_params_build (&gihparams);
|
|
|
|
drawables = g_new (GimpDrawable *, n_drawables);
|
|
for (iter = layers, i = 0; iter; iter = iter->next, i++)
|
|
drawables[i] = iter->data;
|
|
|
|
drawables_array = gimp_object_array_new (GIMP_TYPE_DRAWABLE, (GObject **) drawables,
|
|
n_drawables, FALSE);
|
|
procedure = gimp_pdb_lookup_procedure (gimp_get_pdb (),
|
|
"file-gih-export-internal");
|
|
save_retvals = gimp_procedure_run (procedure,
|
|
"image", image,
|
|
"num-drawables", n_drawables,
|
|
"drawables", drawables_array,
|
|
"file", file,
|
|
"spacing", spacing,
|
|
"name", description,
|
|
"params", paramstring,
|
|
NULL);
|
|
g_free (drawables);
|
|
gimp_object_array_free (drawables_array);
|
|
|
|
if (GIMP_VALUES_GET_ENUM (save_retvals, 0) == GIMP_PDB_SUCCESS)
|
|
{
|
|
parasite = gimp_parasite_new ("gimp-brush-pipe-name",
|
|
GIMP_PARASITE_PERSISTENT,
|
|
strlen (description) + 1,
|
|
description);
|
|
gimp_image_attach_parasite (orig_image, parasite);
|
|
gimp_parasite_free (parasite);
|
|
|
|
gimp_image_detach_parasite (image, "gimp-brush-pipe-parameters");
|
|
}
|
|
else
|
|
{
|
|
g_set_error (&error, 0, 0,
|
|
"Running procedure 'file-gih-export-internal' "
|
|
"failed: %s",
|
|
gimp_pdb_get_last_error (gimp_get_pdb ()));
|
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
|
|
g_free (paramstring);
|
|
}
|
|
|
|
gimp_pixpipe_params_free (&gihparams);
|
|
g_free (description);
|
|
|
|
out:
|
|
if (export == GIMP_EXPORT_EXPORT)
|
|
gimp_image_delete (image);
|
|
|
|
g_list_free (layers);
|
|
return gimp_procedure_new_return_values (procedure, status, error);
|
|
}
|
|
|
|
|
|
/* export routines */
|
|
|
|
static void
|
|
gih_remove_guides (GimpProcedureConfig *config,
|
|
GimpImage *image)
|
|
{
|
|
GimpArray *array;
|
|
|
|
g_object_get (config, "guides", &array, NULL);
|
|
|
|
if (array != NULL)
|
|
{
|
|
gint32 *guides = (gint32 *) array->data;
|
|
gint n_guides = array->length / 4;
|
|
|
|
for (gint i = 0; i < n_guides; i++)
|
|
gimp_image_delete_guide (image, guides[i]);
|
|
}
|
|
g_clear_pointer (&array, gimp_array_free);
|
|
|
|
g_object_set (config, "guides", NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
gih_cell_width_notify (GimpProcedureConfig *config,
|
|
const GParamSpec *pspec,
|
|
GimpProcedureDialog *dialog)
|
|
{
|
|
GimpImage *image;
|
|
GParamSpec *spec;
|
|
gchar *info_text;
|
|
gchar *grid_text = NULL;
|
|
const gchar *width_warning = _("Width Mismatch!");
|
|
gchar *height_warning = _("Height Mismatch!");
|
|
GtkWidget *widget;
|
|
GtkAdjustment *rank0;
|
|
gint dimension;
|
|
|
|
gint cell_width;
|
|
gint image_width;
|
|
gint n_horiz_cells;
|
|
gint n_vert_cells;
|
|
|
|
gint cell_height;
|
|
gint image_height;
|
|
gint n_vert_guides;
|
|
gint n_horiz_guides;
|
|
|
|
gint old_max_cells;
|
|
gint max_cells;
|
|
gint num_cells;
|
|
|
|
image = g_object_get_data (G_OBJECT (dialog), "image");
|
|
rank0 = g_object_get_data (G_OBJECT (dialog), "rank0");
|
|
|
|
g_object_get (config,
|
|
"cell-width", &cell_width,
|
|
"cell-height", &cell_height,
|
|
"num-cells", &num_cells,
|
|
"dimension", &dimension,
|
|
NULL);
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-width");
|
|
image_width = G_PARAM_SPEC_INT (spec)->maximum;
|
|
n_horiz_cells = image_width / cell_width;
|
|
n_vert_guides = n_horiz_cells - 1;
|
|
|
|
if (cell_width * n_horiz_cells == image_width)
|
|
width_warning = NULL;
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-height");
|
|
image_height = G_PARAM_SPEC_INT (spec)->maximum;
|
|
n_vert_cells = image_height / cell_height;
|
|
n_horiz_guides = n_vert_cells - 1;
|
|
|
|
if (cell_height * n_vert_cells == image_height)
|
|
height_warning = NULL;
|
|
|
|
/* TRANSLATORS: \xc3\x97 is the UTF-8 encoding for the multiplication sign. */
|
|
if (n_horiz_guides + n_vert_guides > 0)
|
|
grid_text = g_strdup_printf (_("Displays as a %d \xc3\x97 %d grid on each layer"),
|
|
n_horiz_cells, n_vert_cells);
|
|
info_text = g_strdup_printf ("%s%s%s%s%s",
|
|
grid_text != NULL ? grid_text : "",
|
|
grid_text != NULL && width_warning != NULL ? " / " : "",
|
|
width_warning != NULL ? width_warning : "",
|
|
(grid_text != NULL || width_warning != NULL) && height_warning != NULL ? " / " : "",
|
|
height_warning != NULL ? height_warning : "");
|
|
|
|
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "num-cells");
|
|
old_max_cells = G_PARAM_SPEC_INT (spec)->maximum;
|
|
max_cells = n_horiz_cells * n_vert_cells;
|
|
|
|
if (num_cells == old_max_cells)
|
|
num_cells = max_cells;
|
|
else
|
|
num_cells = MIN (max_cells, num_cells);
|
|
|
|
G_PARAM_SPEC_INT (spec)->maximum = max_cells;
|
|
widget = gimp_procedure_dialog_get_widget (dialog, "num-cells", G_TYPE_NONE);
|
|
g_object_set (widget, "upper", (gdouble) max_cells, NULL);
|
|
gimp_label_spin_set_increments (GIMP_LABEL_SPIN (widget), 1.0, 1.0);
|
|
|
|
gih_remove_guides (config, image);
|
|
|
|
widget = gimp_procedure_dialog_get_widget (dialog, "info-text", G_TYPE_NONE);
|
|
gtk_widget_set_visible (widget, (strlen (info_text) > 0));
|
|
if (n_horiz_guides + n_vert_guides > 0)
|
|
{
|
|
gint32 *guides = NULL;
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
guides = g_new0 (gint32, n_horiz_guides + n_vert_guides);
|
|
|
|
for (gint i = 0; i < n_vert_guides; i++)
|
|
guides[i] = gimp_image_add_vguide (image, cell_width * (i + 1));
|
|
|
|
for (gint i = 0; i < n_horiz_guides; i++)
|
|
guides[n_vert_guides + i] = gimp_image_add_hguide (image, cell_height * (i + 1));
|
|
|
|
g_value_init (&value, GIMP_TYPE_INT32_ARRAY);
|
|
gimp_value_set_int32_array (&value, guides, n_horiz_guides + n_vert_guides);
|
|
g_object_set_property (G_OBJECT (config), "guides", &value);
|
|
g_free (guides);
|
|
}
|
|
|
|
g_object_set (config,
|
|
"info-text", info_text,
|
|
"num-cells", num_cells,
|
|
NULL);
|
|
if (rank0 != NULL && dimension == 1)
|
|
gtk_adjustment_set_value (rank0, num_cells);
|
|
|
|
g_free (info_text);
|
|
g_free (grid_text);
|
|
}
|
|
|
|
static void
|
|
gih_selection_mode_changed (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint index;
|
|
|
|
index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
|
|
|
|
g_free (*((gchar **) data));
|
|
*((gchar **) data) = g_strdup (selection_modes [index]);
|
|
}
|
|
|
|
static void
|
|
gih_dimension_notify (GimpProcedureConfig *config,
|
|
const GParamSpec *pspec,
|
|
SizeAdjustmentData *data)
|
|
{
|
|
gint dimension;
|
|
gint i;
|
|
|
|
g_object_get (config, "dimension", &dimension, NULL);
|
|
|
|
for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
|
|
{
|
|
gtk_widget_set_sensitive (data->rank_entry[i], i < dimension);
|
|
gtk_widget_set_sensitive (data->mode_entry[i], i < dimension);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gih_save_dialog (GimpImage *image,
|
|
GimpProcedure *procedure,
|
|
GimpProcedureConfig *config)
|
|
{
|
|
GtkWidget *dialog;
|
|
GtkWidget *dimgrid;
|
|
GtkWidget *label;
|
|
GtkAdjustment *adjustment;
|
|
GtkWidget *spinbutton;
|
|
GtkWidget *cb;
|
|
gint i;
|
|
SizeAdjustmentData cellw_adjust;
|
|
SizeAdjustmentData cellh_adjust;
|
|
gchar **selection;
|
|
GBytes *rank_bytes = NULL;
|
|
guint8 rank[GIMP_PIXPIPE_MAXDIM];
|
|
gint num_cells;
|
|
gint dimension;
|
|
gboolean run;
|
|
|
|
dialog = gimp_export_procedure_dialog_new (GIMP_EXPORT_PROCEDURE (procedure),
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
image);
|
|
|
|
gtk_widget_set_halign (gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
|
|
"info-text", NULL, TRUE, FALSE),
|
|
GTK_ALIGN_START);
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
"description", "spacing",
|
|
"cell-width", "cell-height", "num-cells",
|
|
"info-text", "dimension", NULL);
|
|
|
|
g_object_set_data (G_OBJECT (dialog), "image", image);
|
|
g_signal_connect (config, "notify::cell-width",
|
|
G_CALLBACK (gih_cell_width_notify),
|
|
dialog);
|
|
g_signal_connect (config, "notify::cell-height",
|
|
G_CALLBACK (gih_cell_width_notify),
|
|
dialog);
|
|
gih_cell_width_notify (config, NULL, GIMP_PROCEDURE_DIALOG (dialog));
|
|
|
|
g_signal_connect (config, "notify::dimension",
|
|
G_CALLBACK (gih_dimension_notify),
|
|
&cellw_adjust);
|
|
|
|
/*
|
|
* Ranks / Selection: ______ ______ ______ ______ ______
|
|
*/
|
|
|
|
g_object_get (config,
|
|
"selection-modes", &selection,
|
|
"ranks", &rank_bytes,
|
|
"num-cells", &num_cells,
|
|
NULL);
|
|
if (selection == NULL || g_strv_length (selection) != GIMP_PIXPIPE_MAXDIM)
|
|
{
|
|
GStrvBuilder *builder = g_strv_builder_new ();
|
|
gint old_len;
|
|
|
|
old_len = (selection == NULL ? 0 : g_strv_length (selection));
|
|
|
|
for (i = 0; i < MIN (old_len, GIMP_PIXPIPE_MAXDIM); i++)
|
|
g_strv_builder_add (builder, selection[i]);
|
|
|
|
for (i = old_len; i < GIMP_PIXPIPE_MAXDIM; i++)
|
|
g_strv_builder_add (builder, "random");
|
|
|
|
g_strfreev (selection);
|
|
selection = g_strv_builder_end (builder);
|
|
g_strv_builder_unref (builder);
|
|
}
|
|
|
|
if (rank_bytes == NULL)
|
|
{
|
|
dimension = 1;
|
|
|
|
rank[0] = 1;
|
|
for (i = 1; i < GIMP_PIXPIPE_MAXDIM; i++)
|
|
rank[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
const guint8 *stored;
|
|
|
|
stored = g_bytes_get_data (rank_bytes, NULL);
|
|
dimension = g_bytes_get_size (rank_bytes);
|
|
|
|
for (i = 0; i < dimension; i++)
|
|
rank[i] = stored[i];
|
|
|
|
for (i = dimension; i < GIMP_PIXPIPE_MAXDIM; i++)
|
|
rank[i] = 1;
|
|
}
|
|
g_bytes_unref (rank_bytes);
|
|
dimension = MAX (dimension, 1);
|
|
|
|
dimgrid = gtk_grid_new ();
|
|
gtk_grid_set_column_spacing (GTK_GRID (dimgrid), 4);
|
|
|
|
label = gtk_label_new (_("Ranks:"));
|
|
gtk_grid_attach (GTK_GRID (dimgrid), label, 0, 0, 1, 1);
|
|
gtk_widget_show (label);
|
|
|
|
for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
|
|
{
|
|
gsize j;
|
|
|
|
adjustment = gtk_adjustment_new (rank[i], 1, 100, 1, 1, 0);
|
|
if (i == 0)
|
|
g_object_set_data (G_OBJECT (dialog), "rank0", adjustment);
|
|
|
|
spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
|
|
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
|
|
gtk_grid_attach (GTK_GRID (dimgrid), spinbutton, 1, i, 1, 1);
|
|
|
|
gtk_widget_show (spinbutton);
|
|
|
|
if (i >= dimension)
|
|
gtk_widget_set_sensitive (spinbutton, FALSE);
|
|
|
|
g_signal_connect (adjustment, "value-changed",
|
|
G_CALLBACK (gimp_int_adjustment_update),
|
|
&rank[i]);
|
|
|
|
cellw_adjust.rank_entry[i] = cellh_adjust.rank_entry[i] = spinbutton;
|
|
|
|
cb = gtk_combo_box_text_new ();
|
|
|
|
for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb),
|
|
selection_modes[j]);
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 2); /* random */
|
|
|
|
for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
|
|
if (!strcmp (selection[i], selection_modes[j]))
|
|
{
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (cb), j);
|
|
break;
|
|
}
|
|
|
|
gtk_grid_attach (GTK_GRID (dimgrid), cb, 2, i, 1, 1);
|
|
|
|
gtk_widget_show (cb);
|
|
|
|
if (i >= dimension)
|
|
gtk_widget_set_sensitive (cb, FALSE);
|
|
|
|
g_signal_connect (GTK_COMBO_BOX (cb), "changed",
|
|
G_CALLBACK (gih_selection_mode_changed),
|
|
&selection[i]);
|
|
|
|
cellw_adjust.mode_entry[i] = cellh_adjust.mode_entry[i] = cb;
|
|
}
|
|
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
|
dimgrid, TRUE, TRUE, 0);
|
|
gtk_widget_show (dimgrid);
|
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
|
|
|
g_object_get (config, "dimension", &dimension, NULL);
|
|
rank_bytes = g_bytes_new (rank, sizeof (guint8) * dimension);
|
|
|
|
g_object_set (config,
|
|
"selection-modes", selection,
|
|
"ranks", rank_bytes,
|
|
NULL);
|
|
|
|
gih_remove_guides (config, image);
|
|
gtk_widget_destroy (dialog);
|
|
|
|
g_strfreev (selection);
|
|
g_bytes_unref (rank_bytes);
|
|
|
|
return run;
|
|
}
|