Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  fractal-explorer-dialogs.c   Sprache: C

 

/**********************************************************************
   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 GeglColor       **gradient_samples = NULL;
static GimpGradient     *gradient = NULL;
static gboolean          ready_now = FALSE;
static gchar            *tpath = 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 update_previews            (GimpProcedureConfig *config);
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,
                                        GimpProcedureConfig *config);

static void set_grad_data_cache        (GimpGradient        *in_gradient,
                                        gint                 n_colors);

/**********************************************************************
 CALLBACKS
 *********************************************************************/


/* Update both previews: image and colormap
 * Handler for notify signals, and also called directly.
 */

static void
update_previews (GimpProcedureConfig *config)
{
  set_cmap_preview (config);
  dialog_update_preview (config);
}

static void
dialog_redraw_callback (GtkWidget *widget,
                        gpointer   data)
{
  GimpProcedureConfig *config     = (GimpProcedureConfig *) data;
  gint                 alwaysprev = wvals.alwayspreview;

  wvals.alwayspreview = TRUE;
  update_previews (config);
  wvals.alwayspreview = alwaysprev;
}

static void
dialog_undo_zoom_callback (GtkWidget *widget,
                           gpointer   data)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;

  if (zoomindex > 0)
    {
      g_object_get (config,
                    "xmin", &wvals.xmin,
                    "xmax", &wvals.xmax,
                    "ymin", &wvals.ymin,
                    "ymax", &wvals.ymax,
                    NULL);

      zooms[zoomindex] = wvals;
      zoomindex--;
      wvals = zooms[zoomindex];

      g_object_set (config,
                    "xmin", wvals.xmin,
                    "xmax", wvals.xmax,
                    "ymin", wvals.ymin,
                    "ymax", wvals.ymax,
                    NULL);

      update_previews (config);
    }
}

static void
dialog_redo_zoom_callback (GtkWidget *widget,
                           gpointer   data)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;

  if (zoomindex < zoommax)
    {
      zoomindex++;
      wvals = zooms[zoomindex];
      g_object_set (config,
                    "xmin", wvals.xmin,
                    "xmax", wvals.xmax,
                    "ymin", wvals.ymin,
                    "ymax", wvals.ymax,
                    NULL);

      update_previews (config);
    }
}

static void
dialog_step_in_callback (GtkWidget *widget,
                         gpointer   data)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;
  gdouble              xdifferenz;
  gdouble              ydifferenz;
  gdouble              xmin;
  gdouble              xmax;
  gdouble              ymin;
  gdouble              ymax;

  g_object_get (config,
                "xmin", &xmin,
                "xmax", &xmax,
                "ymin", &ymin,
                "ymax", &ymax,
                NULL);

  if (zoomindex < ZOOM_UNDO_SIZE - 1)
    {
      g_object_get (config,
                    "xmin", &wvals.xmin,
                    "xmax", &wvals.xmax,
                    "ymin", &wvals.ymin,
                    "ymax", &wvals.ymax,
                    NULL);

      zooms[zoomindex] = wvals;
      zoomindex++;
    }
  zoommax = zoomindex;

  xdifferenz =  xmax - xmin;
  ydifferenz =  ymax - ymin;
  xmin += 1.0 / 6.0 * xdifferenz;
  ymin += 1.0 / 6.0 * ydifferenz;
  xmax -= 1.0 / 6.0 * xdifferenz;
  ymax -= 1.0 / 6.0 * ydifferenz;

  wvals.xmin = xmin;
  wvals.xmax = xmax;
  wvals.ymin = ymin;
  wvals.ymax = ymax;
  zooms[zoomindex] = wvals;

  g_object_set (config,
                "xmin", xmin,
                "xmax", xmax,
                "ymin", ymin,
                "ymax", ymax,
                NULL);

  update_previews (config);
}

