1 /* Plug-in to load and export .gih (GIMP Brush Pipe) files.
2 *
3 * Copyright (C) 1999 Tor Lillqvist
4 * Copyright (C) 2000 Jens Lautenbacher, Sven Neumann
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 /* Example of how to call file_gih_save from script-fu:
21
22 (let ((ranks (cons-array 1 'byte)))
23 (aset ranks 0 12)
24 (file-gih-save 1
25 img
26 drawable
27 "foo.gih"
28 "foo.gih"
29 100
30 "test brush"
31 125
32 125
33 3
34 4
35 1
36 ranks
37 1
38 '("random")))
39 */
40
41
42 #include "config.h"
43
44 #include <libgimp/gimp.h>
45 #include <libgimp/gimpui.h>
46 #include <libgimpbase/gimpparasiteio.h>
47
48 #include "libgimp/stdplugins-intl.h"
49
50
51 #define SAVE_PROC "file-gih-save"
52 #define PLUG_IN_BINARY "file-gih"
53 #define PLUG_IN_ROLE "gimp-file-gih"
54
55
56 /* Parameters applicable each time we export a gih, exported in the
57 * main gimp application between invocations of this plug-in.
58 */
59 typedef struct
60 {
61 gchar description[256];
62 gint spacing;
63 } BrushInfo;
64
65 typedef struct
66 {
67 GimpOrientationType orientation;
68 gint32 image;
69 gint32 toplayer;
70 gint nguides;
71 gint32 *guides;
72 gint *value;
73 GtkWidget *count_label; /* Corresponding count adjustment, */
74 gint *count; /* cols or rows */
75 gint *other_count; /* and the other one */
76 GtkAdjustment *ncells;
77 GtkAdjustment *rank0;
78 GtkWidget *warning_label;
79 GtkWidget *rank_entry[GIMP_PIXPIPE_MAXDIM];
80 GtkWidget *mode_entry[GIMP_PIXPIPE_MAXDIM];
81 } SizeAdjustmentData;
82
83
84 /* local function prototypes */
85
86 static void query (void);
87 static void run (const gchar *name,
88 gint nparams,
89 const GimpParam *param,
90 gint *nreturn_vals,
91 GimpParam **return_vals);
92
93 static gboolean gih_save_dialog (gint32 image_ID);
94
95
96 /* private variables */
97
98 const GimpPlugInInfo PLUG_IN_INFO =
99 {
100 NULL, /* init_proc */
101 NULL, /* quit_proc */
102 query, /* query_proc */
103 run, /* run_proc */
104 };
105
106 static BrushInfo info =
107 {
108 "GIMP Brush Pipe",
109 20
110 };
111
112 static gint num_layers = 0;
113 static GimpPixPipeParams gihparams = { 0, };
114
115 static const gchar * const selection_modes[] = { "incremental",
116 "angular",
117 "random",
118 "velocity",
119 "pressure",
120 "xtilt",
121 "ytilt" };
122
123
MAIN()124 MAIN ()
125
126 static void
127 query (void)
128 {
129 static const GimpParamDef gih_save_args[] =
130 {
131 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
132 { GIMP_PDB_IMAGE, "image", "Input image" },
133 { GIMP_PDB_DRAWABLE, "drawable", "Drawable to export" },
134 { GIMP_PDB_STRING, "uri", "The URI of the file to export the brush pipe in" },
135 { GIMP_PDB_STRING, "raw-uri", "The URI of the file to export the brush pipe in" },
136 { GIMP_PDB_INT32, "spacing", "Spacing of the brush" },
137 { GIMP_PDB_STRING, "description", "Short description of the brush pipe" },
138 { GIMP_PDB_INT32, "cell-width", "Width of the brush cells" },
139 { GIMP_PDB_INT32, "cell-height", "Width of the brush cells" },
140 { GIMP_PDB_INT8, "display-cols", "Display column number" },
141 { GIMP_PDB_INT8, "display-rows", "Display row number" },
142 { GIMP_PDB_INT32, "dimension", "Dimension of the brush pipe" },
143 /* The number of rank and sel args depend on the dimension */
144 { GIMP_PDB_INT8ARRAY, "rank", "Ranks of the dimensions" },
145 { GIMP_PDB_INT32, "dimension", "Dimension (again)" },
146 { GIMP_PDB_STRINGARRAY, "sel", "Selection modes" }
147 };
148
149 gimp_install_procedure (SAVE_PROC,
150 "exports images in GIMP brush pipe format",
151 "This plug-in exports an image in the GIMP brush pipe "
152 "format. For a colored brush pipe, RGBA layers are "
153 "used, otherwise the layers should be grayscale "
154 "masks. The image can be multi-layered, and "
155 "additionally the layers can be divided into a "
156 "rectangular array of brushes.",
157 "Tor Lillqvist",
158 "Tor Lillqvist",
159 "1999",
160 N_("GIMP brush (animated)"),
161 "RGB*, GRAY*",
162 GIMP_PLUGIN,
163 G_N_ELEMENTS (gih_save_args), 0,
164 gih_save_args, NULL);
165
166 gimp_plugin_icon_register (SAVE_PROC, GIMP_ICON_TYPE_ICON_NAME,
167 (const guint8 *) GIMP_ICON_BRUSH);
168 gimp_register_file_handler_mime (SAVE_PROC, "image/x-gimp-gih");
169 gimp_register_file_handler_uri (SAVE_PROC);
170 gimp_register_save_handler (SAVE_PROC, "gih", "");
171 }
172
173 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)174 run (const gchar *name,
175 gint nparams,
176 const GimpParam *param,
177 gint *nreturn_vals,
178 GimpParam **return_vals)
179 {
180 static GimpParam values[2];
181 GimpRunMode run_mode;
182 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
183 gint32 image_ID;
184 gint32 drawable_ID;
185 GimpExportReturn export = GIMP_EXPORT_CANCEL;
186 GError *error = NULL;
187 gint i;
188
189 INIT_I18N();
190
191 run_mode = param[0].data.d_int32;
192
193 *return_vals = values;
194 *nreturn_vals = 1;
195
196 values[0].type = GIMP_PDB_STATUS;
197 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
198
199 if (strcmp (name, SAVE_PROC) == 0)
200 {
201 GFile *file;
202 GimpParasite *parasite;
203 gint32 orig_image_ID;
204
205 image_ID = param[1].data.d_int32;
206 drawable_ID = param[2].data.d_int32;
207 file = g_file_new_for_uri (param[3].data.d_string);
208
209 orig_image_ID = image_ID;
210
211 switch (run_mode)
212 {
213 case GIMP_RUN_INTERACTIVE:
214 case GIMP_RUN_WITH_LAST_VALS:
215 gimp_ui_init (PLUG_IN_BINARY, FALSE);
216
217 export = gimp_export_image (&image_ID, &drawable_ID, "GIH",
218 GIMP_EXPORT_CAN_HANDLE_RGB |
219 GIMP_EXPORT_CAN_HANDLE_GRAY |
220 GIMP_EXPORT_CAN_HANDLE_ALPHA |
221 GIMP_EXPORT_CAN_HANDLE_LAYERS);
222
223 if (export == GIMP_EXPORT_CANCEL)
224 {
225 values[0].data.d_status = GIMP_PDB_CANCEL;
226 return;
227 }
228
229 /* Possibly retrieve data */
230 gimp_get_data (SAVE_PROC, &info);
231
232 parasite = gimp_image_get_parasite (orig_image_ID,
233 "gimp-brush-pipe-name");
234 if (parasite)
235 {
236 strncpy (info.description,
237 gimp_parasite_data (parasite),
238 MIN (sizeof (info.description),
239 gimp_parasite_data_size (parasite)));
240 info.description[sizeof (info.description) - 1] = '\0';
241
242 gimp_parasite_free (parasite);
243 }
244 else
245 {
246 gchar *name = g_path_get_basename (gimp_file_get_utf8_name (file));
247
248 if (g_str_has_suffix (name, ".gih"))
249 name[strlen (name) - 4] = '\0';
250
251 if (strlen (name))
252 {
253 strncpy (info.description, name, sizeof (info.description));
254 info.description[sizeof (info.description) - 1] = '\0';
255 }
256
257 g_free (name);
258 }
259
260 parasite = gimp_image_get_parasite (orig_image_ID,
261 "gimp-brush-pipe-spacing");
262 if (parasite)
263 {
264 info.spacing = atoi (gimp_parasite_data (parasite));
265 gimp_parasite_free (parasite);
266 }
267 break;
268
269 default:
270 break;
271 }
272
273 g_free (gimp_image_get_layers (image_ID, &num_layers));
274
275 gimp_pixpipe_params_init (&gihparams);
276
277 switch (run_mode)
278 {
279 case GIMP_RUN_INTERACTIVE:
280 gihparams.ncells = (num_layers * gihparams.rows * gihparams.cols);
281
282 gihparams.cellwidth = gimp_image_width (image_ID) / gihparams.cols;
283 gihparams.cellheight = gimp_image_height (image_ID) / gihparams.rows;
284
285 parasite = gimp_image_get_parasite (orig_image_ID,
286 "gimp-brush-pipe-parameters");
287 if (parasite)
288 {
289 gimp_pixpipe_params_parse (gimp_parasite_data (parasite),
290 &gihparams);
291 gimp_parasite_free (parasite);
292 }
293
294 /* Force default rank to same as number of cells if there is
295 * just one dim
296 */
297 if (gihparams.dim == 1)
298 gihparams.rank[0] = gihparams.ncells;
299
300 if (! gih_save_dialog (image_ID))
301 status = GIMP_PDB_CANCEL;
302 break;
303
304 case GIMP_RUN_NONINTERACTIVE:
305 if (nparams != 15)
306 {
307 status = GIMP_PDB_CALLING_ERROR;
308 }
309 else
310 {
311 info.spacing = param[5].data.d_int32;
312 strncpy (info.description, param[6].data.d_string,
313 sizeof (info.description));
314 info.description[sizeof (info.description) - 1] = '\0';
315
316 gihparams.cellwidth = param[7].data.d_int32;
317 gihparams.cellheight = param[8].data.d_int32;
318 gihparams.cols = param[9].data.d_int8;
319 gihparams.rows = param[10].data.d_int8;
320 gihparams.dim = param[11].data.d_int32;
321 gihparams.ncells = 1;
322
323 if (param[13].data.d_int32 != gihparams.dim)
324 {
325 status = GIMP_PDB_CALLING_ERROR;
326 }
327 else
328 {
329 for (i = 0; i < gihparams.dim; i++)
330 {
331 gihparams.rank[i] = param[12].data.d_int8array[i];
332 gihparams.selection[i] = g_strdup (param[14].data.d_stringarray[i]);
333 gihparams.ncells *= gihparams.rank[i];
334 }
335 }
336 }
337 break;
338
339 case GIMP_RUN_WITH_LAST_VALS:
340 parasite = gimp_image_get_parasite (orig_image_ID,
341 "gimp-brush-pipe-parameters");
342 if (parasite)
343 {
344 gimp_pixpipe_params_parse (gimp_parasite_data (parasite),
345 &gihparams);
346 gimp_parasite_free (parasite);
347 }
348 break;
349 }
350
351 if (status == GIMP_PDB_SUCCESS)
352 {
353 GimpParam *save_retvals;
354 gint n_save_retvals;
355 gchar spacing[8];
356 gchar *paramstring;
357
358 paramstring = gimp_pixpipe_params_build (&gihparams);
359
360 save_retvals =
361 gimp_run_procedure ("file-gih-save-internal",
362 &n_save_retvals,
363 GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
364 GIMP_PDB_IMAGE, image_ID,
365 GIMP_PDB_DRAWABLE, drawable_ID,
366 GIMP_PDB_STRING, param[3].data.d_string,
367 GIMP_PDB_STRING, param[4].data.d_string,
368 GIMP_PDB_INT32, info.spacing,
369 GIMP_PDB_STRING, info.description,
370 GIMP_PDB_STRING, paramstring,
371 GIMP_PDB_END);
372
373 if (save_retvals[0].data.d_status == GIMP_PDB_SUCCESS)
374 {
375 gimp_set_data (SAVE_PROC, &info, sizeof (info));
376
377 parasite = gimp_parasite_new ("gimp-brush-pipe-name",
378 GIMP_PARASITE_PERSISTENT,
379 strlen (info.description) + 1,
380 info.description);
381 gimp_image_attach_parasite (orig_image_ID, parasite);
382 gimp_parasite_free (parasite);
383
384 g_snprintf (spacing, sizeof (spacing), "%d",
385 info.spacing);
386
387 parasite = gimp_parasite_new ("gimp-brush-pipe-spacing",
388 GIMP_PARASITE_PERSISTENT,
389 strlen (spacing) + 1, spacing);
390 gimp_image_attach_parasite (orig_image_ID, parasite);
391 gimp_parasite_free (parasite);
392
393 parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
394 GIMP_PARASITE_PERSISTENT,
395 strlen (paramstring) + 1,
396 paramstring);
397 gimp_image_attach_parasite (orig_image_ID, parasite);
398 gimp_parasite_free (parasite);
399 }
400 else
401 {
402 g_set_error (&error, 0, 0,
403 "Running procedure 'file-gih-save-internal' "
404 "failed: %s",
405 gimp_get_pdb_error ());
406
407 status = GIMP_PDB_EXECUTION_ERROR;
408 }
409
410 g_free (paramstring);
411 }
412
413 gimp_pixpipe_params_free (&gihparams);
414
415 if (export == GIMP_EXPORT_EXPORT)
416 gimp_image_delete (image_ID);
417 }
418 else
419 {
420 status = GIMP_PDB_CALLING_ERROR;
421 }
422
423 if (status != GIMP_PDB_SUCCESS && error)
424 {
425 *nreturn_vals = 2;
426 values[1].type = GIMP_PDB_STRING;
427 values[1].data.d_string = error->message;
428 }
429
430 values[0].data.d_status = status;
431 }
432
433
434 /* save routines */
435
436 static void
size_adjustment_callback(GtkWidget * widget,SizeAdjustmentData * adj)437 size_adjustment_callback (GtkWidget *widget,
438 SizeAdjustmentData *adj)
439 {
440 gint i;
441 gint size;
442 gint newn;
443 gchar buf[10];
444
445 for (i = 0; i < adj->nguides; i++)
446 gimp_image_delete_guide (adj->image, adj->guides[i]);
447
448 g_free (adj->guides);
449 adj->guides = NULL;
450 gimp_displays_flush ();
451
452 *(adj->value) = gtk_adjustment_get_value (GTK_ADJUSTMENT (widget));
453
454 if (adj->orientation == GIMP_ORIENTATION_VERTICAL)
455 {
456 size = gimp_image_width (adj->image);
457 newn = size / *(adj->value);
458 adj->nguides = newn - 1;
459 adj->guides = g_new (gint32, adj->nguides);
460 for (i = 0; i < adj->nguides; i++)
461 adj->guides[i] = gimp_image_add_vguide (adj->image,
462 *(adj->value) * (i+1));
463 }
464 else
465 {
466 size = gimp_image_height (adj->image);
467 newn = size / *(adj->value);
468 adj->nguides = newn - 1;
469 adj->guides = g_new (gint32, adj->nguides);
470 for (i = 0; i < adj->nguides; i++)
471 adj->guides[i] = gimp_image_add_hguide (adj->image,
472 *(adj->value) * (i+1));
473 }
474 gimp_displays_flush ();
475 g_snprintf (buf, sizeof (buf), "%2d", newn);
476 gtk_label_set_text (GTK_LABEL (adj->count_label), buf);
477
478 *(adj->count) = newn;
479
480 gtk_widget_set_visible (GTK_WIDGET (adj->warning_label),
481 newn * *(adj->value) != size);
482
483 if (adj->ncells != NULL)
484 gtk_adjustment_set_value (GTK_ADJUSTMENT (adj->ncells),
485 *(adj->other_count) * *(adj->count));
486 if (adj->rank0 != NULL)
487 gtk_adjustment_set_value (GTK_ADJUSTMENT (adj->rank0),
488 *(adj->other_count) * *(adj->count));
489 }
490
491 static void
entry_callback(GtkWidget * widget,gpointer data)492 entry_callback (GtkWidget *widget,
493 gpointer data)
494 {
495 if (data == info.description)
496 {
497 strncpy (info.description, gtk_entry_get_text (GTK_ENTRY (widget)),
498 sizeof (info.description));
499 info.description[sizeof (info.description) - 1] = 0;
500 }
501 }
502
503 static void
cb_callback(GtkWidget * widget,gpointer data)504 cb_callback (GtkWidget *widget,
505 gpointer data)
506 {
507 gint index;
508
509 index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
510
511 *((const gchar **) data) = selection_modes [index];
512 }
513
514 static void
dim_callback(GtkAdjustment * adjustment,SizeAdjustmentData * data)515 dim_callback (GtkAdjustment *adjustment,
516 SizeAdjustmentData *data)
517 {
518 gint i;
519
520 gihparams.dim = RINT (gtk_adjustment_get_value (adjustment));
521
522 for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
523 {
524 gtk_widget_set_sensitive (data->rank_entry[i], i < gihparams.dim);
525 gtk_widget_set_sensitive (data->mode_entry[i], i < gihparams.dim);
526 }
527 }
528
529 static gboolean
gih_save_dialog(gint32 image_ID)530 gih_save_dialog (gint32 image_ID)
531 {
532 GtkWidget *dialog;
533 GtkWidget *table;
534 GtkWidget *dimtable;
535 GtkWidget *label;
536 GtkAdjustment *adjustment;
537 GtkWidget *spinbutton;
538 GtkWidget *entry;
539 GtkWidget *box;
540 GtkWidget *cb;
541 gint i;
542 gchar buffer[100];
543 SizeAdjustmentData cellw_adjust;
544 SizeAdjustmentData cellh_adjust;
545 gint32 *layer_ID;
546 gint32 nlayers;
547 gboolean run;
548
549 dialog = gimp_export_dialog_new (_("Brush Pipe"), PLUG_IN_BINARY, SAVE_PROC);
550
551 /* The main table */
552 table = gtk_table_new (8, 2, FALSE);
553 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
554 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
555 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
556 gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
557 table, TRUE, TRUE, 0);
558 gtk_widget_show (table);
559
560 /*
561 * Description: ___________
562 */
563 entry = gtk_entry_new ();
564 gtk_widget_set_size_request (entry, 200, -1);
565 gtk_entry_set_text (GTK_ENTRY (entry), info.description);
566 gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
567 _("_Description:"), 0.0, 0.5,
568 entry, 1, FALSE);
569
570 g_signal_connect (entry, "changed",
571 G_CALLBACK (entry_callback),
572 info.description);
573
574 /*
575 * Spacing: __
576 */
577 adjustment = (GtkAdjustment *) gtk_adjustment_new (info.spacing,
578 1, 1000, 1, 10, 0);
579 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
580 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
581 gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
582 _("_Spacing (percent):"), 0.0, 0.5,
583 spinbutton, 1, TRUE);
584
585 g_signal_connect (adjustment, "value-changed",
586 G_CALLBACK (gimp_int_adjustment_update),
587 &info.spacing);
588
589 /*
590 * Cell size: __ x __ pixels
591 */
592 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
593
594 adjustment = (GtkAdjustment *)
595 gtk_adjustment_new (gihparams.cellwidth,
596 2, gimp_image_width (image_ID), 1, 10, 0);
597 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
598 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
599 gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, FALSE, 0);
600 gtk_widget_show (spinbutton);
601
602 layer_ID = gimp_image_get_layers (image_ID, &nlayers);
603 cellw_adjust.orientation = GIMP_ORIENTATION_VERTICAL;
604 cellw_adjust.image = image_ID;
605 cellw_adjust.toplayer = layer_ID[nlayers-1];
606 cellw_adjust.nguides = 0;
607 cellw_adjust.guides = NULL;
608 cellw_adjust.value = &gihparams.cellwidth;
609
610 g_signal_connect (adjustment, "value-changed",
611 G_CALLBACK (size_adjustment_callback),
612 &cellw_adjust);
613
614 label = gtk_label_new ("x");
615 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
616 gtk_widget_show (label);
617
618 adjustment = (GtkAdjustment *)
619 gtk_adjustment_new (gihparams.cellheight,
620 2, gimp_image_height (image_ID), 1, 10, 0);
621 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
622 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
623 gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, FALSE, 0);
624 gtk_widget_show (spinbutton);
625
626 cellh_adjust.orientation = GIMP_ORIENTATION_HORIZONTAL;
627 cellh_adjust.image = image_ID;
628 cellh_adjust.toplayer = layer_ID[nlayers-1];
629 cellh_adjust.nguides = 0;
630 cellh_adjust.guides = NULL;
631 cellh_adjust.value = &gihparams.cellheight;
632
633 g_signal_connect (adjustment, "value-changed",
634 G_CALLBACK (size_adjustment_callback),
635 &cellh_adjust);
636
637 label = gtk_label_new ( _("Pixels"));
638 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
639 gtk_widget_show (label);
640
641 gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
642 _("Ce_ll size:"), 0.0, 0.5,
643 box, 1, FALSE);
644
645 g_free (layer_ID);
646
647 /*
648 * Number of cells: ___
649 */
650 adjustment = (GtkAdjustment *)
651 gtk_adjustment_new (gihparams.ncells, 1, 1000, 1, 10, 0);
652 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
653 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
654 gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
655 _("_Number of cells:"), 0.0, 0.5,
656 spinbutton, 1, TRUE);
657
658 g_signal_connect (adjustment, "value-changed",
659 G_CALLBACK (gimp_int_adjustment_update),
660 &gihparams.ncells);
661
662 if (gihparams.dim == 1)
663 cellw_adjust.ncells = cellh_adjust.ncells = adjustment;
664 else
665 cellw_adjust.ncells = cellh_adjust.ncells = NULL;
666
667 /*
668 * Display as: __ rows x __ cols
669 */
670 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
671
672 g_snprintf (buffer, sizeof (buffer), "%2d", gihparams.rows);
673 label = gtk_label_new (buffer);
674 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
675 cellh_adjust.count_label = label;
676 cellh_adjust.count = &gihparams.rows;
677 cellh_adjust.other_count = &gihparams.cols;
678 gtk_widget_show (label);
679
680 label = gtk_label_new (_(" Rows of "));
681 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
682 gtk_widget_show (label);
683
684 g_snprintf (buffer, sizeof (buffer), "%2d", gihparams.cols);
685 label = gtk_label_new (buffer);
686 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
687 cellw_adjust.count_label = label;
688 cellw_adjust.count = &gihparams.cols;
689 cellw_adjust.other_count = &gihparams.rows;
690 gtk_widget_show (label);
691
692 label = gtk_label_new (_(" Columns on each layer"));
693 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
694 gtk_widget_show (label);
695
696 label = gtk_label_new (_(" (Width Mismatch!) "));
697 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
698 cellw_adjust.warning_label = label;
699
700 label = gtk_label_new (_(" (Height Mismatch!) "));
701 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
702 cellh_adjust.warning_label = label;
703
704 gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
705 _("Display as:"), 0.0, 0.5,
706 box, 1, FALSE);
707
708 /*
709 * Dimension: ___
710 */
711 adjustment = (GtkAdjustment *)
712 gtk_adjustment_new (gihparams.dim, 1, GIMP_PIXPIPE_MAXDIM, 1, 1, 0);
713 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
714 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
715 gimp_table_attach_aligned (GTK_TABLE (table), 0, 5,
716 _("Di_mension:"), 0.0, 0.5,
717 spinbutton, 1, TRUE);
718
719 g_signal_connect (adjustment, "value-changed",
720 G_CALLBACK (dim_callback),
721 &cellw_adjust);
722
723 /*
724 * Ranks / Selection: ______ ______ ______ ______ ______
725 */
726
727 dimtable = gtk_table_new (2, GIMP_PIXPIPE_MAXDIM, FALSE);
728 gtk_table_set_col_spacings (GTK_TABLE (dimtable), 4);
729 for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
730 {
731 gint j;
732
733 adjustment = (GtkAdjustment *)
734 gtk_adjustment_new (gihparams.rank[i], 1, 100, 1, 1, 0);
735 spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
736 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
737 gtk_table_attach (GTK_TABLE (dimtable), spinbutton, 0, 1, i, i + 1,
738 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
739
740 gtk_widget_show (spinbutton);
741
742 if (i >= gihparams.dim)
743 gtk_widget_set_sensitive (spinbutton, FALSE);
744
745 g_signal_connect (adjustment, "value-changed",
746 G_CALLBACK (gimp_int_adjustment_update),
747 &gihparams.rank[i]);
748
749 cellw_adjust.rank_entry[i] = cellh_adjust.rank_entry[i] = spinbutton;
750
751 if (i == 0)
752 {
753 if (gihparams.dim == 1)
754 cellw_adjust.rank0 = cellh_adjust.rank0 = adjustment;
755 else
756 cellw_adjust.rank0 = cellh_adjust.rank0 = NULL;
757 }
758
759 cb = gtk_combo_box_text_new ();
760
761 for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
762 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb),
763 selection_modes[j]);
764 gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 2); /* random */
765
766 if (gihparams.selection[i])
767 for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
768 if (!strcmp (gihparams.selection[i], selection_modes[j]))
769 {
770 gtk_combo_box_set_active (GTK_COMBO_BOX (cb), j);
771 break;
772 }
773
774 gtk_table_attach (GTK_TABLE (dimtable), cb, 1, 2, i, i + 1,
775 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
776
777 gtk_widget_show (cb);
778
779 if (i >= gihparams.dim)
780 gtk_widget_set_sensitive (cb, FALSE);
781
782 g_signal_connect (GTK_COMBO_BOX (cb), "changed",
783 G_CALLBACK (cb_callback),
784 &gihparams.selection[i]);
785
786 cellw_adjust.mode_entry[i] = cellh_adjust.mode_entry[i] = cb;
787
788
789 }
790
791 gimp_table_attach_aligned (GTK_TABLE (table), 0, 6,
792 _("Ranks:"), 0.0, 0.0,
793 dimtable, 1, FALSE);
794
795 gtk_widget_show (dialog);
796
797 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
798
799 if (run)
800 {
801 gint i;
802
803 for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
804 gihparams.selection[i] = g_strdup (gihparams.selection[i]);
805
806 /* Fix up bogus values */
807 gihparams.ncells = MIN (gihparams.ncells,
808 num_layers * gihparams.rows * gihparams.cols);
809 }
810
811 gtk_widget_destroy (dialog);
812
813 for (i = 0; i < cellw_adjust.nguides; i++)
814 gimp_image_delete_guide (image_ID, cellw_adjust.guides[i]);
815 for (i = 0; i < cellh_adjust.nguides; i++)
816 gimp_image_delete_guide (image_ID, cellh_adjust.guides[i]);
817
818 return run;
819 }
820