1 /**********************************************************************
2 GIMP - The GNU Image Manipulation Program
3 Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *********************************************************************/
18
19 #include "config.h"
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <glib/gstdio.h>
26
27 #include <libgimp/gimp.h>
28 #include <libgimp/gimpui.h>
29
30 #include "fractal-explorer.h"
31 #include "fractal-explorer-dialogs.h"
32
33 #include "libgimp/stdplugins-intl.h"
34
35
36 #define ZOOM_UNDO_SIZE 100
37
38
39 static gint n_gradient_samples = 0;
40 static gdouble *gradient_samples = NULL;
41 static gchar *gradient_name = NULL;
42 static gboolean ready_now = FALSE;
43 static gchar *tpath = NULL;
44 static DialogElements *elements = NULL;
45 static GtkWidget *cmap_preview;
46 static GtkWidget *maindlg;
47
48 static explorer_vals_t zooms[ZOOM_UNDO_SIZE];
49 static gint zoomindex = 0;
50 static gint zoommax = 0;
51
52 static gint oldxpos = -1;
53 static gint oldypos = -1;
54 static gdouble x_press = -1.0;
55 static gdouble y_press = -1.0;
56
57 static explorer_vals_t standardvals =
58 {
59 0,
60 -2.0,
61 2.0,
62 -1.5,
63 1.5,
64 50.0,
65 -0.75,
66 -0.2,
67 0,
68 1.0,
69 1.0,
70 1.0,
71 1,
72 1,
73 0,
74 0,
75 0,
76 0,
77 1,
78 256,
79 0
80 };
81
82 /**********************************************************************
83 FORWARD DECLARATIONS
84 *********************************************************************/
85
86 static void load_file_chooser_response (GtkFileChooser *chooser,
87 gint response_id,
88 gpointer data);
89 static void save_file_chooser_response (GtkFileChooser *chooser,
90 gint response_id,
91 gpointer data);
92 static void create_load_file_chooser (GtkWidget *widget,
93 GtkWidget *dialog);
94 static void create_save_file_chooser (GtkWidget *widget,
95 GtkWidget *dialog);
96
97 static void cmap_preview_size_allocate (GtkWidget *widget,
98 GtkAllocation *allocation);
99
100 /**********************************************************************
101 CALLBACKS
102 *********************************************************************/
103
104 static void
dialog_response(GtkWidget * widget,gint response_id,gpointer data)105 dialog_response (GtkWidget *widget,
106 gint response_id,
107 gpointer data)
108 {
109 switch (response_id)
110 {
111 case GTK_RESPONSE_OK:
112 wint.run = TRUE;
113 gtk_widget_destroy (widget);
114 break;
115
116 default:
117 gtk_widget_destroy (widget);
118 break;
119 }
120 }
121
122 static void
dialog_reset_callback(GtkWidget * widget,gpointer data)123 dialog_reset_callback (GtkWidget *widget,
124 gpointer data)
125 {
126 wvals.xmin = standardvals.xmin;
127 wvals.xmax = standardvals.xmax;
128 wvals.ymin = standardvals.ymin;
129 wvals.ymax = standardvals.ymax;
130 wvals.iter = standardvals.iter;
131 wvals.cx = standardvals.cx;
132 wvals.cy = standardvals.cy;
133
134 dialog_change_scale ();
135 set_cmap_preview ();
136 dialog_update_preview ();
137 }
138
139 static void
dialog_redraw_callback(GtkWidget * widget,gpointer data)140 dialog_redraw_callback (GtkWidget *widget,
141 gpointer data)
142 {
143 gint alwaysprev = wvals.alwayspreview;
144
145 wvals.alwayspreview = TRUE;
146 set_cmap_preview ();
147 dialog_update_preview ();
148 wvals.alwayspreview = alwaysprev;
149 }
150
151 static void
dialog_undo_zoom_callback(GtkWidget * widget,gpointer data)152 dialog_undo_zoom_callback (GtkWidget *widget,
153 gpointer data)
154 {
155 if (zoomindex > 0)
156 {
157 zooms[zoomindex] = wvals;
158 zoomindex--;
159 wvals = zooms[zoomindex];
160 dialog_change_scale ();
161 set_cmap_preview ();
162 dialog_update_preview ();
163 }
164 }
165
166 static void
dialog_redo_zoom_callback(GtkWidget * widget,gpointer data)167 dialog_redo_zoom_callback (GtkWidget *widget,
168 gpointer data)
169 {
170 if (zoomindex < zoommax)
171 {
172 zoomindex++;
173 wvals = zooms[zoomindex];
174 dialog_change_scale ();
175 set_cmap_preview ();
176 dialog_update_preview ();
177 }
178 }
179
180 static void
dialog_step_in_callback(GtkWidget * widget,gpointer data)181 dialog_step_in_callback (GtkWidget *widget,
182 gpointer data)
183 {
184 double xdifferenz;
185 double ydifferenz;
186
187 if (zoomindex < ZOOM_UNDO_SIZE - 1)
188 {
189 zooms[zoomindex]=wvals;
190 zoomindex++;
191 }
192 zoommax = zoomindex;
193
194 xdifferenz = wvals.xmax - wvals.xmin;
195 ydifferenz = wvals.ymax - wvals.ymin;
196 wvals.xmin += 1.0 / 6.0 * xdifferenz;
197 wvals.ymin += 1.0 / 6.0 * ydifferenz;
198 wvals.xmax -= 1.0 / 6.0 * xdifferenz;
199 wvals.ymax -= 1.0 / 6.0 * ydifferenz;
200 zooms[zoomindex] = wvals;
201
202 dialog_change_scale ();
203 set_cmap_preview ();
204 dialog_update_preview ();
205 }
206
207 static void
dialog_step_out_callback(GtkWidget * widget,gpointer data)208 dialog_step_out_callback (GtkWidget *widget,
209 gpointer data)
210 {
211 gdouble xdifferenz;
212 gdouble ydifferenz;
213
214 if (zoomindex < ZOOM_UNDO_SIZE - 1)
215 {
216 zooms[zoomindex]=wvals;
217 zoomindex++;
218 }
219 zoommax = zoomindex;
220
221 xdifferenz = wvals.xmax - wvals.xmin;
222 ydifferenz = wvals.ymax - wvals.ymin;
223 wvals.xmin -= 1.0 / 4.0 * xdifferenz;
224 wvals.ymin -= 1.0 / 4.0 * ydifferenz;
225 wvals.xmax += 1.0 / 4.0 * xdifferenz;
226 wvals.ymax += 1.0 / 4.0 * ydifferenz;
227 zooms[zoomindex] = wvals;
228
229 dialog_change_scale ();
230 set_cmap_preview ();
231 dialog_update_preview ();
232 }
233
234 static void
explorer_toggle_update(GtkWidget * widget,gpointer data)235 explorer_toggle_update (GtkWidget *widget,
236 gpointer data)
237 {
238 gimp_toggle_button_update (widget, data);
239
240 set_cmap_preview ();
241 dialog_update_preview ();
242 }
243
244 static void
explorer_radio_update(GtkWidget * widget,gpointer data)245 explorer_radio_update (GtkWidget *widget,
246 gpointer data)
247 {
248 gboolean c_sensitive;
249
250 gimp_radio_button_update (widget, data);
251
252 switch (wvals.fractaltype)
253 {
254 case TYPE_MANDELBROT:
255 case TYPE_SIERPINSKI:
256 c_sensitive = FALSE;
257 break;
258
259 default:
260 c_sensitive = TRUE;
261 break;
262 }
263
264 gimp_scale_entry_set_sensitive (elements->cx, c_sensitive);
265 gimp_scale_entry_set_sensitive (elements->cy, c_sensitive);
266
267 set_cmap_preview ();
268 dialog_update_preview ();
269 }
270
271 static void
explorer_double_adjustment_update(GtkAdjustment * adjustment,gpointer data)272 explorer_double_adjustment_update (GtkAdjustment *adjustment,
273 gpointer data)
274 {
275 gimp_double_adjustment_update (adjustment, data);
276
277 set_cmap_preview ();
278 dialog_update_preview ();
279 }
280
281 static void
explorer_number_of_colors_callback(GtkAdjustment * adjustment,gpointer data)282 explorer_number_of_colors_callback (GtkAdjustment *adjustment,
283 gpointer data)
284 {
285 gimp_int_adjustment_update (adjustment, data);
286
287 g_free (gradient_samples);
288
289 if (! gradient_name)
290 gradient_name = gimp_context_get_gradient ();
291
292 gimp_gradient_get_uniform_samples (gradient_name,
293 wvals.ncolors,
294 wvals.gradinvert,
295 &n_gradient_samples,
296 &gradient_samples);
297
298 set_cmap_preview ();
299 dialog_update_preview ();
300 }
301
302 static void
explorer_gradient_select_callback(GimpGradientSelectButton * gradient_button,const gchar * name,gint width,const gdouble * gradient_data,gboolean dialog_closing,gpointer data)303 explorer_gradient_select_callback (GimpGradientSelectButton *gradient_button,
304 const gchar *name,
305 gint width,
306 const gdouble *gradient_data,
307 gboolean dialog_closing,
308 gpointer data)
309 {
310 g_free (gradient_name);
311 g_free (gradient_samples);
312
313 gradient_name = g_strdup (name);
314
315 gimp_gradient_get_uniform_samples (gradient_name,
316 wvals.ncolors,
317 wvals.gradinvert,
318 &n_gradient_samples,
319 &gradient_samples);
320
321 if (wvals.colormode == 1)
322 {
323 set_cmap_preview ();
324 dialog_update_preview ();
325 }
326 }
327
328 static void
preview_draw_crosshair(gint px,gint py)329 preview_draw_crosshair (gint px,
330 gint py)
331 {
332 gint x, y;
333 guchar *p_ul;
334
335 p_ul = wint.wimage + 3 * (preview_width * py + 0);
336
337 for (x = 0; x < preview_width; x++)
338 {
339 p_ul[0] ^= 254;
340 p_ul[1] ^= 254;
341 p_ul[2] ^= 254;
342 p_ul += 3;
343 }
344
345 p_ul = wint.wimage + 3 * (preview_width * 0 + px);
346
347 for (y = 0; y < preview_height; y++)
348 {
349 p_ul[0] ^= 254;
350 p_ul[1] ^= 254;
351 p_ul[2] ^= 254;
352 p_ul += 3 * preview_width;
353 }
354 }
355
356 static void
preview_redraw(void)357 preview_redraw (void)
358 {
359 gimp_preview_area_draw (GIMP_PREVIEW_AREA (wint.preview),
360 0, 0, preview_width, preview_height,
361 GIMP_RGB_IMAGE,
362 wint.wimage, preview_width * 3);
363
364 gtk_widget_queue_draw (wint.preview);
365 }
366
367 static gboolean
preview_button_press_event(GtkWidget * widget,GdkEventButton * event)368 preview_button_press_event (GtkWidget *widget,
369 GdkEventButton *event)
370 {
371 if (event->button == 1)
372 {
373 x_press = event->x;
374 y_press = event->y;
375 xbild = preview_width;
376 ybild = preview_height;
377 xdiff = (xmax - xmin) / xbild;
378 ydiff = (ymax - ymin) / ybild;
379
380 preview_draw_crosshair (x_press, y_press);
381 preview_redraw ();
382 }
383 return TRUE;
384 }
385
386 static gboolean
preview_motion_notify_event(GtkWidget * widget,GdkEventButton * event)387 preview_motion_notify_event (GtkWidget *widget,
388 GdkEventButton *event)
389 {
390 if (oldypos != -1)
391 {
392 preview_draw_crosshair (oldxpos, oldypos);
393 }
394
395 oldxpos = event->x;
396 oldypos = event->y;
397
398 if ((oldxpos >= 0.0) &&
399 (oldypos >= 0.0) &&
400 (oldxpos < preview_width) &&
401 (oldypos < preview_height))
402 {
403 preview_draw_crosshair (oldxpos, oldypos);
404 }
405 else
406 {
407 oldypos = -1;
408 oldxpos = -1;
409 }
410
411 preview_redraw ();
412
413 return TRUE;
414 }
415
416 static gboolean
preview_leave_notify_event(GtkWidget * widget,GdkEventButton * event)417 preview_leave_notify_event (GtkWidget *widget,
418 GdkEventButton *event)
419 {
420 if (oldypos != -1)
421 {
422 preview_draw_crosshair (oldxpos, oldypos);
423 }
424 oldxpos = -1;
425 oldypos = -1;
426
427 preview_redraw ();
428
429 gdk_window_set_cursor (gtk_widget_get_window (maindlg), NULL);
430
431 return TRUE;
432 }
433
434 static gboolean
preview_enter_notify_event(GtkWidget * widget,GdkEventButton * event)435 preview_enter_notify_event (GtkWidget *widget,
436 GdkEventButton *event)
437 {
438 static GdkCursor *cursor = NULL;
439
440 if (! cursor)
441 {
442 GdkDisplay *display = gtk_widget_get_display (maindlg);
443
444 cursor = gdk_cursor_new_for_display (display, GDK_TCROSS);
445
446 }
447
448 gdk_window_set_cursor (gtk_widget_get_window (maindlg), cursor);
449
450 return TRUE;
451 }
452
453 static gboolean
preview_button_release_event(GtkWidget * widget,GdkEventButton * event)454 preview_button_release_event (GtkWidget *widget,
455 GdkEventButton *event)
456 {
457 gdouble l_xmin;
458 gdouble l_xmax;
459 gdouble l_ymin;
460 gdouble l_ymax;
461
462 if (event->button == 1)
463 {
464 gdouble x_release, y_release;
465
466 x_release = event->x;
467 y_release = event->y;
468
469 if ((x_press >= 0.0) && (y_press >= 0.0) &&
470 (x_release >= 0.0) && (y_release >= 0.0) &&
471 (x_press < preview_width) && (y_press < preview_height) &&
472 (x_release < preview_width) && (y_release < preview_height))
473 {
474 l_xmin = (wvals.xmin +
475 (wvals.xmax - wvals.xmin) * (x_press / preview_width));
476 l_xmax = (wvals.xmin +
477 (wvals.xmax - wvals.xmin) * (x_release / preview_width));
478 l_ymin = (wvals.ymin +
479 (wvals.ymax - wvals.ymin) * (y_press / preview_height));
480 l_ymax = (wvals.ymin +
481 (wvals.ymax - wvals.ymin) * (y_release / preview_height));
482
483 if (zoomindex < ZOOM_UNDO_SIZE - 1)
484 {
485 zooms[zoomindex] = wvals;
486 zoomindex++;
487 }
488 zoommax = zoomindex;
489 wvals.xmin = l_xmin;
490 wvals.xmax = l_xmax;
491 wvals.ymin = l_ymin;
492 wvals.ymax = l_ymax;
493 dialog_change_scale ();
494 dialog_update_preview ();
495 oldypos = oldxpos = -1;
496 }
497 }
498
499 return TRUE;
500 }
501
502 /**********************************************************************
503 FUNCTION: explorer_dialog
504 *********************************************************************/
505
506 gint
explorer_dialog(void)507 explorer_dialog (void)
508 {
509 GtkWidget *dialog;
510 GtkWidget *top_hbox;
511 GtkWidget *left_vbox;
512 GtkWidget *abox;
513 GtkWidget *vbox;
514 GtkWidget *bbox;
515 GtkWidget *frame;
516 GtkWidget *toggle;
517 GtkWidget *toggle_vbox;
518 GtkWidget *toggle_vbox2;
519 GtkWidget *toggle_vbox3;
520 GtkWidget *notebook;
521 GtkWidget *hbox;
522 GtkWidget *table;
523 GtkWidget *button;
524 GtkWidget *gradient;
525 gchar *path;
526 gchar *gradient_name;
527 GSList *group = NULL;
528 gint i;
529
530 gimp_ui_init (PLUG_IN_BINARY, TRUE);
531
532 path = gimp_gimprc_query ("fractalexplorer-path");
533
534 if (path)
535 {
536 fractalexplorer_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
537 g_free (path);
538 }
539 else
540 {
541 gchar *gimprc = gimp_personal_rc_file ("gimprc");
542 gchar *full_path = gimp_config_build_data_path ("fractalexplorer");
543 gchar *esc_path = g_strescape (full_path, NULL);
544 g_free (full_path);
545
546 g_message (_("No %s in gimprc:\n"
547 "You need to add an entry like\n"
548 "(%s \"%s\")\n"
549 "to your %s file."),
550 "fractalexplorer-path",
551 "fractalexplorer-path",
552 esc_path, gimp_filename_to_utf8 (gimprc));
553
554 g_free (gimprc);
555 g_free (esc_path);
556 }
557
558 wint.wimage = g_new (guchar, preview_width * preview_height * 3);
559 elements = g_new (DialogElements, 1);
560
561 dialog = maindlg =
562 gimp_dialog_new (_("Fractal Explorer"), PLUG_IN_ROLE,
563 NULL, 0,
564 gimp_standard_help_func, PLUG_IN_PROC,
565
566 _("_Cancel"), GTK_RESPONSE_CANCEL,
567 _("_OK"), GTK_RESPONSE_OK,
568
569 NULL);
570
571 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
572 GTK_RESPONSE_OK,
573 GTK_RESPONSE_CANCEL,
574 -1);
575
576 gimp_window_set_transient (GTK_WINDOW (dialog));
577
578 g_signal_connect (dialog, "response",
579 G_CALLBACK (dialog_response),
580 NULL);
581
582 g_signal_connect (dialog, "destroy",
583 G_CALLBACK (gtk_main_quit),
584 NULL);
585
586 top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
587 gtk_container_set_border_width (GTK_CONTAINER (top_hbox), 12);
588 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
589 top_hbox, FALSE, FALSE, 0);
590 gtk_widget_show (top_hbox);
591
592 left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
593 gtk_box_pack_start (GTK_BOX (top_hbox), left_vbox, FALSE, FALSE, 0);
594 gtk_widget_show (left_vbox);
595
596 /* Preview */
597 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
598 gtk_box_pack_start (GTK_BOX (left_vbox), vbox, FALSE, FALSE, 0);
599 gtk_widget_show (vbox);
600
601 abox = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
602 gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
603 gtk_widget_show (abox);
604
605 frame = gtk_frame_new (NULL);
606 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
607 gtk_container_add (GTK_CONTAINER (abox), frame);
608 gtk_widget_show (frame);
609
610 wint.preview = gimp_preview_area_new ();
611 gtk_widget_set_size_request (wint.preview, preview_width, preview_height);
612 gtk_container_add (GTK_CONTAINER (frame), wint.preview);
613
614 g_signal_connect (wint.preview, "button-press-event",
615 G_CALLBACK (preview_button_press_event),
616 NULL);
617 g_signal_connect (wint.preview, "button-release-event",
618 G_CALLBACK (preview_button_release_event),
619 NULL);
620 g_signal_connect (wint.preview, "motion-notify-event",
621 G_CALLBACK (preview_motion_notify_event),
622 NULL);
623 g_signal_connect (wint.preview, "leave-notify-event",
624 G_CALLBACK (preview_leave_notify_event),
625 NULL);
626 g_signal_connect (wint.preview, "enter-notify-event",
627 G_CALLBACK (preview_enter_notify_event),
628 NULL);
629
630 gtk_widget_set_events (wint.preview, (GDK_BUTTON_PRESS_MASK |
631 GDK_BUTTON_RELEASE_MASK |
632 GDK_POINTER_MOTION_MASK |
633 GDK_LEAVE_NOTIFY_MASK |
634 GDK_ENTER_NOTIFY_MASK));
635 gtk_widget_show (wint.preview);
636
637 toggle = gtk_check_button_new_with_mnemonic (_("Re_altime preview"));
638 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
639 g_signal_connect (toggle, "toggled",
640 G_CALLBACK (explorer_toggle_update),
641 &wvals.alwayspreview);
642 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
643 wvals.alwayspreview);
644 gtk_widget_show (toggle);
645 gimp_help_set_help_data (toggle, _("If enabled the preview will "
646 "be redrawn automatically"), NULL);
647
648 button = gtk_button_new_with_mnemonic (_("R_edraw preview"));
649 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
650 g_signal_connect (button, "clicked",
651 G_CALLBACK (dialog_redraw_callback),
652 dialog);
653 gtk_widget_show (button);
654
655 /* Zoom Options */
656 frame = gimp_frame_new (_("Zoom"));
657 gtk_box_pack_start (GTK_BOX (left_vbox), frame, FALSE, FALSE, 0);
658 gtk_widget_show (frame);
659
660 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
661 gtk_container_add (GTK_CONTAINER (frame), vbox);
662 gtk_widget_show (vbox);
663
664 bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
665 gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
666 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
667 gtk_widget_show (bbox);
668
669 button = gtk_button_new_with_mnemonic (_("Zoom _In"));
670 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
671 gtk_widget_show (button);
672
673 g_signal_connect (button, "clicked",
674 G_CALLBACK (dialog_step_in_callback),
675 dialog);
676
677 button = gtk_button_new_with_mnemonic (_("Zoom _Out"));
678 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
679 gtk_widget_show (button);
680
681 g_signal_connect (button, "clicked",
682 G_CALLBACK (dialog_step_out_callback),
683 dialog);
684
685 bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
686 gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
687 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
688 gtk_widget_show (bbox);
689
690 button = gtk_button_new_with_mnemonic (_("_Undo"));
691 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
692 gtk_widget_show (button);
693
694 gimp_help_set_help_data (button, _("Undo last zoom change"), NULL);
695
696 g_signal_connect (button, "clicked",
697 G_CALLBACK (dialog_undo_zoom_callback),
698 dialog);
699
700 button = gtk_button_new_with_mnemonic (_("_Redo"));
701 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
702 gtk_widget_show (button);
703
704 gimp_help_set_help_data (button, _("Redo last zoom change"), NULL);
705
706 g_signal_connect (button, "clicked",
707 G_CALLBACK (dialog_redo_zoom_callback),
708 dialog);
709
710 /* Create notebook */
711 notebook = gtk_notebook_new ();
712 gtk_box_pack_start (GTK_BOX (top_hbox), notebook, FALSE, FALSE, 0);
713 gtk_widget_show (notebook);
714
715 /* "Parameters" page */
716 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
717 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
718 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
719 gtk_label_new_with_mnemonic (_("_Parameters")));
720 gtk_widget_show (vbox);
721
722 frame = gimp_frame_new (_("Fractal Parameters"));
723 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
724 gtk_widget_show (frame);
725
726 table = gtk_table_new (8, 3, FALSE);
727 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
728 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
729 gtk_table_set_row_spacing (GTK_TABLE (table), 6, 12);
730 gtk_container_add (GTK_CONTAINER (frame), table);
731 gtk_widget_show (table);
732
733 elements->xmin =
734 gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
735 _("Left:"), SCALE_WIDTH, 10,
736 wvals.xmin, -3, 3, 0.001, 0.01, 5,
737 TRUE, 0, 0, NULL, NULL);
738 g_signal_connect (elements->xmin, "value-changed",
739 G_CALLBACK (explorer_double_adjustment_update),
740 &wvals.xmin);
741
742 elements->xmax =
743 gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
744 _("Right:"), SCALE_WIDTH, 10,
745 wvals.xmax, -3, 3, 0.001, 0.01, 5,
746 TRUE, 0, 0, NULL, NULL);
747 g_signal_connect (elements->xmax, "value-changed",
748 G_CALLBACK (explorer_double_adjustment_update),
749 &wvals.xmax);
750
751 elements->ymin =
752 gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
753 _("Top:"), SCALE_WIDTH, 10,
754 wvals.ymin, -3, 3, 0.001, 0.01, 5,
755 TRUE, 0, 0, NULL, NULL);
756 g_signal_connect (elements->ymin, "value-changed",
757 G_CALLBACK (explorer_double_adjustment_update),
758 &wvals.ymin);
759
760 elements->ymax =
761 gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
762 _("Bottom:"), SCALE_WIDTH, 10,
763 wvals.ymax, -3, 3, 0.001, 0.01, 5,
764 TRUE, 0, 0, NULL, NULL);
765 g_signal_connect (elements->ymax, "value-changed",
766 G_CALLBACK (explorer_double_adjustment_update),
767 &wvals.ymax);
768
769 elements->iter =
770 gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
771 _("Iterations:"), SCALE_WIDTH, 10,
772 wvals.iter, 1, 1000, 1, 10, 0,
773 TRUE, 0, 0,
774 _("The higher the number of iterations, "
775 "the more details will be calculated"), NULL);
776 g_signal_connect (elements->iter, "value-changed",
777 G_CALLBACK (explorer_double_adjustment_update),
778 &wvals.iter);
779
780 elements->cx =
781 gimp_scale_entry_new (GTK_TABLE (table), 0, 5,
782 _("CX:"), SCALE_WIDTH, 10,
783 wvals.cx, -2.5, 2.5, 0.001, 0.01, 5,
784 TRUE, 0, 0,
785 _("Changes aspect of fractal"), NULL);
786 g_signal_connect (elements->cx, "value-changed",
787 G_CALLBACK (explorer_double_adjustment_update),
788 &wvals.cx);
789
790 elements->cy =
791 gimp_scale_entry_new (GTK_TABLE (table), 0, 6,
792 _("CY:"), SCALE_WIDTH, 10,
793 wvals.cy, -2.5, 2.5, 0.001, 0.01, 5,
794 TRUE, 0, 0,
795 _("Changes aspect of fractal"), NULL);
796 g_signal_connect (elements->cy, "value-changed",
797 G_CALLBACK (explorer_double_adjustment_update),
798 &wvals.cy);
799
800 bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
801 gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
802 gtk_table_attach_defaults (GTK_TABLE (table), bbox, 0, 3, 7, 8);
803 gtk_widget_show (bbox);
804
805 button = gtk_button_new_with_mnemonic (_("_Open"));
806 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
807 g_signal_connect (button, "clicked",
808 G_CALLBACK (create_load_file_chooser),
809 dialog);
810 gtk_widget_show (button);
811 gimp_help_set_help_data (button, _("Load a fractal from file"), NULL);
812
813 button = gtk_button_new_with_mnemonic (_("_Reset"));
814 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
815 g_signal_connect (button, "clicked",
816 G_CALLBACK (dialog_reset_callback),
817 dialog);
818 gtk_widget_show (button);
819 gimp_help_set_help_data (button, _("Reset parameters to default values"),
820 NULL);
821
822 button = gtk_button_new_with_mnemonic (_("_Save"));
823 gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
824 g_signal_connect (button, "clicked",
825 G_CALLBACK (create_save_file_chooser),
826 dialog);
827 gtk_widget_show (button);
828 gimp_help_set_help_data (button, _("Save active fractal to file"), NULL);
829
830 /* Fractal type toggle box */
831 frame = gimp_frame_new (_("Fractal Type"));
832 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
833 gtk_widget_show (frame);
834
835 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
836 gtk_container_add (GTK_CONTAINER (frame), hbox);
837 gtk_widget_show (hbox);
838
839 toggle_vbox =
840 gimp_int_radio_group_new (FALSE, NULL,
841 G_CALLBACK (explorer_radio_update),
842 &wvals.fractaltype, wvals.fractaltype,
843
844 _("Mandelbrot"), TYPE_MANDELBROT,
845 &(elements->type[TYPE_MANDELBROT]),
846 _("Julia"), TYPE_JULIA,
847 &(elements->type[TYPE_JULIA]),
848 _("Barnsley 1"), TYPE_BARNSLEY_1,
849 &(elements->type[TYPE_BARNSLEY_1]),
850 _("Barnsley 2"), TYPE_BARNSLEY_2,
851 &(elements->type[TYPE_BARNSLEY_2]),
852 _("Barnsley 3"), TYPE_BARNSLEY_3,
853 &(elements->type[TYPE_BARNSLEY_3]),
854 _("Spider"), TYPE_SPIDER,
855 &(elements->type[TYPE_SPIDER]),
856 _("Man'o'war"), TYPE_MAN_O_WAR,
857 &(elements->type[TYPE_MAN_O_WAR]),
858 _("Lambda"), TYPE_LAMBDA,
859 &(elements->type[TYPE_LAMBDA]),
860 _("Sierpinski"), TYPE_SIERPINSKI,
861 &(elements->type[TYPE_SIERPINSKI]),
862
863 NULL);
864
865 toggle_vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
866 for (i = TYPE_BARNSLEY_2; i <= TYPE_SPIDER; i++)
867 {
868 g_object_ref (elements->type[i]);
869
870 gtk_widget_hide (elements->type[i]);
871 gtk_container_remove (GTK_CONTAINER (toggle_vbox), elements->type[i]);
872 gtk_box_pack_start (GTK_BOX (toggle_vbox2), elements->type[i],
873 FALSE, FALSE, 0);
874 gtk_widget_show (elements->type[i]);
875
876 g_object_unref (elements->type[i]);
877 }
878
879 toggle_vbox3 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
880 for (i = TYPE_MAN_O_WAR; i <= TYPE_SIERPINSKI; i++)
881 {
882 g_object_ref (elements->type[i]);
883
884 gtk_widget_hide (elements->type[i]);
885 gtk_container_remove (GTK_CONTAINER (toggle_vbox), elements->type[i]);
886 gtk_box_pack_start (GTK_BOX (toggle_vbox3), elements->type[i],
887 FALSE, FALSE, 0);
888 gtk_widget_show (elements->type[i]);
889
890 g_object_unref (elements->type[i]);
891 }
892
893 gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox, FALSE, FALSE, 0);
894 gtk_widget_show (toggle_vbox);
895
896 gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox2, FALSE, FALSE, 0);
897 gtk_widget_show (toggle_vbox2);
898
899 gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox3, FALSE, FALSE, 0);
900 gtk_widget_show (toggle_vbox3);
901
902 /* Color page */
903 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
904 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
905 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
906 gtk_label_new_with_mnemonic (_("Co_lors")));
907 gtk_widget_show (vbox);
908
909 /* Number of Colors frame */
910 frame = gimp_frame_new (_("Number of Colors"));
911 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
912 gtk_widget_show (frame);
913
914 table = gtk_table_new (2, 3, FALSE);
915 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
916 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
917 gtk_container_add (GTK_CONTAINER (frame), table);
918 gtk_widget_show (table);
919
920 elements->ncol =
921 gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
922 _("Number of colors:"), SCALE_WIDTH, 0,
923 wvals.ncolors, 2, MAXNCOLORS, 1, 10, 0,
924 TRUE, 0, 0,
925 _("Change the number of colors in the mapping"),
926 NULL);
927 g_signal_connect (elements->ncol, "value-changed",
928 G_CALLBACK (explorer_number_of_colors_callback),
929 &wvals.ncolors);
930
931 elements->useloglog = toggle =
932 gtk_check_button_new_with_label (_("Use loglog smoothing"));
933 gtk_table_attach_defaults (GTK_TABLE (table), toggle, 0, 3, 1, 2);
934 g_signal_connect (toggle, "toggled",
935 G_CALLBACK (explorer_toggle_update),
936 &wvals.useloglog);
937 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.useloglog);
938 gtk_widget_show (toggle);
939 gimp_help_set_help_data (toggle, _("Use log log smoothing to eliminate "
940 "\"banding\" in the result"), NULL);
941
942 /* Color Density frame */
943 frame = gimp_frame_new (_("Color Density"));
944 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
945 gtk_widget_show (frame);
946
947 table = gtk_table_new (3, 3, FALSE);
948 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
949 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
950 gtk_container_add (GTK_CONTAINER (frame), table);
951 gtk_widget_show (table);
952
953 elements->red =
954 gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
955 _("Red:"), SCALE_WIDTH, 0,
956 wvals.redstretch, 0, 1, 0.01, 0.1, 2,
957 TRUE, 0, 0,
958 _("Change the intensity of the red channel"), NULL);
959 g_signal_connect (elements->red, "value-changed",
960 G_CALLBACK (explorer_double_adjustment_update),
961 &wvals.redstretch);
962
963 elements->green =
964 gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
965 _("Green:"), SCALE_WIDTH, 0,
966 wvals.greenstretch, 0, 1, 0.01, 0.1, 2,
967 TRUE, 0, 0,
968 _("Change the intensity of the green channel"), NULL);
969 g_signal_connect (elements->green, "value-changed",
970 G_CALLBACK (explorer_double_adjustment_update),
971 &wvals.greenstretch);
972
973 elements->blue =
974 gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
975 _("Blue:"), SCALE_WIDTH, 0,
976 wvals.bluestretch, 0, 1, 0.01, 0.1, 2,
977 TRUE, 0, 0,
978 _("Change the intensity of the blue channel"), NULL);
979 g_signal_connect (elements->blue, "value-changed",
980 G_CALLBACK (explorer_double_adjustment_update),
981 &wvals.bluestretch);
982
983 /* Color Function frame */
984 frame = gimp_frame_new (_("Color Function"));
985 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
986 gtk_widget_show (frame);
987
988 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
989 gtk_container_add (GTK_CONTAINER (frame), hbox);
990 gtk_widget_show (hbox);
991
992 /* Redmode radio frame */
993 frame = gimp_int_radio_group_new (TRUE, _("Red"),
994 G_CALLBACK (explorer_radio_update),
995 &wvals.redmode, wvals.redmode,
996
997 _("Sine"), SINUS,
998 &elements->redmode[SINUS],
999 _("Cosine"), COSINUS,
1000 &elements->redmode[COSINUS],
1001 C_("color-function", "None"), NONE,
1002 &elements->redmode[NONE],
1003
1004 NULL);
1005 gimp_help_set_help_data (elements->redmode[SINUS],
1006 _("Use sine-function for this color component"),
1007 NULL);
1008 gimp_help_set_help_data (elements->redmode[COSINUS],
1009 _("Use cosine-function for this color "
1010 "component"), NULL);
1011 gimp_help_set_help_data (elements->redmode[NONE],
1012 _("Use linear mapping instead of any "
1013 "trigonometrical function for this color "
1014 "channel"), NULL);
1015 gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1016 gtk_widget_show (frame);
1017
1018 toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
1019
1020 elements->redinvert = toggle =
1021 gtk_check_button_new_with_label (_("Inversion"));
1022 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.redinvert);
1023 gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
1024 g_signal_connect (toggle, "toggled",
1025 G_CALLBACK (explorer_toggle_update),
1026 &wvals.redinvert);
1027 gtk_widget_show (toggle);
1028 gimp_help_set_help_data (toggle,
1029 _("If you enable this option higher color values "
1030 "will be swapped with lower ones and vice "
1031 "versa"), NULL);
1032
1033 /* Greenmode radio frame */
1034 frame = gimp_int_radio_group_new (TRUE, _("Green"),
1035 G_CALLBACK (explorer_radio_update),
1036 &wvals.greenmode, wvals.greenmode,
1037
1038 _("Sine"), SINUS,
1039 &elements->greenmode[SINUS],
1040 _("Cosine"), COSINUS,
1041 &elements->greenmode[COSINUS],
1042 C_("color-function", "None"), NONE,
1043 &elements->greenmode[NONE],
1044
1045 NULL);
1046 gimp_help_set_help_data (elements->greenmode[SINUS],
1047 _("Use sine-function for this color component"),
1048 NULL);
1049 gimp_help_set_help_data (elements->greenmode[COSINUS],
1050 _("Use cosine-function for this color "
1051 "component"), NULL);
1052 gimp_help_set_help_data (elements->greenmode[NONE],
1053 _("Use linear mapping instead of any "
1054 "trigonometrical function for this color "
1055 "channel"), NULL);
1056 gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1057 gtk_widget_show (frame);
1058
1059 toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
1060
1061 elements->greeninvert = toggle =
1062 gtk_check_button_new_with_label (_("Inversion"));
1063 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.greeninvert);
1064 gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
1065 g_signal_connect (toggle, "toggled",
1066 G_CALLBACK (explorer_toggle_update),
1067 &wvals.greeninvert);
1068 gtk_widget_show (toggle);
1069 gimp_help_set_help_data (toggle,
1070 _("If you enable this option higher color values "
1071 "will be swapped with lower ones and vice "
1072 "versa"), NULL);
1073
1074 /* Bluemode radio frame */
1075 frame = gimp_int_radio_group_new (TRUE, _("Blue"),
1076 G_CALLBACK (explorer_radio_update),
1077 &wvals.bluemode, wvals.bluemode,
1078
1079 _("Sine"), SINUS,
1080 &elements->bluemode[SINUS],
1081 _("Cosine"), COSINUS,
1082 &elements->bluemode[COSINUS],
1083 C_("color-function", "None"), NONE,
1084 &elements->bluemode[NONE],
1085
1086 NULL);
1087 gimp_help_set_help_data (elements->bluemode[SINUS],
1088 _("Use sine-function for this color component"),
1089 NULL);
1090 gimp_help_set_help_data (elements->bluemode[COSINUS],
1091 _("Use cosine-function for this color "
1092 "component"), NULL);
1093 gimp_help_set_help_data (elements->bluemode[NONE],
1094 _("Use linear mapping instead of any "
1095 "trigonometrical function for this color "
1096 "channel"), NULL);
1097 gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1098 gtk_widget_show (frame);
1099
1100 toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
1101
1102 elements->blueinvert = toggle =
1103 gtk_check_button_new_with_label (_("Inversion"));
1104 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON( toggle), wvals.blueinvert);
1105 gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
1106 g_signal_connect (toggle, "toggled",
1107 G_CALLBACK (explorer_toggle_update),
1108 &wvals.blueinvert);
1109 gtk_widget_show (toggle);
1110 gimp_help_set_help_data (toggle,
1111 _("If you enable this option higher color values "
1112 "will be swapped with lower ones and vice "
1113 "versa"), NULL);
1114
1115 /* Colormode toggle box */
1116 frame = gimp_frame_new (_("Color Mode"));
1117 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1118 gtk_widget_show (frame);
1119
1120 toggle_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
1121 gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
1122 gtk_widget_show (toggle_vbox);
1123
1124 toggle = elements->colormode[0] =
1125 gtk_radio_button_new_with_label (group, _("As specified above"));
1126 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
1127 gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
1128 g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
1129 GINT_TO_POINTER (0));
1130 g_signal_connect (toggle, "toggled",
1131 G_CALLBACK (explorer_radio_update),
1132 &wvals.colormode);
1133 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1134 wvals.colormode == 0);
1135 gtk_widget_show (toggle);
1136 gimp_help_set_help_data (toggle,
1137 _("Create a color-map with the options you "
1138 "specified above (color density/function). The "
1139 "result is visible in the preview image"), NULL);
1140
1141 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1142 gtk_box_pack_start (GTK_BOX (toggle_vbox), hbox, FALSE, FALSE, 0);
1143 gtk_widget_show (hbox);
1144
1145 toggle = elements->colormode[1] =
1146 gtk_radio_button_new_with_label (group,
1147 _("Apply active gradient to final image"));
1148 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
1149 gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
1150 g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
1151 GINT_TO_POINTER (1));
1152 g_signal_connect (toggle, "toggled",
1153 G_CALLBACK (explorer_radio_update),
1154 &wvals.colormode);
1155 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1156 wvals.colormode == 1);
1157 gtk_widget_show (toggle);
1158 gimp_help_set_help_data (toggle,
1159 _("Create a color-map using a gradient from "
1160 "the gradient editor"), NULL);
1161
1162 gradient_name = gimp_context_get_gradient ();
1163
1164 gimp_gradient_get_uniform_samples (gradient_name,
1165 wvals.ncolors,
1166 wvals.gradinvert,
1167 &n_gradient_samples,
1168 &gradient_samples);
1169
1170 gradient = gimp_gradient_select_button_new (_("FractalExplorer Gradient"),
1171 gradient_name);
1172 g_signal_connect (gradient, "gradient-set",
1173 G_CALLBACK (explorer_gradient_select_callback), NULL);
1174 g_free (gradient_name);
1175 gtk_box_pack_start (GTK_BOX (hbox), gradient, FALSE, FALSE, 0);
1176 gtk_widget_show (gradient);
1177
1178 abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1179 {
1180 gint xsize, ysize;
1181
1182 for (ysize = 1; ysize * ysize * ysize < 8192; ysize++) /**/;
1183 xsize = wvals.ncolors / ysize;
1184 while (xsize * ysize < 8192) xsize++;
1185
1186 gtk_widget_set_size_request (abox, xsize, ysize * 4);
1187 }
1188 gtk_box_pack_start (GTK_BOX (toggle_vbox), abox, FALSE, FALSE, 0);
1189 gtk_widget_show (abox);
1190
1191 cmap_preview = gimp_preview_area_new ();
1192 gtk_widget_set_size_request (cmap_preview, 32, 32);
1193 gtk_container_add (GTK_CONTAINER (abox), cmap_preview);
1194 g_signal_connect (cmap_preview, "size-allocate",
1195 G_CALLBACK (cmap_preview_size_allocate), NULL);
1196 gtk_widget_show (cmap_preview);
1197
1198 frame = add_objects_list ();
1199 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame,
1200 gtk_label_new_with_mnemonic (_("_Fractals")));
1201 gtk_widget_show (frame);
1202
1203 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
1204
1205 gtk_widget_show (dialog);
1206 ready_now = TRUE;
1207
1208 set_cmap_preview ();
1209 dialog_update_preview ();
1210
1211 gtk_main ();
1212
1213 g_free (wint.wimage);
1214
1215 return wint.run;
1216 }
1217
1218
1219 /**********************************************************************
1220 FUNCTION: dialog_update_preview
1221 *********************************************************************/
1222
1223 void
dialog_update_preview(void)1224 dialog_update_preview (void)
1225 {
1226 gint ycoord;
1227 guchar *p_ul;
1228
1229 if (NULL == wint.preview)
1230 return;
1231
1232 if (ready_now && wvals.alwayspreview)
1233 {
1234 xmin = wvals.xmin;
1235 xmax = wvals.xmax;
1236 ymin = wvals.ymin;
1237 ymax = wvals.ymax;
1238 xbild = preview_width;
1239 ybild = preview_height;
1240 xdiff = (xmax - xmin) / xbild;
1241 ydiff = (ymax - ymin) / ybild;
1242
1243 p_ul = wint.wimage;
1244
1245 for (ycoord = 0; ycoord < preview_height; ycoord++)
1246 {
1247 explorer_render_row (NULL,
1248 p_ul,
1249 ycoord,
1250 preview_width,
1251 3);
1252 p_ul += preview_width * 3;
1253 }
1254
1255 preview_redraw ();
1256 }
1257 }
1258
1259 /**********************************************************************
1260 FUNCTION: cmap_preview_size_allocate()
1261 *********************************************************************/
1262
1263 static void
cmap_preview_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1264 cmap_preview_size_allocate (GtkWidget *widget,
1265 GtkAllocation *allocation)
1266 {
1267 gint i;
1268 gint x;
1269 gint y;
1270 gint j;
1271 guchar *b;
1272 GimpPreviewArea *preview = GIMP_PREVIEW_AREA (widget);
1273
1274 b = g_new (guchar, allocation->width * allocation->height * 3);
1275
1276 for (y = 0; y < allocation->height; y++)
1277 {
1278 for (x = 0; x < allocation->width; x++)
1279 {
1280 i = x + (y / 4) * allocation->width;
1281 if (i > wvals.ncolors)
1282 {
1283 for (j = 0; j < 3; j++)
1284 b[(y*allocation->width + x) * 3 + j] = 0;
1285 }
1286 else
1287 {
1288 b[(y*allocation->width + x) * 3] = colormap[i].r;
1289 b[(y*allocation->width + x) * 3 + 1] = colormap[i].g;
1290 b[(y*allocation->width + x) * 3 + 2] = colormap[i].b;
1291 }
1292 }
1293 }
1294 gimp_preview_area_draw (preview,
1295 0, 0, allocation->width, allocation->height,
1296 GIMP_RGB_IMAGE, b, allocation->width*3);
1297 gtk_widget_queue_draw (cmap_preview);
1298
1299 g_free (b);
1300
1301 }
1302
1303 /**********************************************************************
1304 FUNCTION: set_cmap_preview()
1305 *********************************************************************/
1306
1307 void
set_cmap_preview(void)1308 set_cmap_preview (void)
1309 {
1310 gint xsize, ysize;
1311
1312 if (NULL == cmap_preview)
1313 return;
1314
1315 make_color_map ();
1316
1317 for (ysize = 1; ysize * ysize * ysize < wvals.ncolors; ysize++)
1318 /**/;
1319 xsize = wvals.ncolors / ysize;
1320 while (xsize * ysize < wvals.ncolors)
1321 xsize++;
1322
1323 gtk_widget_set_size_request (cmap_preview, xsize, ysize * 4);
1324 }
1325
1326 /**********************************************************************
1327 FUNCTION: make_color_map()
1328 *********************************************************************/
1329
1330 void
make_color_map(void)1331 make_color_map (void)
1332 {
1333 gint i;
1334 gint r;
1335 gint gr;
1336 gint bl;
1337 gdouble redstretch;
1338 gdouble greenstretch;
1339 gdouble bluestretch;
1340 gdouble pi = atan (1) * 4;
1341
1342 /* get gradient samples if they don't exist -- fixes gradient color
1343 * mode for noninteractive use (bug #103470).
1344 */
1345 if (gradient_samples == NULL)
1346 {
1347 gchar *gradient_name = gimp_context_get_gradient ();
1348
1349 gimp_gradient_get_uniform_samples (gradient_name,
1350 wvals.ncolors,
1351 wvals.gradinvert,
1352 &n_gradient_samples,
1353 &gradient_samples);
1354
1355 g_free (gradient_name);
1356 }
1357
1358 redstretch = wvals.redstretch * 127.5;
1359 greenstretch = wvals.greenstretch * 127.5;
1360 bluestretch = wvals.bluestretch * 127.5;
1361
1362 for (i = 0; i < wvals.ncolors; i++)
1363 if (wvals.colormode == 1)
1364 {
1365 colormap[i].r = (guchar)(gradient_samples[i * 4] * 255.9);
1366 colormap[i].g = (guchar)(gradient_samples[i * 4 + 1] * 255.9);
1367 colormap[i].b = (guchar)(gradient_samples[i * 4 + 2] * 255.9);
1368 }
1369 else
1370 {
1371 double x = (i*2.0) / wvals.ncolors;
1372 r = gr = bl = 0;
1373
1374 switch (wvals.redmode)
1375 {
1376 case SINUS:
1377 r = (int) redstretch *(1.0 + sin((x - 1) * pi));
1378 break;
1379 case COSINUS:
1380 r = (int) redstretch *(1.0 + cos((x - 1) * pi));
1381 break;
1382 case NONE:
1383 r = (int)(redstretch *(x));
1384 break;
1385 default:
1386 break;
1387 }
1388
1389 switch (wvals.greenmode)
1390 {
1391 case SINUS:
1392 gr = (int) greenstretch *(1.0 + sin((x - 1) * pi));
1393 break;
1394 case COSINUS:
1395 gr = (int) greenstretch *(1.0 + cos((x - 1) * pi));
1396 break;
1397 case NONE:
1398 gr = (int)(greenstretch *(x));
1399 break;
1400 default:
1401 break;
1402 }
1403
1404 switch (wvals.bluemode)
1405 {
1406 case SINUS:
1407 bl = (int) bluestretch * (1.0 + sin ((x - 1) * pi));
1408 break;
1409 case COSINUS:
1410 bl = (int) bluestretch * (1.0 + cos ((x - 1) * pi));
1411 break;
1412 case NONE:
1413 bl = (int) (bluestretch * x);
1414 break;
1415 default:
1416 break;
1417 }
1418
1419 r = MIN (r, 255);
1420 gr = MIN (gr, 255);
1421 bl = MIN (bl, 255);
1422
1423 if (wvals.redinvert)
1424 r = 255 - r;
1425
1426 if (wvals.greeninvert)
1427 gr = 255 - gr;
1428
1429 if (wvals.blueinvert)
1430 bl = 255 - bl;
1431
1432 colormap[i].r = r;
1433 colormap[i].g = gr;
1434 colormap[i].b = bl;
1435 }
1436 }
1437
1438 /**********************************************************************
1439 FUNCTION: dialog_change_scale
1440 *********************************************************************/
1441
1442 void
dialog_change_scale(void)1443 dialog_change_scale (void)
1444 {
1445 ready_now = FALSE;
1446
1447 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->xmin), wvals.xmin);
1448 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->xmax), wvals.xmax);
1449 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->ymin), wvals.ymin);
1450 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->ymax), wvals.ymax);
1451 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->iter), wvals.iter);
1452 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->cx), wvals.cx);
1453 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->cy), wvals.cy);
1454
1455 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->red), wvals.redstretch);
1456 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->green),wvals.greenstretch);
1457 gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->blue), wvals.bluestretch);
1458
1459 gtk_toggle_button_set_active
1460 (GTK_TOGGLE_BUTTON (elements->type[wvals.fractaltype]), TRUE);
1461
1462 gtk_toggle_button_set_active
1463 (GTK_TOGGLE_BUTTON (elements->redmode[wvals.redmode]), TRUE);
1464 gtk_toggle_button_set_active
1465 (GTK_TOGGLE_BUTTON (elements->greenmode[wvals.greenmode]), TRUE);
1466 gtk_toggle_button_set_active
1467 (GTK_TOGGLE_BUTTON (elements->bluemode[wvals.bluemode]), TRUE);
1468
1469 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->redinvert),
1470 wvals.redinvert);
1471 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->greeninvert),
1472 wvals.greeninvert);
1473 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->blueinvert),
1474 wvals.blueinvert);
1475
1476 gtk_toggle_button_set_active
1477 (GTK_TOGGLE_BUTTON (elements->colormode[wvals.colormode]), TRUE);
1478
1479 ready_now = TRUE;
1480 }
1481
1482
1483 /**********************************************************************
1484 FUNCTION: save_options
1485 *********************************************************************/
1486
1487 static void
save_options(FILE * fp)1488 save_options (FILE * fp)
1489 {
1490 gchar buf[64];
1491
1492 /* Save options */
1493
1494 fprintf (fp, "fractaltype: %i\n", wvals.fractaltype);
1495
1496 g_ascii_dtostr (buf, sizeof (buf), wvals.xmin);
1497 fprintf (fp, "xmin: %s\n", buf);
1498
1499 g_ascii_dtostr (buf, sizeof (buf), wvals.xmax);
1500 fprintf (fp, "xmax: %s\n", buf);
1501
1502 g_ascii_dtostr (buf, sizeof (buf), wvals.ymin);
1503 fprintf (fp, "ymin: %s\n", buf);
1504
1505 g_ascii_dtostr (buf, sizeof (buf), wvals.ymax);
1506 fprintf (fp, "ymax: %s\n", buf);
1507
1508 g_ascii_dtostr (buf, sizeof (buf), wvals.iter);
1509 fprintf (fp, "iter: %s\n", buf);
1510
1511 g_ascii_dtostr (buf, sizeof (buf), wvals.cx);
1512 fprintf (fp, "cx: %s\n", buf);
1513
1514 g_ascii_dtostr (buf, sizeof (buf), wvals.cy);
1515 fprintf (fp, "cy: %s\n", buf);
1516
1517 g_ascii_dtostr (buf, sizeof (buf), wvals.redstretch * 128.0);
1518 fprintf (fp, "redstretch: %s\n", buf);
1519
1520 g_ascii_dtostr (buf, sizeof (buf), wvals.greenstretch * 128.0);
1521 fprintf (fp, "greenstretch: %s\n", buf);
1522
1523 g_ascii_dtostr (buf, sizeof (buf), wvals.bluestretch * 128.0);
1524 fprintf (fp, "bluestretch: %s\n", buf);
1525
1526 fprintf (fp, "redmode: %i\n", wvals.redmode);
1527 fprintf (fp, "greenmode: %i\n", wvals.greenmode);
1528 fprintf (fp, "bluemode: %i\n", wvals.bluemode);
1529 fprintf (fp, "redinvert: %i\n", wvals.redinvert);
1530 fprintf (fp, "greeninvert: %i\n", wvals.greeninvert);
1531 fprintf (fp, "blueinvert: %i\n", wvals.blueinvert);
1532 fprintf (fp, "colormode: %i\n", wvals.colormode);
1533 fputs ("#**********************************************************************\n", fp);
1534 fprintf(fp, "<EOF>\n");
1535 fputs ("#**********************************************************************\n", fp);
1536 }
1537
1538 static void
save_callback(void)1539 save_callback (void)
1540 {
1541 FILE *fp;
1542 const gchar *savename = filename;
1543
1544 fp = g_fopen (savename, "wt+");
1545
1546 if (!fp)
1547 {
1548 g_message (_("Could not open '%s' for writing: %s"),
1549 gimp_filename_to_utf8 (savename), g_strerror (errno));
1550 return;
1551 }
1552
1553 /* Write header out */
1554 fputs (FRACTAL_HEADER, fp);
1555 fputs ("#**********************************************************************\n", fp);
1556 fputs ("# This is a data file for the Fractal Explorer plug-in for GIMP *\n", fp);
1557 fputs ("#**********************************************************************\n", fp);
1558
1559 save_options (fp);
1560
1561 if (ferror (fp))
1562 g_message (_("Could not write '%s': %s"),
1563 gimp_filename_to_utf8 (savename), g_strerror (ferror (fp)));
1564
1565 fclose (fp);
1566 }
1567
1568 static void
save_file_chooser_response(GtkFileChooser * chooser,gint response_id,gpointer data)1569 save_file_chooser_response (GtkFileChooser *chooser,
1570 gint response_id,
1571 gpointer data)
1572 {
1573 if (response_id == GTK_RESPONSE_OK)
1574 {
1575 filename = gtk_file_chooser_get_filename (chooser);
1576
1577 save_callback ();
1578 }
1579
1580 gtk_widget_destroy (GTK_WIDGET (chooser));
1581 }
1582
1583 static void
file_chooser_set_default_folder(GtkFileChooser * chooser)1584 file_chooser_set_default_folder (GtkFileChooser *chooser)
1585 {
1586 GList *path_list;
1587 gchar *dir;
1588
1589 if (! fractalexplorer_path)
1590 return;
1591
1592 path_list = gimp_path_parse (fractalexplorer_path, 256, FALSE, NULL);
1593
1594 dir = gimp_path_get_user_writable_dir (path_list);
1595
1596 if (! dir)
1597 dir = g_strdup (gimp_directory ());
1598
1599 gtk_file_chooser_set_current_folder (chooser, dir);
1600
1601 g_free (dir);
1602 gimp_path_free (path_list);
1603 }
1604
1605 static void
load_file_chooser_response(GtkFileChooser * chooser,gint response_id,gpointer data)1606 load_file_chooser_response (GtkFileChooser *chooser,
1607 gint response_id,
1608 gpointer data)
1609 {
1610 if (response_id == GTK_RESPONSE_OK)
1611 {
1612 filename = gtk_file_chooser_get_filename (chooser);
1613
1614 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
1615 {
1616 explorer_load ();
1617 }
1618
1619 gtk_widget_show (maindlg);
1620 dialog_change_scale ();
1621 set_cmap_preview ();
1622 dialog_update_preview ();
1623 }
1624
1625 gtk_widget_destroy (GTK_WIDGET (chooser));
1626 }
1627
1628 static void
create_load_file_chooser(GtkWidget * widget,GtkWidget * dialog)1629 create_load_file_chooser (GtkWidget *widget,
1630 GtkWidget *dialog)
1631 {
1632 static GtkWidget *window = NULL;
1633
1634 if (!window)
1635 {
1636 window =
1637 gtk_file_chooser_dialog_new (_("Load Fractal Parameters"),
1638 GTK_WINDOW (dialog),
1639 GTK_FILE_CHOOSER_ACTION_OPEN,
1640
1641 _("_Cancel"), GTK_RESPONSE_CANCEL,
1642 _("_Open"), GTK_RESPONSE_OK,
1643
1644 NULL);
1645
1646 gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
1647
1648 gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
1649 GTK_RESPONSE_OK,
1650 GTK_RESPONSE_CANCEL,
1651 -1);
1652
1653 file_chooser_set_default_folder (GTK_FILE_CHOOSER (window));
1654
1655 g_signal_connect (window, "destroy",
1656 G_CALLBACK (gtk_widget_destroyed),
1657 &window);
1658 g_signal_connect (window, "response",
1659 G_CALLBACK (load_file_chooser_response),
1660 window);
1661 }
1662
1663 gtk_window_present (GTK_WINDOW (window));
1664 }
1665
1666 static void
create_save_file_chooser(GtkWidget * widget,GtkWidget * dialog)1667 create_save_file_chooser (GtkWidget *widget,
1668 GtkWidget *dialog)
1669 {
1670 static GtkWidget *window = NULL;
1671
1672 if (! window)
1673 {
1674 window =
1675 gtk_file_chooser_dialog_new (_("Save Fractal Parameters"),
1676 GTK_WINDOW (dialog),
1677 GTK_FILE_CHOOSER_ACTION_SAVE,
1678
1679 _("_Cancel"), GTK_RESPONSE_CANCEL,
1680 _("_Save"), GTK_RESPONSE_OK,
1681
1682 NULL);
1683
1684 gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
1685 GTK_RESPONSE_OK,
1686 GTK_RESPONSE_CANCEL,
1687 -1);
1688 gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
1689
1690 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (window),
1691 TRUE);
1692 g_signal_connect (window, "destroy",
1693 G_CALLBACK (gtk_widget_destroyed),
1694 &window);
1695 g_signal_connect (window, "response",
1696 G_CALLBACK (save_file_chooser_response),
1697 window);
1698 }
1699
1700 if (tpath)
1701 {
1702 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (window), tpath);
1703 }
1704 else
1705 {
1706 file_chooser_set_default_folder (GTK_FILE_CHOOSER (window));
1707 }
1708
1709 gtk_window_present (GTK_WINDOW (window));
1710 }
1711
1712 gchar*
get_line(gchar * buf,gint s,FILE * from,gint init)1713 get_line (gchar *buf,
1714 gint s,
1715 FILE *from,
1716 gint init)
1717 {
1718 gint slen;
1719 gchar *ret;
1720
1721 if (init)
1722 line_no = 1;
1723 else
1724 line_no++;
1725
1726 do
1727 {
1728 ret = fgets (buf, s, from);
1729 }
1730 while (!ferror (from) && buf[0] == '#');
1731
1732 slen = strlen (buf);
1733
1734 /* The last newline is a pain */
1735 if (slen > 0)
1736 buf[slen - 1] = '\0';
1737
1738 if (ferror (from))
1739 {
1740 g_warning ("Error reading file");
1741 return NULL;
1742 }
1743
1744 return ret;
1745 }
1746
1747 gint
load_options(fractalexplorerOBJ * xxx,FILE * fp)1748 load_options (fractalexplorerOBJ *xxx,
1749 FILE *fp)
1750 {
1751 gchar load_buf[MAX_LOAD_LINE];
1752 gchar str_buf[MAX_LOAD_LINE];
1753 gchar opt_buf[MAX_LOAD_LINE];
1754
1755 /* default values */
1756 xxx->opts = standardvals;
1757 xxx->opts.gradinvert = FALSE;
1758
1759 get_line (load_buf, MAX_LOAD_LINE, fp, 0);
1760
1761 while (!feof (fp) && strcmp (load_buf, "<EOF>"))
1762 {
1763 /* Get option name */
1764 sscanf (load_buf, "%255s %255s", str_buf, opt_buf);
1765
1766 if (!strcmp (str_buf, "fractaltype:"))
1767 {
1768 gint sp = 0;
1769
1770 sp = atoi (opt_buf);
1771 if (sp < 0)
1772 return -1;
1773 xxx->opts.fractaltype = sp;
1774 }
1775 else if (!strcmp (str_buf, "xmin:"))
1776 {
1777 xxx->opts.xmin = g_ascii_strtod (opt_buf, NULL);
1778 }
1779 else if (!strcmp (str_buf, "xmax:"))
1780 {
1781 xxx->opts.xmax = g_ascii_strtod (opt_buf, NULL);
1782 }
1783 else if (!strcmp(str_buf, "ymin:"))
1784 {
1785 xxx->opts.ymin = g_ascii_strtod (opt_buf, NULL);
1786 }
1787 else if (!strcmp (str_buf, "ymax:"))
1788 {
1789 xxx->opts.ymax = g_ascii_strtod (opt_buf, NULL);
1790 }
1791 else if (!strcmp(str_buf, "redstretch:"))
1792 {
1793 gdouble sp = g_ascii_strtod (opt_buf, NULL);
1794 xxx->opts.redstretch = sp / 128.0;
1795 }
1796 else if (!strcmp(str_buf, "greenstretch:"))
1797 {
1798 gdouble sp = g_ascii_strtod (opt_buf, NULL);
1799 xxx->opts.greenstretch = sp / 128.0;
1800 }
1801 else if (!strcmp (str_buf, "bluestretch:"))
1802 {
1803 gdouble sp = g_ascii_strtod (opt_buf, NULL);
1804 xxx->opts.bluestretch = sp / 128.0;
1805 }
1806 else if (!strcmp (str_buf, "iter:"))
1807 {
1808 xxx->opts.iter = g_ascii_strtod (opt_buf, NULL);
1809 }
1810 else if (!strcmp(str_buf, "cx:"))
1811 {
1812 xxx->opts.cx = g_ascii_strtod (opt_buf, NULL);
1813 }
1814 else if (!strcmp (str_buf, "cy:"))
1815 {
1816 xxx->opts.cy = g_ascii_strtod (opt_buf, NULL);
1817 }
1818 else if (!strcmp(str_buf, "redmode:"))
1819 {
1820 xxx->opts.redmode = atoi (opt_buf);
1821 }
1822 else if (!strcmp(str_buf, "greenmode:"))
1823 {
1824 xxx->opts.greenmode = atoi (opt_buf);
1825 }
1826 else if (!strcmp(str_buf, "bluemode:"))
1827 {
1828 xxx->opts.bluemode = atoi (opt_buf);
1829 }
1830 else if (!strcmp (str_buf, "redinvert:"))
1831 {
1832 xxx->opts.redinvert = atoi (opt_buf);
1833 }
1834 else if (!strcmp (str_buf, "greeninvert:"))
1835 {
1836 xxx->opts.greeninvert = atoi (opt_buf);
1837 }
1838 else if (!strcmp(str_buf, "blueinvert:"))
1839 {
1840 xxx->opts.blueinvert = atoi (opt_buf);
1841 }
1842 else if (!strcmp (str_buf, "colormode:"))
1843 {
1844 xxx->opts.colormode = atoi (opt_buf);
1845 }
1846
1847 get_line (load_buf, MAX_LOAD_LINE, fp, 0);
1848 }
1849
1850 return 0;
1851 }
1852
1853 void
explorer_load(void)1854 explorer_load (void)
1855 {
1856 FILE *fp;
1857 gchar load_buf[MAX_LOAD_LINE];
1858
1859 g_assert (filename != NULL);
1860
1861 fp = g_fopen (filename, "rt");
1862
1863 if (!fp)
1864 {
1865 g_message (_("Could not open '%s' for reading: %s"),
1866 gimp_filename_to_utf8 (filename), g_strerror (errno));
1867 return;
1868 }
1869 get_line (load_buf, MAX_LOAD_LINE, fp, 1);
1870
1871 if (strncmp (FRACTAL_HEADER, load_buf, strlen (load_buf)))
1872 {
1873 g_message (_("'%s' is not a FractalExplorer file"),
1874 gimp_filename_to_utf8 (filename));
1875 fclose (fp);
1876 return;
1877 }
1878 if (load_options (current_obj,fp))
1879 {
1880 g_message (_("'%s' is corrupt. Line %d Option section incorrect"),
1881 gimp_filename_to_utf8 (filename), line_no);
1882 fclose (fp);
1883 return;
1884 }
1885
1886 wvals = current_obj->opts;
1887
1888 fclose (fp);
1889 }
1890