summaryrefslogtreecommitdiffstats
path: root/plug-ins/fractal-explorer/fractal-explorer-dialogs.c
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/fractal-explorer/fractal-explorer-dialogs.c')
-rw-r--r--plug-ins/fractal-explorer/fractal-explorer-dialogs.c1889
1 files changed, 1889 insertions, 0 deletions
diff --git a/plug-ins/fractal-explorer/fractal-explorer-dialogs.c b/plug-ins/fractal-explorer/fractal-explorer-dialogs.c
new file mode 100644
index 0000000..8f53860
--- /dev/null
+++ b/plug-ins/fractal-explorer/fractal-explorer-dialogs.c
@@ -0,0 +1,1889 @@
+/**********************************************************************
+ GIMP - The GNU Image Manipulation Program
+ Copyright (C) 1995 Spencer Kimball and Peter Mattis
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *********************************************************************/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "fractal-explorer.h"
+#include "fractal-explorer-dialogs.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define ZOOM_UNDO_SIZE 100
+
+
+static gint n_gradient_samples = 0;
+static gdouble *gradient_samples = NULL;
+static gchar *gradient_name = NULL;
+static gboolean ready_now = FALSE;
+static gchar *tpath = NULL;
+static DialogElements *elements = NULL;
+static GtkWidget *cmap_preview;
+static GtkWidget *maindlg;
+
+static explorer_vals_t zooms[ZOOM_UNDO_SIZE];
+static gint zoomindex = 0;
+static gint zoommax = 0;
+
+static gint oldxpos = -1;
+static gint oldypos = -1;
+static gdouble x_press = -1.0;
+static gdouble y_press = -1.0;
+
+static explorer_vals_t standardvals =
+{
+ 0,
+ -2.0,
+ 2.0,
+ -1.5,
+ 1.5,
+ 50.0,
+ -0.75,
+ -0.2,
+ 0,
+ 1.0,
+ 1.0,
+ 1.0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 256,
+ 0
+};
+
+/**********************************************************************
+ FORWARD DECLARATIONS
+ *********************************************************************/
+
+static void load_file_chooser_response (GtkFileChooser *chooser,
+ gint response_id,
+ gpointer data);
+static void save_file_chooser_response (GtkFileChooser *chooser,
+ gint response_id,
+ gpointer data);
+static void create_load_file_chooser (GtkWidget *widget,
+ GtkWidget *dialog);
+static void create_save_file_chooser (GtkWidget *widget,
+ GtkWidget *dialog);
+
+static void cmap_preview_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+/**********************************************************************
+ CALLBACKS
+ *********************************************************************/
+
+static void
+dialog_response (GtkWidget *widget,
+ gint response_id,
+ gpointer data)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_OK:
+ wint.run = TRUE;
+ gtk_widget_destroy (widget);
+ break;
+
+ default:
+ gtk_widget_destroy (widget);
+ break;
+ }
+}
+
+static void
+dialog_reset_callback (GtkWidget *widget,
+ gpointer data)
+{
+ wvals.xmin = standardvals.xmin;
+ wvals.xmax = standardvals.xmax;
+ wvals.ymin = standardvals.ymin;
+ wvals.ymax = standardvals.ymax;
+ wvals.iter = standardvals.iter;
+ wvals.cx = standardvals.cx;
+ wvals.cy = standardvals.cy;
+
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+dialog_redraw_callback (GtkWidget *widget,
+ gpointer data)
+{
+ gint alwaysprev = wvals.alwayspreview;
+
+ wvals.alwayspreview = TRUE;
+ set_cmap_preview ();
+ dialog_update_preview ();
+ wvals.alwayspreview = alwaysprev;
+}
+
+static void
+dialog_undo_zoom_callback (GtkWidget *widget,
+ gpointer data)
+{
+ if (zoomindex > 0)
+ {
+ zooms[zoomindex] = wvals;
+ zoomindex--;
+ wvals = zooms[zoomindex];
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+ }
+}
+
+static void
+dialog_redo_zoom_callback (GtkWidget *widget,
+ gpointer data)
+{
+ if (zoomindex < zoommax)
+ {
+ zoomindex++;
+ wvals = zooms[zoomindex];
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+ }
+}
+
+static void
+dialog_step_in_callback (GtkWidget *widget,
+ gpointer data)
+{
+ double xdifferenz;
+ double ydifferenz;
+
+ if (zoomindex < ZOOM_UNDO_SIZE - 1)
+ {
+ zooms[zoomindex]=wvals;
+ zoomindex++;
+ }
+ zoommax = zoomindex;
+
+ xdifferenz = wvals.xmax - wvals.xmin;
+ ydifferenz = wvals.ymax - wvals.ymin;
+ wvals.xmin += 1.0 / 6.0 * xdifferenz;
+ wvals.ymin += 1.0 / 6.0 * ydifferenz;
+ wvals.xmax -= 1.0 / 6.0 * xdifferenz;
+ wvals.ymax -= 1.0 / 6.0 * ydifferenz;
+ zooms[zoomindex] = wvals;
+
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+dialog_step_out_callback (GtkWidget *widget,
+ gpointer data)
+{
+ gdouble xdifferenz;
+ gdouble ydifferenz;
+
+ if (zoomindex < ZOOM_UNDO_SIZE - 1)
+ {
+ zooms[zoomindex]=wvals;
+ zoomindex++;
+ }
+ zoommax = zoomindex;
+
+ xdifferenz = wvals.xmax - wvals.xmin;
+ ydifferenz = wvals.ymax - wvals.ymin;
+ wvals.xmin -= 1.0 / 4.0 * xdifferenz;
+ wvals.ymin -= 1.0 / 4.0 * ydifferenz;
+ wvals.xmax += 1.0 / 4.0 * xdifferenz;
+ wvals.ymax += 1.0 / 4.0 * ydifferenz;
+ zooms[zoomindex] = wvals;
+
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+explorer_toggle_update (GtkWidget *widget,
+ gpointer data)
+{
+ gimp_toggle_button_update (widget, data);
+
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+explorer_radio_update (GtkWidget *widget,
+ gpointer data)
+{
+ gboolean c_sensitive;
+
+ gimp_radio_button_update (widget, data);
+
+ switch (wvals.fractaltype)
+ {
+ case TYPE_MANDELBROT:
+ case TYPE_SIERPINSKI:
+ c_sensitive = FALSE;
+ break;
+
+ default:
+ c_sensitive = TRUE;
+ break;
+ }
+
+ gimp_scale_entry_set_sensitive (elements->cx, c_sensitive);
+ gimp_scale_entry_set_sensitive (elements->cy, c_sensitive);
+
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+explorer_double_adjustment_update (GtkAdjustment *adjustment,
+ gpointer data)
+{
+ gimp_double_adjustment_update (adjustment, data);
+
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+explorer_number_of_colors_callback (GtkAdjustment *adjustment,
+ gpointer data)
+{
+ gimp_int_adjustment_update (adjustment, data);
+
+ g_free (gradient_samples);
+
+ if (! gradient_name)
+ gradient_name = gimp_context_get_gradient ();
+
+ gimp_gradient_get_uniform_samples (gradient_name,
+ wvals.ncolors,
+ wvals.gradinvert,
+ &n_gradient_samples,
+ &gradient_samples);
+
+ set_cmap_preview ();
+ dialog_update_preview ();
+}
+
+static void
+explorer_gradient_select_callback (GimpGradientSelectButton *gradient_button,
+ const gchar *name,
+ gint width,
+ const gdouble *gradient_data,
+ gboolean dialog_closing,
+ gpointer data)
+{
+ g_free (gradient_name);
+ g_free (gradient_samples);
+
+ gradient_name = g_strdup (name);
+
+ gimp_gradient_get_uniform_samples (gradient_name,
+ wvals.ncolors,
+ wvals.gradinvert,
+ &n_gradient_samples,
+ &gradient_samples);
+
+ if (wvals.colormode == 1)
+ {
+ set_cmap_preview ();
+ dialog_update_preview ();
+ }
+}
+
+static void
+preview_draw_crosshair (gint px,
+ gint py)
+{
+ gint x, y;
+ guchar *p_ul;
+
+ p_ul = wint.wimage + 3 * (preview_width * py + 0);
+
+ for (x = 0; x < preview_width; x++)
+ {
+ p_ul[0] ^= 254;
+ p_ul[1] ^= 254;
+ p_ul[2] ^= 254;
+ p_ul += 3;
+ }
+
+ p_ul = wint.wimage + 3 * (preview_width * 0 + px);
+
+ for (y = 0; y < preview_height; y++)
+ {
+ p_ul[0] ^= 254;
+ p_ul[1] ^= 254;
+ p_ul[2] ^= 254;
+ p_ul += 3 * preview_width;
+ }
+}
+
+static void
+preview_redraw (void)
+{
+ gimp_preview_area_draw (GIMP_PREVIEW_AREA (wint.preview),
+ 0, 0, preview_width, preview_height,
+ GIMP_RGB_IMAGE,
+ wint.wimage, preview_width * 3);
+
+ gtk_widget_queue_draw (wint.preview);
+}
+
+static gboolean
+preview_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (event->button == 1)
+ {
+ x_press = event->x;
+ y_press = event->y;
+ xbild = preview_width;
+ ybild = preview_height;
+ xdiff = (xmax - xmin) / xbild;
+ ydiff = (ymax - ymin) / ybild;
+
+ preview_draw_crosshair (x_press, y_press);
+ preview_redraw ();
+ }
+ return TRUE;
+}
+
+static gboolean
+preview_motion_notify_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (oldypos != -1)
+ {
+ preview_draw_crosshair (oldxpos, oldypos);
+ }
+
+ oldxpos = event->x;
+ oldypos = event->y;
+
+ if ((oldxpos >= 0.0) &&
+ (oldypos >= 0.0) &&
+ (oldxpos < preview_width) &&
+ (oldypos < preview_height))
+ {
+ preview_draw_crosshair (oldxpos, oldypos);
+ }
+ else
+ {
+ oldypos = -1;
+ oldxpos = -1;
+ }
+
+ preview_redraw ();
+
+ return TRUE;
+}
+
+static gboolean
+preview_leave_notify_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (oldypos != -1)
+ {
+ preview_draw_crosshair (oldxpos, oldypos);
+ }
+ oldxpos = -1;
+ oldypos = -1;
+
+ preview_redraw ();
+
+ gdk_window_set_cursor (gtk_widget_get_window (maindlg), NULL);
+
+ return TRUE;
+}
+
+static gboolean
+preview_enter_notify_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ static GdkCursor *cursor = NULL;
+
+ if (! cursor)
+ {
+ GdkDisplay *display = gtk_widget_get_display (maindlg);
+
+ cursor = gdk_cursor_new_for_display (display, GDK_TCROSS);
+
+ }
+
+ gdk_window_set_cursor (gtk_widget_get_window (maindlg), cursor);
+
+ return TRUE;
+}
+
+static gboolean
+preview_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ gdouble l_xmin;
+ gdouble l_xmax;
+ gdouble l_ymin;
+ gdouble l_ymax;
+
+ if (event->button == 1)
+ {
+ gdouble x_release, y_release;
+
+ x_release = event->x;
+ y_release = event->y;
+
+ if ((x_press >= 0.0) && (y_press >= 0.0) &&
+ (x_release >= 0.0) && (y_release >= 0.0) &&
+ (x_press < preview_width) && (y_press < preview_height) &&
+ (x_release < preview_width) && (y_release < preview_height))
+ {
+ l_xmin = (wvals.xmin +
+ (wvals.xmax - wvals.xmin) * (x_press / preview_width));
+ l_xmax = (wvals.xmin +
+ (wvals.xmax - wvals.xmin) * (x_release / preview_width));
+ l_ymin = (wvals.ymin +
+ (wvals.ymax - wvals.ymin) * (y_press / preview_height));
+ l_ymax = (wvals.ymin +
+ (wvals.ymax - wvals.ymin) * (y_release / preview_height));
+
+ if (zoomindex < ZOOM_UNDO_SIZE - 1)
+ {
+ zooms[zoomindex] = wvals;
+ zoomindex++;
+ }
+ zoommax = zoomindex;
+ wvals.xmin = l_xmin;
+ wvals.xmax = l_xmax;
+ wvals.ymin = l_ymin;
+ wvals.ymax = l_ymax;
+ dialog_change_scale ();
+ dialog_update_preview ();
+ oldypos = oldxpos = -1;
+ }
+ }
+
+ return TRUE;
+}
+
+/**********************************************************************
+ FUNCTION: explorer_dialog
+ *********************************************************************/
+
+gint
+explorer_dialog (void)
+{
+ GtkWidget *dialog;
+ GtkWidget *top_hbox;
+ GtkWidget *left_vbox;
+ GtkWidget *abox;
+ GtkWidget *vbox;
+ GtkWidget *bbox;
+ GtkWidget *frame;
+ GtkWidget *toggle;
+ GtkWidget *toggle_vbox;
+ GtkWidget *toggle_vbox2;
+ GtkWidget *toggle_vbox3;
+ GtkWidget *notebook;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *button;
+ GtkWidget *gradient;
+ gchar *path;
+ gchar *gradient_name;
+ GSList *group = NULL;
+ gint i;
+
+ gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+ path = gimp_gimprc_query ("fractalexplorer-path");
+
+ if (path)
+ {
+ fractalexplorer_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
+ g_free (path);
+ }
+ else
+ {
+ gchar *gimprc = gimp_personal_rc_file ("gimprc");
+ gchar *full_path = gimp_config_build_data_path ("fractalexplorer");
+ gchar *esc_path = g_strescape (full_path, NULL);
+ g_free (full_path);
+
+ g_message (_("No %s in gimprc:\n"
+ "You need to add an entry like\n"
+ "(%s \"%s\")\n"
+ "to your %s file."),
+ "fractalexplorer-path",
+ "fractalexplorer-path",
+ esc_path, gimp_filename_to_utf8 (gimprc));
+
+ g_free (gimprc);
+ g_free (esc_path);
+ }
+
+ wint.wimage = g_new (guchar, preview_width * preview_height * 3);
+ elements = g_new (DialogElements, 1);
+
+ dialog = maindlg =
+ gimp_dialog_new (_("Fractal Explorer"), PLUG_IN_ROLE,
+ NULL, 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_OK"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (dialog_response),
+ NULL);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
+
+ top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (top_hbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ top_hbox, FALSE, FALSE, 0);
+ gtk_widget_show (top_hbox);
+
+ left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_box_pack_start (GTK_BOX (top_hbox), left_vbox, FALSE, FALSE, 0);
+ gtk_widget_show (left_vbox);
+
+ /* Preview */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (left_vbox), vbox, FALSE, FALSE, 0);
+ gtk_widget_show (vbox);
+
+ abox = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
+ gtk_widget_show (abox);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (abox), frame);
+ gtk_widget_show (frame);
+
+ wint.preview = gimp_preview_area_new ();
+ gtk_widget_set_size_request (wint.preview, preview_width, preview_height);
+ gtk_container_add (GTK_CONTAINER (frame), wint.preview);
+
+ g_signal_connect (wint.preview, "button-press-event",
+ G_CALLBACK (preview_button_press_event),
+ NULL);
+ g_signal_connect (wint.preview, "button-release-event",
+ G_CALLBACK (preview_button_release_event),
+ NULL);
+ g_signal_connect (wint.preview, "motion-notify-event",
+ G_CALLBACK (preview_motion_notify_event),
+ NULL);
+ g_signal_connect (wint.preview, "leave-notify-event",
+ G_CALLBACK (preview_leave_notify_event),
+ NULL);
+ g_signal_connect (wint.preview, "enter-notify-event",
+ G_CALLBACK (preview_enter_notify_event),
+ NULL);
+
+ gtk_widget_set_events (wint.preview, (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_ENTER_NOTIFY_MASK));
+ gtk_widget_show (wint.preview);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("Re_altime preview"));
+ gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_toggle_update),
+ &wvals.alwayspreview);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ wvals.alwayspreview);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle, _("If enabled the preview will "
+ "be redrawn automatically"), NULL);
+
+ button = gtk_button_new_with_mnemonic (_("R_edraw preview"));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_redraw_callback),
+ dialog);
+ gtk_widget_show (button);
+
+ /* Zoom Options */
+ frame = gimp_frame_new (_("Zoom"));
+ gtk_box_pack_start (GTK_BOX (left_vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+ gtk_widget_show (bbox);
+
+ button = gtk_button_new_with_mnemonic (_("Zoom _In"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_step_in_callback),
+ dialog);
+
+ button = gtk_button_new_with_mnemonic (_("Zoom _Out"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_step_out_callback),
+ dialog);
+
+ bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+ gtk_widget_show (bbox);
+
+ button = gtk_button_new_with_mnemonic (_("_Undo"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ gimp_help_set_help_data (button, _("Undo last zoom change"), NULL);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_undo_zoom_callback),
+ dialog);
+
+ button = gtk_button_new_with_mnemonic (_("_Redo"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ gimp_help_set_help_data (button, _("Redo last zoom change"), NULL);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_redo_zoom_callback),
+ dialog);
+
+ /* Create notebook */
+ notebook = gtk_notebook_new ();
+ gtk_box_pack_start (GTK_BOX (top_hbox), notebook, FALSE, FALSE, 0);
+ gtk_widget_show (notebook);
+
+ /* "Parameters" page */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
+ gtk_label_new_with_mnemonic (_("_Parameters")));
+ gtk_widget_show (vbox);
+
+ frame = gimp_frame_new (_("Fractal Parameters"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (8, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 6, 12);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ elements->xmin =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
+ _("Left:"), SCALE_WIDTH, 10,
+ wvals.xmin, -3, 3, 0.001, 0.01, 5,
+ TRUE, 0, 0, NULL, NULL);
+ g_signal_connect (elements->xmin, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.xmin);
+
+ elements->xmax =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
+ _("Right:"), SCALE_WIDTH, 10,
+ wvals.xmax, -3, 3, 0.001, 0.01, 5,
+ TRUE, 0, 0, NULL, NULL);
+ g_signal_connect (elements->xmax, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.xmax);
+
+ elements->ymin =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
+ _("Top:"), SCALE_WIDTH, 10,
+ wvals.ymin, -3, 3, 0.001, 0.01, 5,
+ TRUE, 0, 0, NULL, NULL);
+ g_signal_connect (elements->ymin, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.ymin);
+
+ elements->ymax =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
+ _("Bottom:"), SCALE_WIDTH, 10,
+ wvals.ymax, -3, 3, 0.001, 0.01, 5,
+ TRUE, 0, 0, NULL, NULL);
+ g_signal_connect (elements->ymax, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.ymax);
+
+ elements->iter =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
+ _("Iterations:"), SCALE_WIDTH, 10,
+ wvals.iter, 1, 1000, 1, 10, 0,
+ TRUE, 0, 0,
+ _("The higher the number of iterations, "
+ "the more details will be calculated"), NULL);
+ g_signal_connect (elements->iter, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.iter);
+
+ elements->cx =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 5,
+ _("CX:"), SCALE_WIDTH, 10,
+ wvals.cx, -2.5, 2.5, 0.001, 0.01, 5,
+ TRUE, 0, 0,
+ _("Changes aspect of fractal"), NULL);
+ g_signal_connect (elements->cx, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.cx);
+
+ elements->cy =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 6,
+ _("CY:"), SCALE_WIDTH, 10,
+ wvals.cy, -2.5, 2.5, 0.001, 0.01, 5,
+ TRUE, 0, 0,
+ _("Changes aspect of fractal"), NULL);
+ g_signal_connect (elements->cy, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.cy);
+
+ bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
+ gtk_table_attach_defaults (GTK_TABLE (table), bbox, 0, 3, 7, 8);
+ gtk_widget_show (bbox);
+
+ button = gtk_button_new_with_mnemonic (_("_Open"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (create_load_file_chooser),
+ dialog);
+ gtk_widget_show (button);
+ gimp_help_set_help_data (button, _("Load a fractal from file"), NULL);
+
+ button = gtk_button_new_with_mnemonic (_("_Reset"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (dialog_reset_callback),
+ dialog);
+ gtk_widget_show (button);
+ gimp_help_set_help_data (button, _("Reset parameters to default values"),
+ NULL);
+
+ button = gtk_button_new_with_mnemonic (_("_Save"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (create_save_file_chooser),
+ dialog);
+ gtk_widget_show (button);
+ gimp_help_set_help_data (button, _("Save active fractal to file"), NULL);
+
+ /* Fractal type toggle box */
+ frame = gimp_frame_new (_("Fractal Type"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+ gtk_widget_show (hbox);
+
+ toggle_vbox =
+ gimp_int_radio_group_new (FALSE, NULL,
+ G_CALLBACK (explorer_radio_update),
+ &wvals.fractaltype, wvals.fractaltype,
+
+ _("Mandelbrot"), TYPE_MANDELBROT,
+ &(elements->type[TYPE_MANDELBROT]),
+ _("Julia"), TYPE_JULIA,
+ &(elements->type[TYPE_JULIA]),
+ _("Barnsley 1"), TYPE_BARNSLEY_1,
+ &(elements->type[TYPE_BARNSLEY_1]),
+ _("Barnsley 2"), TYPE_BARNSLEY_2,
+ &(elements->type[TYPE_BARNSLEY_2]),
+ _("Barnsley 3"), TYPE_BARNSLEY_3,
+ &(elements->type[TYPE_BARNSLEY_3]),
+ _("Spider"), TYPE_SPIDER,
+ &(elements->type[TYPE_SPIDER]),
+ _("Man'o'war"), TYPE_MAN_O_WAR,
+ &(elements->type[TYPE_MAN_O_WAR]),
+ _("Lambda"), TYPE_LAMBDA,
+ &(elements->type[TYPE_LAMBDA]),
+ _("Sierpinski"), TYPE_SIERPINSKI,
+ &(elements->type[TYPE_SIERPINSKI]),
+
+ NULL);
+
+ toggle_vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ for (i = TYPE_BARNSLEY_2; i <= TYPE_SPIDER; i++)
+ {
+ g_object_ref (elements->type[i]);
+
+ gtk_widget_hide (elements->type[i]);
+ gtk_container_remove (GTK_CONTAINER (toggle_vbox), elements->type[i]);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox2), elements->type[i],
+ FALSE, FALSE, 0);
+ gtk_widget_show (elements->type[i]);
+
+ g_object_unref (elements->type[i]);
+ }
+
+ toggle_vbox3 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ for (i = TYPE_MAN_O_WAR; i <= TYPE_SIERPINSKI; i++)
+ {
+ g_object_ref (elements->type[i]);
+
+ gtk_widget_hide (elements->type[i]);
+ gtk_container_remove (GTK_CONTAINER (toggle_vbox), elements->type[i]);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox3), elements->type[i],
+ FALSE, FALSE, 0);
+ gtk_widget_show (elements->type[i]);
+
+ g_object_unref (elements->type[i]);
+ }
+
+ gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox, FALSE, FALSE, 0);
+ gtk_widget_show (toggle_vbox);
+
+ gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox2, FALSE, FALSE, 0);
+ gtk_widget_show (toggle_vbox2);
+
+ gtk_box_pack_start (GTK_BOX (hbox), toggle_vbox3, FALSE, FALSE, 0);
+ gtk_widget_show (toggle_vbox3);
+
+ /* Color page */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
+ gtk_label_new_with_mnemonic (_("Co_lors")));
+ gtk_widget_show (vbox);
+
+ /* Number of Colors frame */
+ frame = gimp_frame_new (_("Number of Colors"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (2, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ elements->ncol =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
+ _("Number of colors:"), SCALE_WIDTH, 0,
+ wvals.ncolors, 2, MAXNCOLORS, 1, 10, 0,
+ TRUE, 0, 0,
+ _("Change the number of colors in the mapping"),
+ NULL);
+ g_signal_connect (elements->ncol, "value-changed",
+ G_CALLBACK (explorer_number_of_colors_callback),
+ &wvals.ncolors);
+
+ elements->useloglog = toggle =
+ gtk_check_button_new_with_label (_("Use loglog smoothing"));
+ gtk_table_attach_defaults (GTK_TABLE (table), toggle, 0, 3, 1, 2);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_toggle_update),
+ &wvals.useloglog);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.useloglog);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle, _("Use log log smoothing to eliminate "
+ "\"banding\" in the result"), NULL);
+
+ /* Color Density frame */
+ frame = gimp_frame_new (_("Color Density"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (3, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ elements->red =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
+ _("Red:"), SCALE_WIDTH, 0,
+ wvals.redstretch, 0, 1, 0.01, 0.1, 2,
+ TRUE, 0, 0,
+ _("Change the intensity of the red channel"), NULL);
+ g_signal_connect (elements->red, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.redstretch);
+
+ elements->green =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
+ _("Green:"), SCALE_WIDTH, 0,
+ wvals.greenstretch, 0, 1, 0.01, 0.1, 2,
+ TRUE, 0, 0,
+ _("Change the intensity of the green channel"), NULL);
+ g_signal_connect (elements->green, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.greenstretch);
+
+ elements->blue =
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
+ _("Blue:"), SCALE_WIDTH, 0,
+ wvals.bluestretch, 0, 1, 0.01, 0.1, 2,
+ TRUE, 0, 0,
+ _("Change the intensity of the blue channel"), NULL);
+ g_signal_connect (elements->blue, "value-changed",
+ G_CALLBACK (explorer_double_adjustment_update),
+ &wvals.bluestretch);
+
+ /* Color Function frame */
+ frame = gimp_frame_new (_("Color Function"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+ gtk_widget_show (hbox);
+
+ /* Redmode radio frame */
+ frame = gimp_int_radio_group_new (TRUE, _("Red"),
+ G_CALLBACK (explorer_radio_update),
+ &wvals.redmode, wvals.redmode,
+
+ _("Sine"), SINUS,
+ &elements->redmode[SINUS],
+ _("Cosine"), COSINUS,
+ &elements->redmode[COSINUS],
+ C_("color-function", "None"), NONE,
+ &elements->redmode[NONE],
+
+ NULL);
+ gimp_help_set_help_data (elements->redmode[SINUS],
+ _("Use sine-function for this color component"),
+ NULL);
+ gimp_help_set_help_data (elements->redmode[COSINUS],
+ _("Use cosine-function for this color "
+ "component"), NULL);
+ gimp_help_set_help_data (elements->redmode[NONE],
+ _("Use linear mapping instead of any "
+ "trigonometrical function for this color "
+ "channel"), NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
+
+ elements->redinvert = toggle =
+ gtk_check_button_new_with_label (_("Inversion"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.redinvert);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_toggle_update),
+ &wvals.redinvert);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle,
+ _("If you enable this option higher color values "
+ "will be swapped with lower ones and vice "
+ "versa"), NULL);
+
+ /* Greenmode radio frame */
+ frame = gimp_int_radio_group_new (TRUE, _("Green"),
+ G_CALLBACK (explorer_radio_update),
+ &wvals.greenmode, wvals.greenmode,
+
+ _("Sine"), SINUS,
+ &elements->greenmode[SINUS],
+ _("Cosine"), COSINUS,
+ &elements->greenmode[COSINUS],
+ C_("color-function", "None"), NONE,
+ &elements->greenmode[NONE],
+
+ NULL);
+ gimp_help_set_help_data (elements->greenmode[SINUS],
+ _("Use sine-function for this color component"),
+ NULL);
+ gimp_help_set_help_data (elements->greenmode[COSINUS],
+ _("Use cosine-function for this color "
+ "component"), NULL);
+ gimp_help_set_help_data (elements->greenmode[NONE],
+ _("Use linear mapping instead of any "
+ "trigonometrical function for this color "
+ "channel"), NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
+
+ elements->greeninvert = toggle =
+ gtk_check_button_new_with_label (_("Inversion"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), wvals.greeninvert);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_toggle_update),
+ &wvals.greeninvert);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle,
+ _("If you enable this option higher color values "
+ "will be swapped with lower ones and vice "
+ "versa"), NULL);
+
+ /* Bluemode radio frame */
+ frame = gimp_int_radio_group_new (TRUE, _("Blue"),
+ G_CALLBACK (explorer_radio_update),
+ &wvals.bluemode, wvals.bluemode,
+
+ _("Sine"), SINUS,
+ &elements->bluemode[SINUS],
+ _("Cosine"), COSINUS,
+ &elements->bluemode[COSINUS],
+ C_("color-function", "None"), NONE,
+ &elements->bluemode[NONE],
+
+ NULL);
+ gimp_help_set_help_data (elements->bluemode[SINUS],
+ _("Use sine-function for this color component"),
+ NULL);
+ gimp_help_set_help_data (elements->bluemode[COSINUS],
+ _("Use cosine-function for this color "
+ "component"), NULL);
+ gimp_help_set_help_data (elements->bluemode[NONE],
+ _("Use linear mapping instead of any "
+ "trigonometrical function for this color "
+ "channel"), NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ toggle_vbox = gtk_bin_get_child (GTK_BIN (frame));
+
+ elements->blueinvert = toggle =
+ gtk_check_button_new_with_label (_("Inversion"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON( toggle), wvals.blueinvert);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_toggle_update),
+ &wvals.blueinvert);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle,
+ _("If you enable this option higher color values "
+ "will be swapped with lower ones and vice "
+ "versa"), NULL);
+
+ /* Colormode toggle box */
+ frame = gimp_frame_new (_("Color Mode"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ toggle_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
+ gtk_widget_show (toggle_vbox);
+
+ toggle = elements->colormode[0] =
+ gtk_radio_button_new_with_label (group, _("As specified above"));
+ group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
+ g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
+ GINT_TO_POINTER (0));
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_radio_update),
+ &wvals.colormode);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ wvals.colormode == 0);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle,
+ _("Create a color-map with the options you "
+ "specified above (color density/function). The "
+ "result is visible in the preview image"), NULL);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ toggle = elements->colormode[1] =
+ gtk_radio_button_new_with_label (group,
+ _("Apply active gradient to final image"));
+ group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
+ gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
+ g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
+ GINT_TO_POINTER (1));
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (explorer_radio_update),
+ &wvals.colormode);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ wvals.colormode == 1);
+ gtk_widget_show (toggle);
+ gimp_help_set_help_data (toggle,
+ _("Create a color-map using a gradient from "
+ "the gradient editor"), NULL);
+
+ gradient_name = gimp_context_get_gradient ();
+
+ gimp_gradient_get_uniform_samples (gradient_name,
+ wvals.ncolors,
+ wvals.gradinvert,
+ &n_gradient_samples,
+ &gradient_samples);
+
+ gradient = gimp_gradient_select_button_new (_("FractalExplorer Gradient"),
+ gradient_name);
+ g_signal_connect (gradient, "gradient-set",
+ G_CALLBACK (explorer_gradient_select_callback), NULL);
+ g_free (gradient_name);
+ gtk_box_pack_start (GTK_BOX (hbox), gradient, FALSE, FALSE, 0);
+ gtk_widget_show (gradient);
+
+ abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+ {
+ gint xsize, ysize;
+
+ for (ysize = 1; ysize * ysize * ysize < 8192; ysize++) /**/;
+ xsize = wvals.ncolors / ysize;
+ while (xsize * ysize < 8192) xsize++;
+
+ gtk_widget_set_size_request (abox, xsize, ysize * 4);
+ }
+ gtk_box_pack_start (GTK_BOX (toggle_vbox), abox, FALSE, FALSE, 0);
+ gtk_widget_show (abox);
+
+ cmap_preview = gimp_preview_area_new ();
+ gtk_widget_set_size_request (cmap_preview, 32, 32);
+ gtk_container_add (GTK_CONTAINER (abox), cmap_preview);
+ g_signal_connect (cmap_preview, "size-allocate",
+ G_CALLBACK (cmap_preview_size_allocate), NULL);
+ gtk_widget_show (cmap_preview);
+
+ frame = add_objects_list ();
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame,
+ gtk_label_new_with_mnemonic (_("_Fractals")));
+ gtk_widget_show (frame);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
+
+ gtk_widget_show (dialog);
+ ready_now = TRUE;
+
+ set_cmap_preview ();
+ dialog_update_preview ();
+
+ gtk_main ();
+
+ g_free (wint.wimage);
+
+ return wint.run;
+}
+
+
+/**********************************************************************
+ FUNCTION: dialog_update_preview
+ *********************************************************************/
+
+void
+dialog_update_preview (void)
+{
+ gint ycoord;
+ guchar *p_ul;
+
+ if (NULL == wint.preview)
+ return;
+
+ if (ready_now && wvals.alwayspreview)
+ {
+ xmin = wvals.xmin;
+ xmax = wvals.xmax;
+ ymin = wvals.ymin;
+ ymax = wvals.ymax;
+ xbild = preview_width;
+ ybild = preview_height;
+ xdiff = (xmax - xmin) / xbild;
+ ydiff = (ymax - ymin) / ybild;
+
+ p_ul = wint.wimage;
+
+ for (ycoord = 0; ycoord < preview_height; ycoord++)
+ {
+ explorer_render_row (NULL,
+ p_ul,
+ ycoord,
+ preview_width,
+ 3);
+ p_ul += preview_width * 3;
+ }
+
+ preview_redraw ();
+ }
+}
+
+/**********************************************************************
+ FUNCTION: cmap_preview_size_allocate()
+ *********************************************************************/
+
+static void
+cmap_preview_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ gint i;
+ gint x;
+ gint y;
+ gint j;
+ guchar *b;
+ GimpPreviewArea *preview = GIMP_PREVIEW_AREA (widget);
+
+ b = g_new (guchar, allocation->width * allocation->height * 3);
+
+ for (y = 0; y < allocation->height; y++)
+ {
+ for (x = 0; x < allocation->width; x++)
+ {
+ i = x + (y / 4) * allocation->width;
+ if (i > wvals.ncolors)
+ {
+ for (j = 0; j < 3; j++)
+ b[(y*allocation->width + x) * 3 + j] = 0;
+ }
+ else
+ {
+ b[(y*allocation->width + x) * 3] = colormap[i].r;
+ b[(y*allocation->width + x) * 3 + 1] = colormap[i].g;
+ b[(y*allocation->width + x) * 3 + 2] = colormap[i].b;
+ }
+ }
+ }
+ gimp_preview_area_draw (preview,
+ 0, 0, allocation->width, allocation->height,
+ GIMP_RGB_IMAGE, b, allocation->width*3);
+ gtk_widget_queue_draw (cmap_preview);
+
+ g_free (b);
+
+}
+
+/**********************************************************************
+ FUNCTION: set_cmap_preview()
+ *********************************************************************/
+
+void
+set_cmap_preview (void)
+{
+ gint xsize, ysize;
+
+ if (NULL == cmap_preview)
+ return;
+
+ make_color_map ();
+
+ for (ysize = 1; ysize * ysize * ysize < wvals.ncolors; ysize++)
+ /**/;
+ xsize = wvals.ncolors / ysize;
+ while (xsize * ysize < wvals.ncolors)
+ xsize++;
+
+ gtk_widget_set_size_request (cmap_preview, xsize, ysize * 4);
+}
+
+/**********************************************************************
+ FUNCTION: make_color_map()
+ *********************************************************************/
+
+void
+make_color_map (void)
+{
+ gint i;
+ gint r;
+ gint gr;
+ gint bl;
+ gdouble redstretch;
+ gdouble greenstretch;
+ gdouble bluestretch;
+ gdouble pi = atan (1) * 4;
+
+ /* get gradient samples if they don't exist -- fixes gradient color
+ * mode for noninteractive use (bug #103470).
+ */
+ if (gradient_samples == NULL)
+ {
+ gchar *gradient_name = gimp_context_get_gradient ();
+
+ gimp_gradient_get_uniform_samples (gradient_name,
+ wvals.ncolors,
+ wvals.gradinvert,
+ &n_gradient_samples,
+ &gradient_samples);
+
+ g_free (gradient_name);
+ }
+
+ redstretch = wvals.redstretch * 127.5;
+ greenstretch = wvals.greenstretch * 127.5;
+ bluestretch = wvals.bluestretch * 127.5;
+
+ for (i = 0; i < wvals.ncolors; i++)
+ if (wvals.colormode == 1)
+ {
+ colormap[i].r = (guchar)(gradient_samples[i * 4] * 255.9);
+ colormap[i].g = (guchar)(gradient_samples[i * 4 + 1] * 255.9);
+ colormap[i].b = (guchar)(gradient_samples[i * 4 + 2] * 255.9);
+ }
+ else
+ {
+ double x = (i*2.0) / wvals.ncolors;
+ r = gr = bl = 0;
+
+ switch (wvals.redmode)
+ {
+ case SINUS:
+ r = (int) redstretch *(1.0 + sin((x - 1) * pi));
+ break;
+ case COSINUS:
+ r = (int) redstretch *(1.0 + cos((x - 1) * pi));
+ break;
+ case NONE:
+ r = (int)(redstretch *(x));
+ break;
+ default:
+ break;
+ }
+
+ switch (wvals.greenmode)
+ {
+ case SINUS:
+ gr = (int) greenstretch *(1.0 + sin((x - 1) * pi));
+ break;
+ case COSINUS:
+ gr = (int) greenstretch *(1.0 + cos((x - 1) * pi));
+ break;
+ case NONE:
+ gr = (int)(greenstretch *(x));
+ break;
+ default:
+ break;
+ }
+
+ switch (wvals.bluemode)
+ {
+ case SINUS:
+ bl = (int) bluestretch * (1.0 + sin ((x - 1) * pi));
+ break;
+ case COSINUS:
+ bl = (int) bluestretch * (1.0 + cos ((x - 1) * pi));
+ break;
+ case NONE:
+ bl = (int) (bluestretch * x);
+ break;
+ default:
+ break;
+ }
+
+ r = MIN (r, 255);
+ gr = MIN (gr, 255);
+ bl = MIN (bl, 255);
+
+ if (wvals.redinvert)
+ r = 255 - r;
+
+ if (wvals.greeninvert)
+ gr = 255 - gr;
+
+ if (wvals.blueinvert)
+ bl = 255 - bl;
+
+ colormap[i].r = r;
+ colormap[i].g = gr;
+ colormap[i].b = bl;
+ }
+}
+
+/**********************************************************************
+ FUNCTION: dialog_change_scale
+ *********************************************************************/
+
+void
+dialog_change_scale (void)
+{
+ ready_now = FALSE;
+
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->xmin), wvals.xmin);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->xmax), wvals.xmax);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->ymin), wvals.ymin);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->ymax), wvals.ymax);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->iter), wvals.iter);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->cx), wvals.cx);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->cy), wvals.cy);
+
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->red), wvals.redstretch);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->green),wvals.greenstretch);
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (elements->blue), wvals.bluestretch);
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON (elements->type[wvals.fractaltype]), TRUE);
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON (elements->redmode[wvals.redmode]), TRUE);
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON (elements->greenmode[wvals.greenmode]), TRUE);
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON (elements->bluemode[wvals.bluemode]), TRUE);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->redinvert),
+ wvals.redinvert);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->greeninvert),
+ wvals.greeninvert);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (elements->blueinvert),
+ wvals.blueinvert);
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON (elements->colormode[wvals.colormode]), TRUE);
+
+ ready_now = TRUE;
+}
+
+
+/**********************************************************************
+ FUNCTION: save_options
+ *********************************************************************/
+
+static void
+save_options (FILE * fp)
+{
+ gchar buf[64];
+
+ /* Save options */
+
+ fprintf (fp, "fractaltype: %i\n", wvals.fractaltype);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.xmin);
+ fprintf (fp, "xmin: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.xmax);
+ fprintf (fp, "xmax: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.ymin);
+ fprintf (fp, "ymin: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.ymax);
+ fprintf (fp, "ymax: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.iter);
+ fprintf (fp, "iter: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.cx);
+ fprintf (fp, "cx: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.cy);
+ fprintf (fp, "cy: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.redstretch * 128.0);
+ fprintf (fp, "redstretch: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.greenstretch * 128.0);
+ fprintf (fp, "greenstretch: %s\n", buf);
+
+ g_ascii_dtostr (buf, sizeof (buf), wvals.bluestretch * 128.0);
+ fprintf (fp, "bluestretch: %s\n", buf);
+
+ fprintf (fp, "redmode: %i\n", wvals.redmode);
+ fprintf (fp, "greenmode: %i\n", wvals.greenmode);
+ fprintf (fp, "bluemode: %i\n", wvals.bluemode);
+ fprintf (fp, "redinvert: %i\n", wvals.redinvert);
+ fprintf (fp, "greeninvert: %i\n", wvals.greeninvert);
+ fprintf (fp, "blueinvert: %i\n", wvals.blueinvert);
+ fprintf (fp, "colormode: %i\n", wvals.colormode);
+ fputs ("#**********************************************************************\n", fp);
+ fprintf(fp, "<EOF>\n");
+ fputs ("#**********************************************************************\n", fp);
+}
+
+static void
+save_callback (void)
+{
+ FILE *fp;
+ const gchar *savename = filename;
+
+ fp = g_fopen (savename, "wt+");
+
+ if (!fp)
+ {
+ g_message (_("Could not open '%s' for writing: %s"),
+ gimp_filename_to_utf8 (savename), g_strerror (errno));
+ return;
+ }
+
+ /* Write header out */
+ fputs (FRACTAL_HEADER, fp);
+ fputs ("#**********************************************************************\n", fp);
+ fputs ("# This is a data file for the Fractal Explorer plug-in for GIMP *\n", fp);
+ fputs ("#**********************************************************************\n", fp);
+
+ save_options (fp);
+
+ if (ferror (fp))
+ g_message (_("Could not write '%s': %s"),
+ gimp_filename_to_utf8 (savename), g_strerror (ferror (fp)));
+
+ fclose (fp);
+}
+
+static void
+save_file_chooser_response (GtkFileChooser *chooser,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ filename = gtk_file_chooser_get_filename (chooser);
+
+ save_callback ();
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (chooser));
+}
+
+static void
+file_chooser_set_default_folder (GtkFileChooser *chooser)
+{
+ GList *path_list;
+ gchar *dir;
+
+ if (! fractalexplorer_path)
+ return;
+
+ path_list = gimp_path_parse (fractalexplorer_path, 256, FALSE, NULL);
+
+ dir = gimp_path_get_user_writable_dir (path_list);
+
+ if (! dir)
+ dir = g_strdup (gimp_directory ());
+
+ gtk_file_chooser_set_current_folder (chooser, dir);
+
+ g_free (dir);
+ gimp_path_free (path_list);
+}
+
+static void
+load_file_chooser_response (GtkFileChooser *chooser,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ filename = gtk_file_chooser_get_filename (chooser);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+ {
+ explorer_load ();
+ }
+
+ gtk_widget_show (maindlg);
+ dialog_change_scale ();
+ set_cmap_preview ();
+ dialog_update_preview ();
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (chooser));
+}
+
+static void
+create_load_file_chooser (GtkWidget *widget,
+ GtkWidget *dialog)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ window =
+ gtk_file_chooser_dialog_new (_("Load Fractal Parameters"),
+ GTK_WINDOW (dialog),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ file_chooser_set_default_folder (GTK_FILE_CHOOSER (window));
+
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &window);
+ g_signal_connect (window, "response",
+ G_CALLBACK (load_file_chooser_response),
+ window);
+ }
+
+ gtk_window_present (GTK_WINDOW (window));
+}
+
+static void
+create_save_file_chooser (GtkWidget *widget,
+ GtkWidget *dialog)
+{
+ static GtkWidget *window = NULL;
+
+ if (! window)
+ {
+ window =
+ gtk_file_chooser_dialog_new (_("Save Fractal Parameters"),
+ GTK_WINDOW (dialog),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+ gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (window),
+ TRUE);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &window);
+ g_signal_connect (window, "response",
+ G_CALLBACK (save_file_chooser_response),
+ window);
+ }
+
+ if (tpath)
+ {
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (window), tpath);
+ }
+ else
+ {
+ file_chooser_set_default_folder (GTK_FILE_CHOOSER (window));
+ }
+
+ gtk_window_present (GTK_WINDOW (window));
+}
+
+gchar*
+get_line (gchar *buf,
+ gint s,
+ FILE *from,
+ gint init)
+{
+ gint slen;
+ gchar *ret;
+
+ if (init)
+ line_no = 1;
+ else
+ line_no++;
+
+ do
+ {
+ ret = fgets (buf, s, from);
+ }
+ while (!ferror (from) && buf[0] == '#');
+
+ slen = strlen (buf);
+
+ /* The last newline is a pain */
+ if (slen > 0)
+ buf[slen - 1] = '\0';
+
+ if (ferror (from))
+ {
+ g_warning ("Error reading file");
+ return NULL;
+ }
+
+ return ret;
+}
+
+gint
+load_options (fractalexplorerOBJ *xxx,
+ FILE *fp)
+{
+ gchar load_buf[MAX_LOAD_LINE];
+ gchar str_buf[MAX_LOAD_LINE];
+ gchar opt_buf[MAX_LOAD_LINE];
+
+ /* default values */
+ xxx->opts = standardvals;
+ xxx->opts.gradinvert = FALSE;
+
+ get_line (load_buf, MAX_LOAD_LINE, fp, 0);
+
+ while (!feof (fp) && strcmp (load_buf, "<EOF>"))
+ {
+ /* Get option name */
+ sscanf (load_buf, "%255s %255s", str_buf, opt_buf);
+
+ if (!strcmp (str_buf, "fractaltype:"))
+ {
+ gint sp = 0;
+
+ sp = atoi (opt_buf);
+ if (sp < 0)
+ return -1;
+ xxx->opts.fractaltype = sp;
+ }
+ else if (!strcmp (str_buf, "xmin:"))
+ {
+ xxx->opts.xmin = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp (str_buf, "xmax:"))
+ {
+ xxx->opts.xmax = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp(str_buf, "ymin:"))
+ {
+ xxx->opts.ymin = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp (str_buf, "ymax:"))
+ {
+ xxx->opts.ymax = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp(str_buf, "redstretch:"))
+ {
+ gdouble sp = g_ascii_strtod (opt_buf, NULL);
+ xxx->opts.redstretch = sp / 128.0;
+ }
+ else if (!strcmp(str_buf, "greenstretch:"))
+ {
+ gdouble sp = g_ascii_strtod (opt_buf, NULL);
+ xxx->opts.greenstretch = sp / 128.0;
+ }
+ else if (!strcmp (str_buf, "bluestretch:"))
+ {
+ gdouble sp = g_ascii_strtod (opt_buf, NULL);
+ xxx->opts.bluestretch = sp / 128.0;
+ }
+ else if (!strcmp (str_buf, "iter:"))
+ {
+ xxx->opts.iter = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp(str_buf, "cx:"))
+ {
+ xxx->opts.cx = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp (str_buf, "cy:"))
+ {
+ xxx->opts.cy = g_ascii_strtod (opt_buf, NULL);
+ }
+ else if (!strcmp(str_buf, "redmode:"))
+ {
+ xxx->opts.redmode = atoi (opt_buf);
+ }
+ else if (!strcmp(str_buf, "greenmode:"))
+ {
+ xxx->opts.greenmode = atoi (opt_buf);
+ }
+ else if (!strcmp(str_buf, "bluemode:"))
+ {
+ xxx->opts.bluemode = atoi (opt_buf);
+ }
+ else if (!strcmp (str_buf, "redinvert:"))
+ {
+ xxx->opts.redinvert = atoi (opt_buf);
+ }
+ else if (!strcmp (str_buf, "greeninvert:"))
+ {
+ xxx->opts.greeninvert = atoi (opt_buf);
+ }
+ else if (!strcmp(str_buf, "blueinvert:"))
+ {
+ xxx->opts.blueinvert = atoi (opt_buf);
+ }
+ else if (!strcmp (str_buf, "colormode:"))
+ {
+ xxx->opts.colormode = atoi (opt_buf);
+ }
+
+ get_line (load_buf, MAX_LOAD_LINE, fp, 0);
+ }
+
+ return 0;
+}
+
+void
+explorer_load (void)
+{
+ FILE *fp;
+ gchar load_buf[MAX_LOAD_LINE];
+
+ g_assert (filename != NULL);
+
+ fp = g_fopen (filename, "rt");
+
+ if (!fp)
+ {
+ g_message (_("Could not open '%s' for reading: %s"),
+ gimp_filename_to_utf8 (filename), g_strerror (errno));
+ return;
+ }
+ get_line (load_buf, MAX_LOAD_LINE, fp, 1);
+
+ if (strncmp (FRACTAL_HEADER, load_buf, strlen (load_buf)))
+ {
+ g_message (_("'%s' is not a FractalExplorer file"),
+ gimp_filename_to_utf8 (filename));
+ fclose (fp);
+ return;
+ }
+ if (load_options (current_obj,fp))
+ {
+ g_message (_("'%s' is corrupt. Line %d Option section incorrect"),
+ gimp_filename_to_utf8 (filename), line_no);
+ fclose (fp);
+ return;
+ }
+
+ wvals = current_obj->opts;
+
+ fclose (fp);
+}