/********************************************************************** 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 . *********************************************************************/ #include "config.h" #include #include #include #include #include #include #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, "\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, "")) { /* 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); }