static void
dialog_step_out_callback (GtkWidget *widget,
                          gpointer   data)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;
  gdouble              xdifferenz;
  gdouble              ydifferenz;
  gdouble              xmin;
  gdouble              xmax;
  gdouble              ymin;
  gdouble              ymax;

  g_object_get (config,
                "xmin", &xmin,
                "xmax", &xmax,
                "ymin", &ymin,
                "ymax", &ymax,
                NULL);

  if (zoomindex < ZOOM_UNDO_SIZE - 1)
    {
      g_object_get (config,
                    "xmin", &wvals.xmin,
                    "xmax", &wvals.xmax,
                    "ymin", &wvals.ymin,
                    "ymax", &wvals.ymax,
                    NULL);

      zooms[zoomindex] = wvals;
      zoomindex++;
    }
  zoommax = zoomindex;

  xdifferenz =  xmax - xmin;
  ydifferenz =  ymax - ymin;
  xmin -= 1.0 / 4.0 * xdifferenz;
  ymin -= 1.0 / 4.0 * ydifferenz;
  xmax += 1.0 / 4.0 * xdifferenz;
  ymax += 1.0 / 4.0 * ydifferenz;

  wvals.xmin = xmin;
  wvals.xmax = xmax;
  wvals.ymin = ymin;
  wvals.ymax = ymax;
  zooms[zoomindex] = wvals;

  g_object_set (config,
                "xmin", xmin,
                "xmax", xmax,
                "ymin", ymin,
                "ymax", ymax,
                NULL);

  update_previews (config);
}

static void
explorer_toggle_update (GtkWidget *widget,
                        gpointer   data)
{
  gimp_toggle_button_update (widget, data);

  update_previews (wvals.config);
}

static void
explorer_radio_update (GtkWidget *widget,
                       gpointer   data)
{
  gboolean c_sensitive;
  gint     fractal_type;

  fractal_type =
    gimp_procedure_config_get_choice_id (wvals.config, "fractal-type");

  switch (fractal_type)
    {
    case TYPE_MANDELBROT:
    case TYPE_SIERPINSKI:
      c_sensitive = FALSE;
      break;

    default:
      c_sensitive = TRUE;
      break;
    }

  gimp_procedure_dialog_set_sensitive (GIMP_PROCEDURE_DIALOG (maindlg),
                                       "cx",
                                       c_sensitive, NULL, NULL, FALSE);
  gimp_procedure_dialog_set_sensitive (GIMP_PROCEDURE_DIALOG (maindlg),
                                       "cy",
                                       c_sensitive, NULL, NULL, FALSE);

  update_previews (wvals.config);
}

static void
explorer_number_of_colors_callback (GimpProcedureConfig *config)
{
  gint n_colors;

  g_object_get (config,
                "n-colors", &n_colors,
                NULL);
  set_grad_data_cache (gradient, n_colors);

  update_previews (config);
}

/* Same signature as all GimpResourceSelectButton */
static void
explorer_gradient_select_callback (gpointer      data,  /* config */
                                   GimpGradient *gradient,
                                   gboolean      dialog_closing)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;
  gint n_colors;
  gint color_mode;

  g_object_get (config,
                "n-colors",   &n_colors,
                NULL);
  color_mode = gimp_procedure_config_get_choice_id (config, "color-mode");
  set_grad_data_cache (gradient, n_colors);

  if (color_mode == 1)
    {
      update_previews (config);
    }
}

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,
                              gpointer        data)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) data;
  gdouble l_xmin;
  gdouble l_xmax;
  gdouble l_ymin;
  gdouble l_ymax;
  gdouble xmin;
  gdouble xmax;
  gdouble ymin;
  gdouble ymax;

  g_object_get (config,
                "xmin", &xmin,
                "xmax", &xmax,
                "ymin", &ymin,
                "ymax", &ymax,
                NULL);

  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 = (xmin + (xmax -xmin) * (x_press / preview_width));
          l_xmax = (xmin + (xmax - xmin) * (x_release / preview_width));
          l_ymin = (ymin + (ymax - ymin) * (y_press / preview_height));
          l_ymax = (ymin + (ymax - ymin) * (y_release / preview_height));

          if (zoomindex < ZOOM_UNDO_SIZE - 1)
            {
              wvals.xmin = l_xmin;
              wvals.xmax = l_xmax;
              wvals.ymin = l_ymin;
              wvals.ymax = l_ymax;
              zooms[zoomindex] = wvals;
              zoomindex++;
            }
          zoommax = zoomindex;
          g_object_set (config,
                "xmin", l_xmin,
                "xmax", l_xmax,
                "ymin", l_ymin,
                "ymax", l_ymax,
                NULL);

          dialog_update_preview (config);
          oldypos = oldxpos = -1;
        }
    }

  return TRUE;
}

/**********************************************************************
 FUNCTION: explorer_dialog
 *********************************************************************/


gint
explorer_dialog (GimpProcedure       *procedure,
                 GimpProcedureConfig *config)
{
  GtkWidget *dialog;
  GtkWidget *top_hbox;
  GtkWidget *left_vbox;
  GtkWidget *vbox;
  GtkWidget *bbox;
  GtkWidget *frame;
  GtkWidget *toggle;
  GtkWidget *hbox;
  GtkWidget *button;
  GtkWidget *gradient_button;
  gchar     *path;
  gint       n_colors;

  gimp_ui_init (PLUG_IN_BINARY);

  path = gimp_gimprc_query ("fractalexplorer-path");

  if (path)
    {
      fractalexplorer_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
      g_free (path);
    }
  else
    {
      GFile *gimprc    = gimp_directory_file ("gimprc", NULL);
      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_file_get_utf8_name (gimprc));

      g_object_unref (gimprc);
      g_free (esc_path);
    }

  wint.wimage = g_new (guchar, preview_width * preview_height * 3);

  dialog = maindlg = gimp_procedure_dialog_new (procedure,
                                                GIMP_PROCEDURE_CONFIG (config),
                                                _("Fractal Explorer"));

  top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
  gtk_widget_set_vexpand (top_hbox, FALSE);
  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_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);

  frame = gtk_frame_new (NULL);
  gtk_widget_set_halign (frame, GTK_ALIGN_START);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  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),
                    config);
  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),
                    config);
  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),
                    config);

  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),
                    config);

  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),
                    config);

  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),
                    config);

  /*  Create notebook  */
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "parameter-tab", _("_Parameters"), FALSE, TRUE);
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "color-tab", _("_Colors"), FALSE, TRUE);
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "fractal-tab", _("_Fractals"), FALSE, TRUE);

  /*  "Parameters" page  */
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "xmin", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "xmax", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "ymin", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "ymax", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "iter", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "cx", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "cy", 1.0);
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "parameter-input-label", _("Fractal Parameters"),
                                   FALSE, FALSE);
  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                  "parameter-input-box",
                                  "xmin", "xmax", "ymin", "ymax",
                                  "iter", "cx", "cy",
                                  NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "parameter-input-frame",
                                    "parameter-input-label", FALSE,
                                    "parameter-input-box");

  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "parameter-type-label", _("Fractal Type"),
                                   FALSE, FALSE);
  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                  "parameter-type-box",
                                  "fractal-type",
                                  NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "parameter-type-frame",
                                    "parameter-type-label", FALSE,
                                    "parameter-type-box");

  vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "parameter-box",
                                         "parameter-input-frame",
                                         "parameter-type-frame",
                                         NULL);

  bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
  gtk_widget_set_margin_top (bbox, 12);
  gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
  gtk_box_pack_start (GTK_BOX (vbox), bbox, TRUE, TRUE, 2);
  gtk_box_reorder_child (GTK_BOX (vbox), bbox, 1);
  gtk_widget_set_visible (bbox, TRUE);

  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_set_visible (button, TRUE);
  gimp_help_set_help_data (button, _("Load a fractal from file"), 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_set_visible (button, TRUE);
  gimp_help_set_help_data (button, _("Save active fractal to file"), NULL);

  g_signal_connect (config, "notify::xmin",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::xmax",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::ymin",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::ymax",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::iter",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::cx",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::cy",
                    G_CALLBACK (update_previews),
                    config);

  g_signal_connect (config, "notify::fractal-type",
                    G_CALLBACK (explorer_radio_update),
                    config);
  explorer_radio_update (NULL, NULL);

  /* Colors Page */
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "n-colors", 1.0);
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "num-colors-label", _("Number of Colors"),
                                   FALSE, FALSE);
  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                      "num-colors-box",
                                      "n-colors",
                                      "use-loglog-smoothing",
                                      NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "num-colors-frame",
                                    "num-colors-label", FALSE,
                                    "num-colors-box");

  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "red-stretch", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "green-stretch", 1.0);
  gimp_procedure_dialog_get_spin_scale (GIMP_PROCEDURE_DIALOG (dialog),
                                        "blue-stretch", 1.0);
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "color-density-label", _("Color Density"),
                                   FALSE, FALSE);
  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                      "color-density-box",
                                      "red-stretch",
                                      "green-stretch",
                                      "blue-stretch",
                                      NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "color-density-frame",
                                    "color-density-label", FALSE,
                                    "color-density-box");

  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "color-function-label", _("Color Function"),
                                   FALSE, FALSE);

  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                      "red-function-box",
                                      "red-mode",
                                      "red-invert",
                                      NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "red-function-frame",
                                    NULL, FALSE,
                                    "red-function-box");

  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                      "green-function-box",
                                      "green-mode",
                                      "green-invert",
                                      NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "green-function-frame",
                                    NULL, FALSE,
                                    "green-function-box");

  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                      "blue-function-box",
                                      "blue-mode",
                                      "blue-invert",
                                      NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "blue-function-frame",
                                    NULL, FALSE,
                                    "blue-function-box");

  hbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "function-hbox",
                                         "red-function-frame",
                                         "green-function-frame",
                                         "blue-function-frame",
                                         NULL);
  gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
                                  GTK_ORIENTATION_HORIZONTAL);

  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "color-function-frame",
                                    "color-function-label", FALSE,
                                    "function-hbox");

  gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
                                    "color-mode", GIMP_TYPE_INT_RADIO_FRAME);

  hbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "color-mode-hbox",
                                         "color-mode",
                                         NULL);
  gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
                                  GTK_ORIENTATION_HORIZONTAL);

  g_object_get (config,
                "n-colors", &n_colors,
                NULL);
  /* Pass NULL to set local gradient data from context. */
  set_grad_data_cache (NULL, n_colors);

  gradient_button = gimp_gradient_chooser_new (_("FractalExplorer Gradient"), NULL, gradient);
  g_signal_connect_swapped (gradient_button, "resource-set",
                            G_CALLBACK (explorer_gradient_select_callback), config);
  gtk_box_pack_start (GTK_BOX (hbox), gradient_button, TRUE, TRUE, 0);
  gtk_widget_set_visible (gradient_button, TRUE);

  vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "color-box",
                                         "num-colors-frame",
                                         "color-density-frame",
                                         "color-function-frame",
                                         "color-mode-hbox",
                                         NULL);

  cmap_preview = gimp_preview_area_new ();
  gtk_widget_set_halign (cmap_preview, GTK_ALIGN_CENTER);
  gtk_widget_set_valign (cmap_preview, GTK_ALIGN_CENTER);
  gtk_widget_set_size_request (cmap_preview, 32, 32);
  gtk_box_pack_start (GTK_BOX (vbox), cmap_preview, TRUE, TRUE, 0);
  g_signal_connect (cmap_preview, "size-allocate",
                    G_CALLBACK (cmap_preview_size_allocate), config);
  gtk_widget_set_visible (cmap_preview, TRUE);

  g_signal_connect (config, "notify::n-colors",
                    G_CALLBACK (explorer_number_of_colors_callback),
                    config);
  g_signal_connect (config, "notify::use-loglog-smoothing",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::red-stretch",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::blue-stretch",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::green-stretch",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::red-mode",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::green-mode",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::blue-mode",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::red-invert",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::green-invert",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::blue-invert",
                    G_CALLBACK (update_previews),
                    config);
  g_signal_connect (config, "notify::color-mode",
                    G_CALLBACK (update_previews),
                    config);
  /* Fractal Presets */
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "preset-label", _("Presets"),
                                   FALSE, FALSE);
  vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "fractal-box",
                                         "preset-label",
                                         NULL);
  frame = add_objects_list ();
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 2);
  gtk_widget_set_visible (frame, TRUE);

  /* Creating layout */
  gimp_procedure_dialog_fill_notebook (GIMP_PROCEDURE_DIALOG (dialog),
                                       "main-notebook",
                                       "parameter-tab", "parameter-box",
                                       "color-tab", "color-box",
                                       "fractal-tab", "fractal-box",
                                       NULL);

  top_hbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                             "top-hbox",
                                             "main-notebook",
                                             NULL);
  gtk_orientable_set_orientation (GTK_ORIENTABLE (top_hbox),
                                  GTK_ORIENTATION_HORIZONTAL);
  gtk_widget_set_vexpand (top_hbox, FALSE);
  gtk_container_set_border_width (GTK_CONTAINER (top_hbox), 12);
  gtk_box_pack_start (GTK_BOX (top_hbox), left_vbox, FALSE, FALSE, 0);
  gtk_box_reorder_child (GTK_BOX (top_hbox), left_vbox, 0);

  gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), "top-hbox", NULL);

  gtk_widget_show (dialog);
  ready_now = TRUE;

  update_previews (config);

  wint.run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
  gtk_widget_destroy (dialog);

  g_free (wint.wimage);

  return wint.run;
}


/**********************************************************************
 FUNCTION: dialog_update_preview
 *********************************************************************/


void
dialog_update_preview (GimpProcedureConfig *config)
{
  gint     ycoord;
  guchar  *p_ul;

  if (NULL == wint.preview)
    return;

  if (ready_now && wvals.alwayspreview)
    {
      g_object_get (config,
                    "xmin", &xmin,
                    "xmax", &xmax,
                    "ymin", &ymin,
                    "ymax", &ymax,
                    NULL);
      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,
                               config);
          p_ul += preview_width * 3;
        }

      preview_redraw ();
    }
}

/**********************************************************************
 FUNCTION: cmap_preview_size_allocate()
 *********************************************************************/


/* Handler for size-allocate.
 * This:
 *    - transfers internal model colormap to the widget
 *    - redraws.
 */

static void
cmap_preview_size_allocate (GtkWidget           *widget,
                            GtkAllocation       *allocation,
                            GimpProcedureConfig *config)
{
  gint             i;
  gint             x;
  gint             y;
  gint             j;
  gint             n_colors;
  guchar          *b;
  GimpPreviewArea *preview = GIMP_PREVIEW_AREA (widget);

  g_object_get (config,
                "n-colors", &n_colors,
                NULL);

  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 > n_colors)
            {
              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 (GimpProcedureConfig *config)
{
  gint xsize;
  gint ysize;
  gint n_colors;

  g_object_get (config,
                "n-colors", &n_colors,
                NULL);

  if (NULL == cmap_preview)
    return;

  /* Change the internal model.  Does not write to widget's model. */
  make_color_map (config);

  for (ysize = 1; ysize * ysize * ysize < n_colors; ysize++)
    /**/;
  xsize = n_colors / ysize;
  while (xsize * ysize < n_colors)
    xsize++;

  /* Set minimum size. Initialize to 0, 0 to force a redraw. */
  gtk_widget_set_size_request (cmap_preview, 0, 0);
  gtk_widget_set_size_request (cmap_preview, xsize, ysize * 4);
}

/**********************************************************************
 FUNCTION: make_color_map()
 *********************************************************************/


void
make_color_map (GimpProcedureConfig *config)
{
  const Babl *colormap_format = babl_format ("R'G'B' u8");
  gint        i;
  gint        r;
  gint        gr;
  gint        bl;
  gdouble     redstretch;
  gdouble     greenstretch;
  gdouble     bluestretch;
  gdouble     pi = atan (1) * 4;
  gint        n_colors;
  gint        color_mode;
  gint        red_mode;
  gint        green_mode;
  gint        blue_mode;
  gboolean    red_invert;
  gboolean    green_invert;
  gboolean    blue_invert;

  g_object_get (config,
                "n-colors",      &n_colors,
                "red-stretch",   &redstretch,
                "green-stretch", &greenstretch,
                "blue-stretch",  &bluestretch,
                "red-invert",    &red_invert,
                "green-invert",  &green_invert,
                "blue-invert",   &blue_invert,
                NULL);
  red_mode    = gimp_procedure_config_get_choice_id (config, "red-mode");
  green_mode  = gimp_procedure_config_get_choice_id (config, "green-mode");
  blue_mode   = gimp_procedure_config_get_choice_id (config, "blue-mode");
  color_mode  = gimp_procedure_config_get_choice_id (config, "color-mode");

  /*  get gradient samples if they don't exist -- fixes gradient color
   *  mode for noninteractive use (bug #103470).
   */

  if (gradient_samples == NULL)
    {
      GimpGradient *gradient = gimp_context_get_gradient ();

      gradient_samples = gimp_gradient_get_uniform_samples (gradient,
                                                            n_colors, FALSE);
    }

  redstretch   *= 127.5;
  greenstretch *= 127.5;
  bluestretch  *= 127.5;

  for (i = 0; i < n_colors; i++)
    if (color_mode == 1)
      {
        gegl_color_get_pixel (gradient_samples[i], colormap_format, (void *) &(colormap[i]));
      }
    else
      {
        double x = (i*2.0) / n_colors;
        r = gr = bl = 0;

        switch (red_mode)
          {
          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 (green_mode)
          {
          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 (blue_mode)
          {
          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 (red_invert)
          r = 255 - r;

        if (green_invert)
          gr = 255 - gr;

        if (blue_invert)
          bl = 255 - bl;

        colormap[i].r = r;
        colormap[i].g = gr;
        colormap[i].b = bl;
      }
}

/**********************************************************************
 FUNCTION: save_options
 *********************************************************************/


static void
save_options (FILE * fp)
{
  gchar    buf[64];
  gint     fractal_type;
  gint     red_mode;
  gint     green_mode;
  gint     blue_mode;
  gint     xmin;
  gint     xmax;
  gint     ymin;
  gint     ymax;
  gint     iter;
  gint     cx;
  gint     cy;
  gdouble  red_stretch;
  gdouble  green_stretch;
  gdouble  blue_stretch;
  gboolean red_invert;
  gboolean green_invert;
  gboolean blue_invert;
  gint     color_mode;

  g_object_get (wvals.config,
                "xmin",          &xmin,
                "xmax",          &xmax,
                "ymin",          &ymin,
                "ymax",          &ymax,
                "iter",          &iter,
                "cx",            &cx,
                "cy",            &cy,
                "red-stretch",   &red_stretch,
                "green-stretch", &green_stretch,
                "blue-stretch",  &blue_stretch,
                "red-invert",    &red_invert,
                "green-invert",  &green_invert,
                "blue-invert",   &blue_invert,
                NULL);
  fractal_type =
    gimp_procedure_config_get_choice_id (wvals.config, "fractal-type");
  red_mode = gimp_procedure_config_get_choice_id (wvals.config, "red-mode");
  green_mode = gimp_procedure_config_get_choice_id (wvals.config, "green-mode");
  blue_mode = gimp_procedure_config_get_choice_id (wvals.config, "blue-mode");
  color_mode = gimp_procedure_config_get_choice_id (wvals.config, "color-mode");

  /* Save options */

  fprintf (fp, "fractaltype: %i\n", fractal_type);

  g_ascii_dtostr (buf, sizeof (buf), xmin);
  fprintf (fp, "xmin: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), xmax);
  fprintf (fp, "xmax: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), ymin);
  fprintf (fp, "ymin: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), ymax);
  fprintf (fp, "ymax: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), iter);
  fprintf (fp, "iter: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), cx);
  fprintf (fp, "cx: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), cy);
  fprintf (fp, "cy: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), red_stretch * 128.0);
  fprintf (fp, "redstretch: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), green_stretch * 128.0);
  fprintf (fp, "greenstretch: %s\n", buf);

  g_ascii_dtostr (buf, sizeof (buf), blue_stretch * 128.0);
  fprintf (fp, "bluestretch: %s\n", buf);

  fprintf (fp, "redmode: %i\n", red_mode);
  fprintf (fp, "greenmode: %i\n", green_mode);
  fprintf (fp, "bluemode: %i\n", blue_mode);
  fprintf (fp, "redinvert: %i\n", red_invert);
  fprintf (fp, "greeninvert: %i\n", green_invert);
  fprintf (fp, "blueinvert: %i\n", blue_invert);
  fprintf (fp, "colormode: %i\n", color_mode);
  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)
{
  GimpProcedureConfig *config = (GimpProcedureConfig *) 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);
      update_previews (config);
    }

  gtk_widget_destroy (GTK_WIDGET (chooser));
}

static void
create_load_file_chooser (GtkWidget *widget,
                          GtkWidget *dialog)
{
  static GtkWidget    *window = NULL;
  GimpProcedureConfig *config;

  g_object_get (GIMP_PROCEDURE_DIALOG (dialog),
                "config", &config,
                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);

      gimp_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),
                        config);
    }

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

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

/* Set cache of gradient and samples from it.
 *
 * The cache is in 2 global variables:
 * gradient, gradient_samples.
 * This keeps the three variables coherent.
 *
 * !!! There is one other writer of gradient_samples, see below.
 * For NON-INTERACTIVE use, global gradient can remain NULL
 * while gradient_samples is not.
 *
 * When in_gradient is NULL, uses gradient from context.
 *
 * In some cases, the gradient is a reference to a proxy
 * received from a temporary procedure callback.
 * Since we are keeping a reference, and can pass it to a gradient chooser,
 * the plugin machinery must not destroy the proxy object until this plugin exits.
 */

static void
set_grad_data_cache (GimpGradient *in_gradient,
                     gint          n_colors)
{
  /* Set the global gradient. */
  if (in_gradient == NULL)
    gradient = gimp_context_get_gradient ();
  else
    gradient = in_gradient;

  /* Refresh the global cache of samples. */
  if (gradient_samples != NULL)
    gimp_color_array_free (gradient_samples);

  gradient_samples = gimp_gradient_get_uniform_samples (gradient,
                                                        n_colors, FALSE);
}

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

  g_object_set (wvals.config,
                "xmin",          current_obj->opts.xmin,
                "xmax",          current_obj->opts.xmax,
                "ymin",          current_obj->opts.ymin,
                "ymax",          current_obj->opts.ymax,
                "iter",          current_obj->opts.iter,
                "cx",            current_obj->opts.cx,
                "cy",            current_obj->opts.cy,
                "red-stretch",   current_obj->opts.redstretch,
                "green-stretch", current_obj->opts.greenstretch,
                "blue-stretch",  current_obj->opts.bluestretch,
                "color-mode",    (current_obj->opts.colormode == 0) ?
                                 "colormap" : "gradient",
                "red-invert",    current_obj->opts.redinvert,
                "green-invert",  current_obj->opts.greeninvert,
                "blue-invert",   current_obj->opts.blueinvert,
                NULL);

  switch (current_obj->opts.fractaltype)
    {
    case 0:
      g_object_set (wvals.config, "fractal-type", "mandelbrot", NULL);
      break;

    case 1:
      g_object_set (wvals.config, "fractal-type", "julia", NULL);
      break;

    case 2:
      g_object_set (wvals.config, "fractal-type", "barnsley-1", NULL);
      break;

    case 3:
      g_object_set (wvals.config, "fractal-type", "barnsley-2", NULL);
      break;

    case 4:
      g_object_set (wvals.config, "fractal-type", "barnsley-3", NULL);
      break;

    case 5:
      g_object_set (wvals.config, "fractal-type", "spider", NULL);
      break;

    case 6:
      g_object_set (wvals.config, "fractal-type", "man-o-war", NULL);
      break;

    case 7:
      g_object_set (wvals.config, "fractal-type", "lambda", NULL);
      break;

    case 8:
      g_object_set (wvals.config, "fractal-type", "sierpinski", NULL);
      break;

    default:
      break;
    }
  switch (current_obj->opts.redmode)
    {
    case 0:
      g_object_set (wvals.config, "red-mode", "red-sin", NULL);
      break;

    case 1:
      g_object_set (wvals.config, "red-mode", "red-cos", NULL);
      break;

    case 2:
      g_object_set (wvals.config, "red-mode", "red-none", NULL);
      break;

    default:
      break;
    }
  switch (current_obj->opts.greenmode)
    {
    case 0:
      g_object_set (wvals.config, "green-mode", "green-sin", NULL);
      break;

    case 1:
      g_object_set (wvals.config, "green-mode", "green-cos", NULL);
      break;

    case 2:
      g_object_set (wvals.config, "green-mode", "green-none", NULL);
      break;

    default:
      break;
    }
  switch (current_obj->opts.bluemode)
    {
    case 0:
      g_object_set (wvals.config, "blue-mode", "blue-sin", NULL);
      break;

    case 1:
      g_object_set (wvals.config, "blue-mode", "blue-cos", NULL);
      break;

    case 2:
      g_object_set (wvals.config, "blue-mode", "blue-none", NULL);
      break;

    default:
      break;
    }

  fclose (fp);
}

Messung
CHZG
81979490

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104852
#Domains=417164