home *** CD-ROM | disk | FTP | other *** search
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * IfsCompose is a interface for creating IFS fractals by
- * direct manipulation.
- * Copyright (C) 1997 Owen Taylor
- *
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- /* TODO
- * ----
- *
- * 1. Run in non-interactive mode (need to figure out useful
- * way for a script to give the 19N paramters for an image).
- * Perhaps just support saving parameters to a file, script
- * passes file name.
- * 2. Save settings on a per-layer basis (long term, needs GIMP
- * support to do properly). Load/save from affine parameters?
- * 3. Figure out if we need multiple phases for supersampled
- * brushes.
- * 4. (minor) Make undo work correctly when focus is in entry widget.
- */
- #include "config.h"
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
-
- #include <gtk/gtk.h>
-
- #include <libgimp/gimp.h>
- #include <libgimp/gimpui.h>
-
- #include "libgimp/stdplugins-intl.h"
-
- #include "ifscompose.h"
-
- #define SCALE_WIDTH 150
- #define ENTRY_WIDTH 60
- #define DESIGN_AREA_MAX_SIZE 256
-
- #define PREVIEW_RENDER_CHUNK 10000
-
- #define UNDO_LEVELS 10
-
- #define IFSCOMPOSE_PARASITE "ifscompose-parasite"
- #define IFSCOMPOSE_DATA "plug_in_ifscompose"
-
- typedef enum
- {
- OP_TRANSLATE,
- OP_ROTATE, /* or scale */
- OP_STRETCH
- } DesignOp;
-
- typedef enum
- {
- VALUE_PAIR_INT,
- VALUE_PAIR_DOUBLE
- } ValuePairType;
-
- typedef struct
- {
- GtkObject *adjustment;
- GtkWidget *scale;
- GtkWidget *entry;
-
- ValuePairType type;
-
- union
- {
- gdouble *d;
- gint *i;
- } data;
-
- gint entry_handler_id;
- } ValuePair;
-
- typedef struct
- {
- IfsComposeVals ifsvals;
- AffElement **elements;
- gint *element_selected;
- gint current_element;
- } UndoItem;
-
- typedef struct
- {
- IfsColor *color;
- gchar *name;
- GtkWidget *hbox;
- GtkWidget *orig_preview;
- GtkWidget *button;
- gint fixed_point;
- } ColorMap;
-
- typedef struct
- {
- GtkWidget *dialog;
-
- ValuePair *iterations_pair;
- ValuePair *subdivide_pair;
- ValuePair *radius_pair;
- ValuePair *memory_pair;
- } IfsOptionsDialog;
-
- typedef struct
- {
- GtkWidget *area;
- GtkWidget *op_menu;
- GdkPixmap *pixmap;
-
- DesignOp op;
- gdouble op_x;
- gdouble op_y;
- gdouble op_xcenter;
- gdouble op_ycenter;
- gdouble op_center_x;
- gdouble op_center_y;
- guint button_state;
- gint num_selected;
-
- GdkGC *selected_gc;
- } IfsDesignArea;
-
- typedef struct
- {
- ValuePair *prob_pair;
- ValuePair *x_pair;
- ValuePair *y_pair;
- ValuePair *scale_pair;
- ValuePair *angle_pair;
- ValuePair *asym_pair;
- ValuePair *shear_pair;
- GtkWidget *flip_check_button;
-
- ColorMap *red_cmap;
- ColorMap *green_cmap;
- ColorMap *blue_cmap;
- ColorMap *black_cmap;
- ColorMap *target_cmap;
- ValuePair *hue_scale_pair;
- ValuePair *value_scale_pair;
- GtkWidget *simple_button;
- GtkWidget *full_button;
- GtkWidget *current_frame;
-
- GtkWidget *move_button;
- gint move_handler;
- GtkWidget *rotate_button;
- gint rotate_handler;
- GtkWidget *stretch_button;
- gint stretch_handler;
-
- GtkWidget *preview;
- guchar *preview_data;
- gint preview_iterations;
-
- gint drawable_width;
- gint drawable_height;
-
- AffElement *selected_orig;
- gint current_element;
- AffElementVals current_vals;
- gint auto_preview;
-
- gboolean in_update; /* true if we're currently in
- update_values() - don't do anything
- on updates */
- } IfsDialog;
-
- typedef struct
- {
- gint run;
- } IfsComposeInterface;
-
- /* Declare local functions.
- */
- static void query (void);
- static void run (gchar *name,
- gint nparams,
- GimpParam *param,
- gint *nreturn_vals,
- GimpParam **return_vals);
-
- /* user interface functions */
- static gint ifs_compose_dialog (GimpDrawable *drawable);
- static void ifs_options_dialog (void);
- static GtkWidget *ifs_compose_trans_page (void);
- static GtkWidget *ifs_compose_color_page (void);
- static void design_op_menu_popup (gint button, guint32 activate_time);
- static void design_op_menu_create (GtkWidget *window);
- static void design_area_create (GtkWidget *window, gint design_width,
- gint design_height);
-
- /* functions for drawing design window */
- static void update_values (void);
- static void set_current_element (gint index);
- static gint design_area_expose (GtkWidget *widget,
- GdkEventExpose *event);
- static gint design_area_button_press (GtkWidget *widget,
- GdkEventButton *event);
- static gint design_area_button_release (GtkWidget *widget,
- GdkEventButton *event);
- static void design_area_select_all_callback (GtkWidget *w, gpointer data);
- static gint design_area_configure (GtkWidget *widget,
- GdkEventConfigure *event);
- static gint design_area_motion (GtkWidget *widget,
- GdkEventMotion *event);
- static void design_area_redraw (void);
-
- /* Undo ring functions */
- static void undo_begin (void);
- static void undo_update (gint element);
- static void undo_exchange (gint el);
- static void undo (void);
- static void redo (void);
-
- static void recompute_center (gboolean save_undo);
- static void recompute_center_cb (GtkWidget *widget,
- gpointer data);
-
- static void ifs_compose (GimpDrawable *drawable);
-
- static void color_map_set_preview_color (GtkWidget *preview,
- IfsColor *color);
- static ColorMap *color_map_create (gchar *name,
- IfsColor *orig_color,
- IfsColor *data,
- gint fixed_point);
- static void color_map_color_changed_cb (GtkWidget *widget,
- ColorMap *color_map);
- static void color_map_update (ColorMap *color_map);
-
- /* interface functions */
- static void simple_color_toggled (GtkWidget *widget,gpointer data);
- static void simple_color_set_sensitive (void);
- static void val_changed_update (void);
- static ValuePair *value_pair_create (gpointer data,
- gdouble lower,
- gdouble upper,
- gboolean create_scale,
- ValuePairType type);
- static void value_pair_update (ValuePair *value_pair);
- static void value_pair_entry_callback (GtkWidget *w,
- ValuePair *value_pair);
- static void value_pair_destroy_callback (GtkWidget *widget,
- ValuePair *value_pair);
- static void value_pair_button_release (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data);
- static void value_pair_scale_callback (GtkAdjustment *adjustment,
- ValuePair *value_pair);
-
- static void auto_preview_callback (GtkWidget *widget, gpointer data);
- static void design_op_callback (GtkWidget *widget, gpointer data);
- static void design_op_update_callback (GtkWidget *widget, gpointer data);
- static void flip_check_button_callback (GtkWidget *widget, gpointer data);
- static gint preview_idle_render (void);
-
- static void ifs_compose_set_defaults (void);
- static void ifs_compose_defaults_callback (GtkWidget *widget,
- gpointer data);
- static void ifs_compose_new_callback (GtkWidget *widget,
- gpointer data);
- static void ifs_compose_delete_callback (GtkWidget *widget,
- gpointer data);
- static void ifs_compose_preview_callback (GtkWidget *widget,
- GtkWidget *preview);
-
- static void ifs_compose_close_callback (GtkWidget *widget,
- GtkWidget **destroyed_widget);
- static void ifs_compose_ok_callback (GtkWidget *widget,
- GtkWidget *window);
-
- /*
- * Some static variables
- */
-
- IfsDialog *ifsD = NULL;
- IfsOptionsDialog *ifsOptD = NULL;
- IfsDesignArea *ifsDesign = NULL;
-
- static AffElement **elements = NULL;
- static gint *element_selected = NULL;
- /* labels are generated by printing this int */
- static gint count_for_naming = 0;
-
- static UndoItem undo_ring[UNDO_LEVELS];
- static gint undo_cur = -1;
- static gint undo_num = 0;
- static gint undo_start = 0;
-
- /* num_elements = 0, signals not inited */
- static IfsComposeVals ifsvals =
- {
- 0, /* num_elements */
- 50000, /* iterations */
- 4096, /* max_memory */
- 4, /* subdivide */
- 0.75, /* radius */
- 1.0, /* aspect ratio */
- 0.5, /* center_x */
- 0.5, /* center_y */
- };
-
- static IfsComposeInterface ifscint =
- {
- FALSE, /* run */
- };
-
- GimpPlugInInfo PLUG_IN_INFO =
- {
- NULL, /* init_proc */
- NULL, /* quit_proc */
- query, /* query_proc */
- run, /* run_proc */
- };
-
-
- MAIN ()
-
- static void
- query (void)
- {
- static GimpParamDef args[] =
- {
- { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
- { GIMP_PDB_IMAGE, "image", "Input image" },
- { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
- };
-
- static GimpParamDef *return_vals = NULL;
-
- static int nargs = sizeof (args) / sizeof (args[0]);
- static int nreturn_vals = 0;
-
- INIT_I18N ();
-
- gimp_install_procedure ("plug_in_ifs_compose",
- "Create an Iterated Function System Fractal",
- "Interactively create an Iterated Function System fractal. "
- "Use the window on the upper left to adjust the component "
- "transformations of the fractal. The operation that is performed "
- "is selected by the buttons underneath the window, or from a "
- "menu popped up by the right mouse button. The fractal will be "
- "rendered with a transparent background if the current image has "
- "a transparent background.",
- "Owen Taylor",
- "Owen Taylor",
- "1997",
- N_("<Image>/Filters/Render/Nature/IfsCompose..."),
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- nargs, nreturn_vals,
- args, return_vals);
- }
-
- static void
- run (gchar *name,
- gint nparams,
- GimpParam *param,
- gint *nreturn_vals,
- GimpParam **return_vals)
- {
- static GimpParam values[1];
- GimpDrawable *active_drawable;
- GimpRunModeType run_mode;
- GimpPDBStatusType status = GIMP_PDB_SUCCESS;
- GimpParasite *parasite = NULL;
- gboolean found_parasite;
-
- run_mode = param[0].data.d_int32;
-
- values[0].type = GIMP_PDB_STATUS;
- values[0].data.d_status = status;
-
- *nreturn_vals = 1;
- *return_vals = values;
-
- INIT_I18N_UI();
-
- /* kill (getpid(), 19); */
-
- /* Get the active drawable */
- active_drawable = gimp_drawable_get (param[2].data.d_drawable);
-
- switch (run_mode)
- {
- case GIMP_RUN_INTERACTIVE:
- /* Possibly retrieve data; first look for a parasite -
- * if not found, fall back to global values
- */
- parasite = gimp_drawable_parasite_find (active_drawable->id,
- IFSCOMPOSE_PARASITE);
- found_parasite = FALSE;
- if (parasite)
- {
- found_parasite = ifsvals_parse_string (gimp_parasite_data (parasite),
- &ifsvals, &elements);
- gimp_parasite_free (parasite);
- }
-
- if (!found_parasite)
- {
- gint length;
- gchar *data;
-
- length = gimp_get_data_size (IFSCOMPOSE_DATA);
- if (length)
- {
- data = g_new (gchar, length);
- gimp_get_data (IFSCOMPOSE_DATA, data);
-
- ifsvals_parse_string (data, &ifsvals, &elements);
- g_free (data);
- }
- }
-
- /* after ifsvals_parse_string, need to set up naming */
- count_for_naming = ifsvals.num_elements;
- /* First acquire information with a dialog */
- if (! ifs_compose_dialog (active_drawable))
- return;
- break;
-
- case GIMP_RUN_NONINTERACTIVE:
- /* Make sure all the arguments are there! */
- status = GIMP_PDB_CALLING_ERROR;
- break;
-
- case GIMP_RUN_WITH_LAST_VALS:
- /* Possibly retrieve data */
- {
- gint length;
- gchar *data;
-
- length = gimp_get_data_size (IFSCOMPOSE_DATA);
- if (length)
- {
- data = g_new (gchar, length);
- gimp_get_data (IFSCOMPOSE_DATA, data);
-
- ifsvals_parse_string (data, &ifsvals, &elements);
- g_free (data);
- }
- else
- ifs_compose_set_defaults ();
- }
- break;
-
- default:
- break;
- }
-
- /* Render the fractal */
- if ((status == GIMP_PDB_SUCCESS) &&
- (gimp_drawable_is_rgb (active_drawable->id) ||
- gimp_drawable_is_gray (active_drawable->id)))
- {
- /* set the tile cache size so that the operation works well */
- gimp_tile_cache_ntiles (2 * (MAX (active_drawable->width, active_drawable->height) /
- gimp_tile_width () + 1));
-
- /* run the effect */
- ifs_compose (active_drawable);
-
- /* If the run mode is interactive, flush the displays */
- if (run_mode != GIMP_RUN_NONINTERACTIVE)
- gimp_displays_flush ();
-
- /* Store data for next invocation - both globally and
- * as a parasite on this layer
- */
- if (run_mode == GIMP_RUN_INTERACTIVE)
- {
- gchar *str = ifsvals_stringify (&ifsvals, elements);
- GimpParasite *parasite;
-
- gimp_set_data (IFSCOMPOSE_DATA, str, strlen(str)+1);
- parasite = gimp_parasite_new (IFSCOMPOSE_PARASITE,
- GIMP_PARASITE_PERSISTENT |
- GIMP_PARASITE_UNDOABLE,
- strlen(str)+1, str);
- gimp_drawable_parasite_attach (active_drawable->id, parasite);
- gimp_parasite_free (parasite);
-
- g_free (str);
- }
- }
- else if (status == GIMP_PDB_SUCCESS)
- {
- status = GIMP_PDB_EXECUTION_ERROR;
- }
-
- values[0].data.d_status = status;
-
- gimp_drawable_detach (active_drawable);
- }
-
- static GtkWidget *
- ifs_compose_trans_page (void)
- {
- GtkWidget *vbox;
- GtkWidget *table;
- GtkWidget *label;
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
-
- table = gtk_table_new (3, 6, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 4);
- gtk_table_set_col_spacing (GTK_TABLE (table), 1, 6);
- gtk_table_set_col_spacing (GTK_TABLE (table), 3, 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 2);
- gtk_table_set_row_spacing (GTK_TABLE (table), 1, 4);
- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
- gtk_widget_show (table);
-
- /* X */
-
- label = gtk_label_new (_("X:"));
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->x_pair = value_pair_create (&ifsD->current_vals.x, 0.0, 1.0, FALSE,
- VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE(table), ifsD->x_pair->entry, 1, 2, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->x_pair->entry);
-
- /* Y */
-
- label = gtk_label_new (_("Y:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->y_pair = value_pair_create (&ifsD->current_vals.y, 0.0, 1.0, FALSE,
- VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE(table), ifsD->y_pair->entry, 1, 2, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->y_pair->entry);
-
- /* Scale */
-
- label = gtk_label_new (_("Scale:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->scale_pair = value_pair_create (&ifsD->current_vals.scale, 0.0, 1.0,
- FALSE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->scale_pair->entry, 3, 4, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->scale_pair->entry);
-
- /* Angle */
-
- label = gtk_label_new (_("Angle:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
- gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->angle_pair = value_pair_create (&ifsD->current_vals.theta, -180, 180,
- FALSE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->angle_pair->entry, 3, 4, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->angle_pair->entry);
-
- /* Asym */
-
- label = gtk_label_new (_("Asymmetry:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 4, 5, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->asym_pair = value_pair_create (&ifsD->current_vals.asym, 0.10, 10.0,
- FALSE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->asym_pair->entry, 5, 6, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->asym_pair->entry);
-
- /* Shear */
-
- label = gtk_label_new (_("Shear:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 4, 5, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->shear_pair = value_pair_create (&ifsD->current_vals.shear, -10.0, 10.0,
- FALSE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->shear_pair->entry, 5, 6, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->shear_pair->entry);
-
- /* Flip */
-
- ifsD->flip_check_button = gtk_check_button_new_with_label (_("Flip"));
- gtk_table_attach (GTK_TABLE (table), ifsD->flip_check_button, 0, 6, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_signal_connect (GTK_OBJECT (ifsD->flip_check_button), "toggled",
- GTK_SIGNAL_FUNC (flip_check_button_callback),
- NULL);
- gtk_widget_show (ifsD->flip_check_button);
-
- return vbox;
- }
-
- static GtkWidget *
- ifs_compose_color_page (void)
- {
- GtkWidget *vbox;
- GtkWidget *table;
- GtkWidget *label;
- GSList *group = NULL;
- IfsColor color;
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
-
- table = gtk_table_new (3, 5, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 2);
- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
- gtk_widget_show (table);
-
- /* Simple color control section */
-
- ifsD->simple_button = gtk_radio_button_new_with_label (group, _("Simple"));
- gtk_table_attach (GTK_TABLE (table), ifsD->simple_button, 0, 1, 0, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- group = gtk_radio_button_group (GTK_RADIO_BUTTON (ifsD->simple_button));
- gtk_signal_connect (GTK_OBJECT (ifsD->simple_button), "toggled",
- GTK_SIGNAL_FUNC (simple_color_toggled),
- NULL);
- gtk_widget_show (ifsD->simple_button);
-
- color.vals[0] = 1.0;
- color.vals[1] = 0.0;
- color.vals[2] = 0.0;
- ifsD->target_cmap = color_map_create (_("IfsCompose: Target"), NULL,
- &ifsD->current_vals.target_color, TRUE);
- gtk_table_attach (GTK_TABLE (table), ifsD->target_cmap->hbox, 1, 2, 0, 2,
- GTK_FILL, 0, 0, 0);
- gtk_widget_show (ifsD->target_cmap->hbox);
-
- label = gtk_label_new (_("Scale Hue by:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->hue_scale_pair = value_pair_create (&ifsD->current_vals.hue_scale,
- 0.0, 1.0, TRUE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->hue_scale_pair->scale, 3, 4, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->hue_scale_pair->scale);
- gtk_table_attach (GTK_TABLE (table), ifsD->hue_scale_pair->entry, 4, 5, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->hue_scale_pair->entry);
-
- label = gtk_label_new (_("Scale Value by:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsD->value_scale_pair = value_pair_create (&ifsD->current_vals.value_scale,
- 0.0, 1.0, TRUE, VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsD->value_scale_pair->scale,
- 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->value_scale_pair->scale);
- gtk_table_attach (GTK_TABLE (table), ifsD->value_scale_pair->entry,
- 4, 5, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->value_scale_pair->entry);
-
- /* Full color control section */
-
- ifsD->full_button = gtk_radio_button_new_with_label (group, _("Full"));
- gtk_table_attach (GTK_TABLE (table), ifsD->full_button, 0, 1, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- group = gtk_radio_button_group (GTK_RADIO_BUTTON (ifsD->full_button));
- gtk_widget_show (ifsD->full_button);
-
- color.vals[0] = 1.0;
- color.vals[1] = 0.0;
- color.vals[2] = 0.0;
- ifsD->red_cmap = color_map_create (_("IfsCompose: Red"),&color,
- &ifsD->current_vals.red_color, FALSE);
- gtk_table_attach (GTK_TABLE (table), ifsD->red_cmap->hbox, 1, 2, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->red_cmap->hbox);
-
- color.vals[0] = 0.0;
- color.vals[1] = 1.0;
- color.vals[2] = 0.0;
- ifsD->green_cmap = color_map_create( _("IfsCompose: Green"),&color,
- &ifsD->current_vals.green_color, FALSE);
- gtk_table_attach (GTK_TABLE (table), ifsD->green_cmap->hbox, 2, 3, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->green_cmap->hbox);
-
- color.vals[0] = 0.0;
- color.vals[1] = 0.0;
- color.vals[2] = 2.0;
- ifsD->blue_cmap = color_map_create (_("IfsCompose: Blue"),&color,
- &ifsD->current_vals.blue_color, FALSE);
- gtk_table_attach (GTK_TABLE (table), ifsD->blue_cmap->hbox, 3, 4, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->blue_cmap->hbox);
-
- color.vals[0] = 0.0;
- color.vals[1] = 0.0;
- color.vals[2] = 0.0;
- ifsD->black_cmap = color_map_create (_("IfsCompose: Black"), &color,
- &ifsD->current_vals.black_color, FALSE);
- gtk_table_attach (GTK_TABLE (table), ifsD->black_cmap->hbox, 4, 5, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsD->black_cmap->hbox);
-
- return vbox;
- }
-
- static gint
- ifs_compose_dialog (GimpDrawable *drawable)
- {
- GtkWidget *dlg;
- GtkWidget *label;
- GtkWidget *button;
- GtkWidget *check_button;
- GtkWidget *vbox;
- GtkWidget *hbox;
- GtkWidget *util_hbox;
- GtkWidget *main_vbox;
- GtkWidget *alignment;
- GtkWidget *aspect_frame;
- GtkWidget *notebook;
- GtkWidget *page;
-
- gint design_width;
- gint design_height;
-
- design_width = drawable->width;
- design_height = drawable->height;
-
- if (design_width > design_height)
- {
- if (design_width > DESIGN_AREA_MAX_SIZE)
- {
- design_height = design_height * DESIGN_AREA_MAX_SIZE / design_width;
- design_width = DESIGN_AREA_MAX_SIZE;
- }
- }
- else
- {
- if (design_height > DESIGN_AREA_MAX_SIZE)
- {
- design_width = design_width * DESIGN_AREA_MAX_SIZE / design_height;
- design_height = DESIGN_AREA_MAX_SIZE;
- }
- }
-
- ifsD = g_new (IfsDialog, 1);
- ifsD->auto_preview = TRUE;
- ifsD->drawable_width = drawable->width;
- ifsD->drawable_height = drawable->height;
-
- ifsD->selected_orig = NULL;
-
- ifsD->preview_data = NULL;
- ifsD->preview_iterations = 0;
-
- ifsD->in_update = 0;
-
- gimp_ui_init ("ifscompose", TRUE);
-
- dlg = gimp_dialog_new (_("IfsCompose"), "ifscompose",
- gimp_standard_help_func, "filters/ifscompose.html",
- GTK_WIN_POS_MOUSE,
- FALSE, TRUE, FALSE,
-
- _("OK"), ifs_compose_ok_callback,
- NULL, NULL, NULL, TRUE, FALSE,
- _("New"), ifs_compose_new_callback,
- NULL, NULL, NULL, FALSE, FALSE,
- _("Delete"), ifs_compose_delete_callback,
- NULL, NULL, NULL, FALSE, FALSE,
- _("Reset"), ifs_compose_defaults_callback,
- NULL, NULL, NULL, FALSE, FALSE,
- _("Cancel"), gtk_widget_destroy,
- NULL, 1, NULL, FALSE, TRUE,
-
- NULL);
-
- gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
- GTK_SIGNAL_FUNC (ifs_compose_close_callback),
- &dlg);
-
- /* The main vbox */
- main_vbox = gtk_vbox_new (FALSE, 6);
- gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox,
- TRUE, TRUE, 0);
-
- /* The design area */
-
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
-
- aspect_frame = gtk_aspect_frame_new (NULL,
- 0.5, 0.5,
- (gdouble) design_width / design_height,
- 0);
- gtk_frame_set_shadow_type (GTK_FRAME (aspect_frame), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 0);
-
- design_area_create (dlg, design_width, design_height);
- gtk_container_add (GTK_CONTAINER (aspect_frame), ifsDesign->area);
-
- gtk_widget_show (ifsDesign->area);
- gtk_widget_show (aspect_frame);
-
- /* The Preview */
-
- aspect_frame = gtk_aspect_frame_new (NULL,
- 0.5, 0.5,
- (gdouble) design_width / design_height,
- 0);
- gtk_frame_set_shadow_type (GTK_FRAME (aspect_frame), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 0);
-
- ifsD->preview = gtk_preview_new (GTK_PREVIEW_COLOR);
- gtk_preview_size (GTK_PREVIEW (ifsD->preview), design_width, design_height);
- gtk_container_add (GTK_CONTAINER (aspect_frame), ifsD->preview);
- gtk_widget_show (ifsD->preview);
-
- gtk_widget_show (aspect_frame);
-
- gtk_widget_show (hbox);
-
- /* Iterations and preview options */
-
- hbox = gtk_hbox_new (FALSE, 4);
- gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
-
- alignment = gtk_alignment_new (1.0, 0.5, 0.5, 0.0);
- gtk_box_pack_start (GTK_BOX (hbox), alignment, TRUE, TRUE, 0);
-
- util_hbox = gtk_hbox_new (FALSE, 4);
- gtk_container_add (GTK_CONTAINER (alignment), util_hbox);
-
- ifsD->move_button = gtk_toggle_button_new_with_label (_("Move"));
- gtk_box_pack_start (GTK_BOX (util_hbox), ifsD->move_button,
- TRUE, TRUE, 0);
- gtk_widget_show (ifsD->move_button);
- ifsD->move_handler =
- gtk_signal_connect (GTK_OBJECT (ifsD->move_button),"toggled",
- GTK_SIGNAL_FUNC (design_op_callback),
- (gpointer) ((long) OP_TRANSLATE));
-
- ifsD->rotate_button = gtk_toggle_button_new_with_label (_("Rotate/Scale"));
- gtk_box_pack_start (GTK_BOX (util_hbox), ifsD->rotate_button,
- TRUE, TRUE, 0);
- gtk_widget_show (ifsD->rotate_button);
- ifsD->rotate_handler =
- gtk_signal_connect (GTK_OBJECT (ifsD->rotate_button), "toggled",
- GTK_SIGNAL_FUNC (design_op_callback),
- (gpointer) ((long) OP_ROTATE));
-
- ifsD->stretch_button = gtk_toggle_button_new_with_label (_("Stretch"));
- gtk_box_pack_start (GTK_BOX (util_hbox), ifsD->stretch_button,
- TRUE, TRUE, 0);
- gtk_widget_show (ifsD->stretch_button);
- ifsD->stretch_handler =
- gtk_signal_connect (GTK_OBJECT (ifsD->stretch_button), "toggled",
- GTK_SIGNAL_FUNC (design_op_callback),
- (gpointer) ((long) OP_STRETCH));
-
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ifsD->move_button), TRUE);
-
- gtk_widget_show (alignment);
- gtk_widget_show (util_hbox);
-
- alignment = gtk_alignment_new (1.0, 0.5, 0.5, 0.0);
- gtk_box_pack_start (GTK_BOX (hbox), alignment, TRUE, TRUE, 0);
-
- util_hbox = gtk_hbox_new (FALSE, 4);
- gtk_container_add (GTK_CONTAINER (alignment), util_hbox);
-
- button = gtk_button_new_with_label (_("Render Options"));
- gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
- GTK_SIGNAL_FUNC (ifs_options_dialog),
- NULL);
- gtk_box_pack_start (GTK_BOX (util_hbox), button, TRUE, TRUE, 0);
- gtk_widget_show (button);
-
- button = gtk_button_new_with_label (_("Preview"));
- gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
- GTK_SIGNAL_FUNC (ifs_compose_preview_callback),
- GTK_OBJECT (ifsD->preview));
- gtk_box_pack_start (GTK_BOX (util_hbox), button, TRUE, TRUE, 0);
- gtk_widget_show (button);
-
- check_button = gtk_check_button_new_with_label (_("Auto"));
- gtk_box_pack_start (GTK_BOX (util_hbox), check_button, TRUE, TRUE, 0);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
- ifsD->auto_preview);
- gtk_signal_connect (GTK_OBJECT (check_button), "toggled",
- GTK_SIGNAL_FUNC (auto_preview_callback),
- NULL);
- gtk_widget_show (check_button);
-
- gtk_widget_show (util_hbox);
- gtk_widget_show (alignment);
- gtk_widget_show (hbox);
-
- /* The current transformation frame */
-
- ifsD->current_frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (ifsD->current_frame),
- GTK_SHADOW_ETCHED_IN);
- gtk_box_pack_start (GTK_BOX (main_vbox), ifsD->current_frame,
- FALSE, FALSE, 0);
-
- vbox = gtk_vbox_new (FALSE, 4);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
- gtk_container_add (GTK_CONTAINER (ifsD->current_frame), vbox);
-
- /* The notebook */
-
- notebook = gtk_notebook_new ();
- gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
- gtk_box_pack_start (GTK_BOX (vbox), notebook, FALSE, FALSE, 0);
- gtk_widget_show (notebook);
-
- page = ifs_compose_trans_page ();
- label = gtk_label_new (_("Spatial Transformation"));
- gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
- gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
- gtk_widget_show (page);
-
- page = ifs_compose_color_page ();
- label = gtk_label_new (_("Color Transformation"));
- gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
- gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
- gtk_widget_show (page);
-
- /* The probability entry */
-
- hbox = gtk_hbox_new (FALSE, 4);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- label = gtk_label_new (_("Relative Probability:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- ifsD->prob_pair = value_pair_create (&ifsD->current_vals.prob, 0.0, 5.0, TRUE,
- VALUE_PAIR_DOUBLE);
- gtk_box_pack_start (GTK_BOX (hbox), ifsD->prob_pair->scale, TRUE, TRUE, 0);
- gtk_widget_show (ifsD->prob_pair->scale);
- gtk_box_pack_start (GTK_BOX (hbox), ifsD->prob_pair->entry, FALSE, TRUE, 0);
- gtk_widget_show (ifsD->prob_pair->entry);
-
- gtk_widget_show (hbox);
- gtk_widget_show (vbox);
- gtk_widget_show (ifsD->current_frame);
-
- gtk_widget_show (main_vbox);
-
- if (ifsvals.num_elements == 0)
- {
- ifs_compose_set_defaults();
- if (ifsD->auto_preview)
- ifs_compose_preview_callback (NULL, ifsD->preview);
- }
- else
- {
- gint i;
- gdouble ratio = (gdouble) ifsD->drawable_height / ifsD->drawable_width;
-
- element_selected = g_new (gint, ifsvals.num_elements);
- element_selected[0] = TRUE;
- for (i = 1; i < ifsvals.num_elements; i++)
- element_selected[i] = FALSE;
-
- if (ratio != ifsvals.aspect_ratio)
- {
- /* Adjust things so that what fit onto the old image, fits
- onto the new image */
- Aff2 t1,t2,t3;
- gdouble x_offset, y_offset;
- gdouble center_x, center_y;
- gdouble scale;
-
- if (ratio < ifsvals.aspect_ratio)
- {
- scale = ratio/ifsvals.aspect_ratio;
- x_offset = (1-scale)/2;
- y_offset = 0;
- }
- else
- {
- scale = 1;
- x_offset = 0;
- y_offset = (ratio - ifsvals.aspect_ratio)/2;
- }
- aff2_scale (&t1, scale, 0);
- aff2_translate (&t2, x_offset, y_offset);
- aff2_compose (&t3, &t2, &t1);
- aff2_invert (&t1, &t3);
-
- aff2_apply (&t3, ifsvals.center_x, ifsvals.center_y, ¢er_x,
- ¢er_y);
-
- for (i = 0; i < ifsvals.num_elements; i++)
- {
- aff_element_compute_trans (elements[i],1,ifsvals.aspect_ratio,
- ifsvals.center_x, ifsvals.center_y);
- aff2_compose (&t2, &elements[i]->trans, &t1);
- aff2_compose (&elements[i]->trans, &t3, &t2);
- aff_element_decompose_trans (elements[i],&elements[i]->trans,
- 1, ifsvals.aspect_ratio,
- center_x, center_y);
- }
- ifsvals.center_x = center_x;
- ifsvals.center_y = center_y;
-
- ifsvals.aspect_ratio = ratio;
- }
-
- for (i = 0; i < ifsvals.num_elements; i++)
- aff_element_compute_color_trans (elements[i]);
- /* boundary and spatial transformations will be computed
- when the design_area gets a ConfigureNotify event */
-
- set_current_element (0);
- if (ifsD->auto_preview)
- ifs_compose_preview_callback (NULL, ifsD->preview);
-
- ifsD->selected_orig = g_new (AffElement, ifsvals.num_elements);
- }
-
- gtk_widget_show (dlg);
- gtk_main ();
-
- gtk_object_unref (GTK_OBJECT (ifsDesign->op_menu));
-
- if (dlg)
- gtk_widget_destroy (dlg);
-
- if (ifsOptD)
- gtk_widget_destroy (ifsOptD->dialog);
-
- gdk_flush ();
-
- gdk_gc_destroy (ifsDesign->selected_gc);
-
- g_free(ifsD);
-
- return ifscint.run;
- }
-
- static void
- design_area_create (GtkWidget *window,
- gint design_width,
- gint design_height)
- {
- ifsDesign = g_new (IfsDesignArea, 1);
-
- ifsDesign->op = OP_TRANSLATE;
- ifsDesign->button_state = 0;
- ifsDesign->pixmap = NULL;
- ifsDesign->selected_gc = NULL;
-
- ifsDesign->area = gtk_drawing_area_new ();
- gtk_drawing_area_size (GTK_DRAWING_AREA (ifsDesign->area),
- design_width, design_height);
-
- gtk_signal_connect (GTK_OBJECT (ifsDesign->area), "expose_event",
- (GtkSignalFunc)design_area_expose,
- NULL);
- gtk_signal_connect (GTK_OBJECT (ifsDesign->area), "button_press_event",
- (GtkSignalFunc)design_area_button_press,
- NULL);
- gtk_signal_connect (GTK_OBJECT (ifsDesign->area), "button_release_event",
- (GtkSignalFunc)design_area_button_release,
- NULL);
- gtk_signal_connect (GTK_OBJECT (ifsDesign->area), "motion_notify_event",
- (GtkSignalFunc)design_area_motion,
- NULL);
- gtk_signal_connect (GTK_OBJECT (ifsDesign->area), "configure_event",
- (GtkSignalFunc) design_area_configure,
- NULL);
- gtk_widget_set_events (ifsDesign->area,
- GDK_EXPOSURE_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK);
-
- design_op_menu_create (window);
- }
-
- static void
- design_op_menu_create (GtkWidget *window)
- {
- GtkWidget *menu_item;
- GtkAccelGroup *accel_group;
-
- ifsDesign->op_menu = gtk_menu_new();
- gtk_object_ref (GTK_OBJECT (ifsDesign->op_menu));
- gtk_object_sink (GTK_OBJECT (ifsDesign->op_menu));
-
- accel_group = gtk_accel_group_new();
- gtk_menu_set_accel_group(GTK_MENU(ifsDesign->op_menu), accel_group);
- gtk_window_add_accel_group(GTK_WINDOW(window),accel_group);
-
- menu_item = gtk_menu_item_new_with_label(_("Move"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)design_op_update_callback,
- (gpointer)((long)OP_TRANSLATE));
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'M', 0,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- menu_item = gtk_menu_item_new_with_label(_("Rotate/Scale"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)design_op_update_callback,
- (gpointer)((long)OP_ROTATE));
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'R', 0,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- menu_item = gtk_menu_item_new_with_label(_("Stretch"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)design_op_update_callback,
- (gpointer)((long)OP_STRETCH));
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'S', 0,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- /* A separator */
- menu_item = gtk_menu_item_new();
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
-
- menu_item = gtk_menu_item_new_with_label(_("Select All"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)design_area_select_all_callback,
- NULL);
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'A', GDK_CONTROL_MASK,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- menu_item = gtk_menu_item_new_with_label(_("Recompute Center"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)recompute_center_cb,
- NULL);
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'R', GDK_MOD1_MASK,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- menu_item = gtk_menu_item_new_with_label(_("Undo"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)undo,
- NULL);
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'Z', GDK_CONTROL_MASK,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
-
- menu_item = gtk_menu_item_new_with_label(_("Redo"));
- gtk_menu_append(GTK_MENU(ifsDesign->op_menu),menu_item);
- gtk_widget_show(menu_item);
- gtk_signal_connect(GTK_OBJECT(menu_item),"activate",
- (GtkSignalFunc)redo,
- NULL);
- gtk_widget_add_accelerator(menu_item,
- "activate",
- accel_group,
- 'R', GDK_CONTROL_MASK,
- GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
- }
-
- static void
- design_op_menu_popup (gint button,
- guint32 activate_time)
- {
- gtk_menu_popup (GTK_MENU (ifsDesign->op_menu),
- NULL, NULL, NULL, NULL,
- button, activate_time);
- }
-
- static void
- ifs_options_dialog (void)
- {
- GtkWidget *table;
- GtkWidget *label;
-
- if (!ifsOptD)
- {
- ifsOptD = g_new (IfsOptionsDialog, 1);
-
- ifsOptD->dialog =
- gimp_dialog_new (_("IfsCompose Options"), "ifscompose",
- gimp_standard_help_func, "filters/ifscompose.html",
- GTK_WIN_POS_MOUSE,
- FALSE, TRUE, FALSE,
-
- _("Close"), gtk_widget_hide,
- NULL, 1, NULL, TRUE, TRUE,
-
- NULL);
-
- /* Table of options */
-
- table = gtk_table_new (4, 3, FALSE);
- gtk_container_set_border_width (GTK_CONTAINER (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 2);
- gtk_table_set_col_spacings (GTK_TABLE (table), 4);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ifsOptD->dialog)->vbox), table,
- FALSE, FALSE, 0);
- gtk_widget_show (table);
-
- label = gtk_label_new (_("Max. Memory:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsOptD->memory_pair = value_pair_create (&ifsvals.max_memory,
- 1, 1000000, FALSE,
- VALUE_PAIR_INT);
- gtk_table_attach (GTK_TABLE (table), ifsOptD->memory_pair->entry,
- 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsOptD->memory_pair->entry);
-
- label = gtk_label_new (_("Iterations:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsOptD->iterations_pair = value_pair_create (&ifsvals.iterations,
- 1, 10000000, FALSE,
- VALUE_PAIR_INT);
- gtk_table_attach (GTK_TABLE (table), ifsOptD->iterations_pair->entry,
- 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsOptD->iterations_pair->entry);
- gtk_widget_show (label);
-
- label = gtk_label_new (_("Subdivide:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsOptD->subdivide_pair = value_pair_create (&ifsvals.subdivide,
- 1, 10, FALSE,
- VALUE_PAIR_INT);
- gtk_table_attach (GTK_TABLE (table), ifsOptD->subdivide_pair->entry,
- 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsOptD->subdivide_pair->entry);
-
- label = gtk_label_new (_("Spot Radius:"));
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
- GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (label);
-
- ifsOptD->radius_pair = value_pair_create (&ifsvals.radius,
- 0, 5, TRUE,
- VALUE_PAIR_DOUBLE);
- gtk_table_attach (GTK_TABLE (table), ifsOptD->radius_pair->scale,
- 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsOptD->radius_pair->scale);
- gtk_table_attach (GTK_TABLE (table), ifsOptD->radius_pair->entry,
- 2, 3, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (ifsOptD->radius_pair->entry);
-
- value_pair_update (ifsOptD->iterations_pair);
- value_pair_update (ifsOptD->subdivide_pair);
- value_pair_update (ifsOptD->memory_pair);
- value_pair_update (ifsOptD->radius_pair);
-
- gtk_widget_show (ifsOptD->dialog);
- }
- else
- {
- if (!GTK_WIDGET_VISIBLE (ifsOptD->dialog))
- gtk_widget_show (ifsOptD->dialog);
- }
- }
-
- static void
- ifs_compose (GimpDrawable *drawable)
- {
- gint i,j;
- GimpImageType type = gimp_drawable_type (drawable->id);
- gchar *buffer;
-
- gint width = drawable->width;
- gint height = drawable->height;
- gint num_bands,band_height,band_y,band_no;
- guchar *data;
- guchar *mask = NULL;
- guchar *nhits;
- guchar rc,gc,bc;
-
- num_bands = ceil((gdouble)(width*height*SQR(ifsvals.subdivide)*5)
- / (1024 * ifsvals.max_memory));
- band_height = (height + num_bands - 1) / num_bands;
-
- if (band_height > height)
- band_height = height;
-
- mask = g_new(guchar,width*band_height*SQR(ifsvals.subdivide));
- data = g_new(guchar,width*band_height*SQR(ifsvals.subdivide)*3);
- nhits = g_new(guchar,width*band_height*SQR(ifsvals.subdivide));
- gimp_palette_get_background ( &rc, &gc, &bc );
-
- band_y = 0;
- for (band_no = 0; band_no < num_bands; band_no++)
- {
- guchar *ptr;
- guchar *maskptr;
- guchar *dest;
- guchar *destrow;
- guchar maskval;
- GimpPixelRgn dest_rgn;
- gint progress;
- gint max_progress;
-
- gpointer pr;
-
- buffer = g_strdup_printf (_("Rendering IFS (%d/%d)..."),
- band_no+1, num_bands);
- gimp_progress_init(buffer);
- g_free (buffer);
-
- /* render the band to a buffer */
- if (band_y + band_height > height)
- band_height = height - band_y;
-
- /* we don't need to clear data since we store nhits */
- memset(mask, 0, width*band_height*SQR(ifsvals.subdivide));
- memset(nhits, 0, width*band_height*SQR(ifsvals.subdivide));
-
- ifs_render(elements, ifsvals.num_elements, width, height, ifsvals.iterations,
- &ifsvals, band_y, band_height, data, mask, nhits, FALSE);
-
- /* transfer the image to the drawable */
-
-
- buffer = g_strdup_printf (_("Copying IFS to image (%d/%d)..."),
- band_no+1,num_bands);
- gimp_progress_init(buffer);
- g_free (buffer);
-
- progress = 0;
- max_progress = band_height * width;
-
- gimp_pixel_rgn_init (&dest_rgn, drawable, 0, band_y,
- width, band_height, TRUE, TRUE);
-
- for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
- {
- destrow = dest_rgn.data;
-
- for (j = dest_rgn.y; j < (dest_rgn.y + dest_rgn.h); j++)
- {
- dest = destrow;
-
- for (i = dest_rgn.x; i < (dest_rgn.x + dest_rgn.w); i++)
- {
- /* Accumulate a reduced pixel */
-
- gint ii,jj;
- gint rtot=0;
- gint btot=0;
- gint gtot=0;
- gint mtot=0;
- for (jj=0;jj<ifsvals.subdivide;jj++)
- {
- ptr = data + 3 *
- (((j-band_y)*ifsvals.subdivide+jj)*ifsvals.subdivide*width +
- i*ifsvals.subdivide);
-
- maskptr = mask +
- ((j-band_y)*ifsvals.subdivide+jj)*ifsvals.subdivide*width +
- i*ifsvals.subdivide;
- for (ii=0;ii<ifsvals.subdivide;ii++)
- {
- maskval = *maskptr++;
- mtot += maskval;
- rtot += maskval* *ptr++;
- gtot += maskval* *ptr++;
- btot += maskval* *ptr++;
- }
- }
- if (mtot)
- {
- rtot /= mtot;
- gtot /= mtot;
- btot /= mtot;
- mtot /= SQR(ifsvals.subdivide);
- }
- /* and store it */
- switch (type)
- {
- case GIMP_GRAY_IMAGE:
- *dest++ = (mtot*(rtot+btot+gtot)+
- (255-mtot)*(rc+gc+bc))/(3*255);
- break;
- case GIMP_GRAYA_IMAGE:
- *dest++ = (rtot+btot+gtot)/3;
- *dest++ = mtot;
- break;
- case GIMP_RGB_IMAGE:
- *dest++ = (mtot*rtot + (255-mtot)*rc)/255;
- *dest++ = (mtot*gtot + (255-mtot)*gc)/255;
- *dest++ = (mtot*btot + (255-mtot)*bc)/255;
- break;
- case GIMP_RGBA_IMAGE:
- *dest++ = rtot;
- *dest++ = gtot;
- *dest++ = btot;
- *dest++ = mtot;
- break;
- case GIMP_INDEXED_IMAGE:
- case GIMP_INDEXEDA_IMAGE:
- g_error("Indexed images not supported by IfsCompose");
- break;
- }
- }
- destrow += dest_rgn.rowstride;;
- }
- progress += dest_rgn.w * dest_rgn.h;
- gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
- }
- band_y += band_height;
- }
-
- g_free(mask);
- g_free(data);
- g_free(nhits);
-
- gimp_drawable_flush (drawable);
- gimp_drawable_merge_shadow (drawable->id, TRUE);
- gimp_drawable_update (drawable->id,0,0,width,height);
- }
-
- static void
- update_values (void)
- {
- ifsD->in_update = TRUE;
-
- ifsD->current_vals = elements[ifsD->current_element]->v;
- ifsD->current_vals.theta *= 180/G_PI;
-
- value_pair_update(ifsD->prob_pair);
- value_pair_update(ifsD->x_pair);
- value_pair_update(ifsD->y_pair);
- value_pair_update(ifsD->scale_pair);
- value_pair_update(ifsD->angle_pair);
- value_pair_update(ifsD->asym_pair);
- value_pair_update(ifsD->shear_pair);
- color_map_update(ifsD->red_cmap);
- color_map_update(ifsD->green_cmap);
- color_map_update(ifsD->blue_cmap);
- color_map_update(ifsD->black_cmap);
- color_map_update(ifsD->target_cmap);
- value_pair_update(ifsD->hue_scale_pair);
- value_pair_update(ifsD->value_scale_pair);
- if (elements[ifsD->current_element]->v.simple_color)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ifsD->simple_button),
- TRUE);
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ifsD->full_button),
- TRUE);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ifsD->flip_check_button),
- elements[ifsD->current_element]->v.flip);
-
- ifsD->in_update = FALSE;
-
- simple_color_set_sensitive();
- }
-
- static void
- set_current_element (gint index)
- {
- ifsD->current_element = index;
-
- gtk_frame_set_label(GTK_FRAME(ifsD->current_frame),elements[index]->name);
-
- update_values();
- }
-
- static gint
- design_area_expose (GtkWidget *widget,
- GdkEventExpose *event)
- {
- gint i;
- gint cx,cy;
-
- if (!ifsDesign->selected_gc)
- {
- ifsDesign->selected_gc = gdk_gc_new(ifsDesign->area->window);
- gdk_gc_set_line_attributes(ifsDesign->selected_gc,2,
- GDK_LINE_SOLID,GDK_CAP_ROUND,
- GDK_JOIN_ROUND);
- }
-
- gdk_draw_rectangle(ifsDesign->pixmap,
- widget->style->bg_gc[widget->state],
- TRUE,
- event->area.x,
- event->area.y,
- event->area.width,event->area.height);
-
- /* draw an indicator for the center */
-
- cx = ifsvals.center_x * widget->allocation.width;
- cy = ifsvals.center_y * widget->allocation.width;
- gdk_draw_line(ifsDesign->pixmap,
- widget->style->fg_gc[widget->state],
- cx - 10, cy, cx + 10, cy);
- gdk_draw_line(ifsDesign->pixmap,
- widget->style->fg_gc[widget->state],
- cx, cy - 10, cx, cy + 10);
-
- for (i=0;i<ifsvals.num_elements;i++)
- {
- aff_element_draw(elements[i], element_selected[i],
- widget->allocation.width,
- widget->allocation.height,
- ifsDesign->pixmap,
- widget->style->fg_gc[widget->state],
- ifsDesign->selected_gc,
- ifsDesign->area->style->font);
- }
-
- gdk_draw_pixmap(widget->window,
- widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
- ifsDesign->pixmap,
- event->area.x, event->area.y,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
-
- return FALSE;
- }
-
- static gint
- design_area_configure (GtkWidget *widget,
- GdkEventConfigure *event)
- {
- gint i;
- gdouble width = widget->allocation.width;
- gdouble height = widget->allocation.height;
-
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_trans(elements[i],width,height,
- ifsvals.center_x, ifsvals.center_y);
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_boundary(elements[i],width,height,
- elements, ifsvals.num_elements);
-
- if (ifsDesign->pixmap)
- {
- gdk_pixmap_unref(ifsDesign->pixmap);
- }
- ifsDesign->pixmap = gdk_pixmap_new(widget->window,
- widget->allocation.width,
- widget->allocation.height,
- gtk_preview_get_visual()->depth);
-
- return FALSE;
- }
-
- static gint
- design_area_button_press (GtkWidget *widget,
- GdkEventButton *event)
- {
- gint i;
- gdouble width = ifsDesign->area->allocation.width;
- gint old_current;
-
- gtk_widget_grab_focus(widget);
-
- if (event->button != 1 ||
- (ifsDesign->button_state & GDK_BUTTON1_MASK))
- {
- if (event->button == 3)
- design_op_menu_popup(event->button, event->time);
- return FALSE;
- }
-
- old_current = ifsD->current_element;
- ifsD->current_element = -1;
-
- /* Find out where the button press was */
- for (i=0;i<ifsvals.num_elements;i++)
- {
- if ( ipolygon_contains(elements[i]->click_boundary,event->x,event->y) )
- {
- set_current_element(i);
- break;
- }
- }
-
- /* if the user started manipulating an object, set up a new
- position on the undo ring */
- if (ifsD->current_element >= 0)
- undo_begin();
-
- if (!(event->state & GDK_SHIFT_MASK)
- && ( (ifsD->current_element<0)
- || !element_selected[ifsD->current_element] ))
- {
- for (i=0;i<ifsvals.num_elements;i++)
- element_selected[i] = 0;
- }
-
- if (ifsD->current_element >= 0)
- {
- ifsDesign->button_state |= GDK_BUTTON1_MASK;
-
- element_selected[ifsD->current_element] = TRUE;
-
- ifsDesign->num_selected = 0;
- ifsDesign->op_xcenter = 0.0;
- ifsDesign->op_ycenter = 0.0;
- for (i=0;i<ifsvals.num_elements;i++)
- {
- if (element_selected[i])
- {
- ifsD->selected_orig[i] = *elements[i];
- ifsDesign->op_xcenter += elements[i]->v.x;
- ifsDesign->op_ycenter += elements[i]->v.y;
- ifsDesign->num_selected++;
- undo_update(i);
- }
- }
- ifsDesign->op_xcenter /= ifsDesign->num_selected;
- ifsDesign->op_ycenter /= ifsDesign->num_selected;
- ifsDesign->op_x = (gdouble)event->x/width;
- ifsDesign->op_y = (gdouble)event->y/width;
- ifsDesign->op_center_x = ifsvals.center_x;
- ifsDesign->op_center_y = ifsvals.center_y;
- }
- else
- {
- ifsD->current_element = old_current;
- element_selected[old_current] = TRUE;
- }
-
- design_area_redraw();
-
- return FALSE;
- }
-
- static gint
- design_area_button_release (GtkWidget *widget,
- GdkEventButton *event)
- {
- if (event->button == 1 &&
- (ifsDesign->button_state & GDK_BUTTON1_MASK))
- {
- ifsDesign->button_state &= ~GDK_BUTTON1_MASK;
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
- return FALSE;
- }
-
- static gint
- design_area_motion (GtkWidget *widget,
- GdkEventMotion *event)
- {
- gint i;
- gdouble xo;
- gdouble yo;
- gdouble xn;
- gdouble yn;
- gint px,py;
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
-
- Aff2 trans,t1,t2,t3;
-
- if (!(ifsDesign->button_state & GDK_BUTTON1_MASK)) return FALSE;
-
- if (event->is_hint)
- {
- gtk_widget_get_pointer(ifsDesign->area, &px, &py);
- event->x = px;
- event->y = py;
- }
-
- xo = (ifsDesign->op_x - ifsDesign->op_xcenter);
- yo = (ifsDesign->op_y - ifsDesign->op_ycenter);
- xn = (gdouble)event->x/width - ifsDesign->op_xcenter;
- yn = (gdouble)event->y/width - ifsDesign->op_ycenter;
-
- /* for (i=0;i<num_elements;i++)
- {
- gtk_widget_draw(widget,&elements[i]->bounding_box);
- } */
-
- switch (ifsDesign->op)
- {
- case OP_ROTATE:
- {
- aff2_translate(&t1,-ifsDesign->op_xcenter*width,
- -ifsDesign->op_ycenter*width);
- aff2_scale(&t2,
- sqrt((SQR(xn)+SQR(yn))/(SQR(xo)+SQR(yo))),
- 0);
- aff2_compose(&t3, &t2, &t1);
- aff2_rotate(&t1, - atan2(yn,xn) + atan2(yo,xo));
- aff2_compose(&t2, &t1, &t3);
- aff2_translate(&t3,ifsDesign->op_xcenter*width,
- ifsDesign->op_ycenter*width);
- aff2_compose(&trans, &t3, &t2);
- break;
- }
- case OP_STRETCH:
- {
- aff2_translate(&t1,-ifsDesign->op_xcenter*width,
- -ifsDesign->op_ycenter*width);
- aff2_compute_stretch(&t2, xo, yo, xn, yn);
- aff2_compose(&t3, &t2, &t1);
- aff2_translate(&t1,ifsDesign->op_xcenter*width,
- ifsDesign->op_ycenter*width);
- aff2_compose(&trans, &t1, &t3);
- break;
- }
- case OP_TRANSLATE:
- {
- aff2_translate(&trans,(xn-xo)*width,(yn-yo)*width);
- break;
- }
- }
-
- for (i=0;i<ifsvals.num_elements;i++)
- if (element_selected[i])
- {
- if (ifsDesign->num_selected == ifsvals.num_elements)
- {
- gdouble cx,cy;
- aff2_invert(&t1, &trans);
- aff2_compose(&t2, &trans, &ifsD->selected_orig[i].trans);
- aff2_compose(&elements[i]->trans, &t2, &t1);
-
- cx = ifsDesign->op_center_x * width;
- cy = ifsDesign->op_center_y * width;
- aff2_apply(&trans,cx,cy,&cx,&cy);
- ifsvals.center_x = cx / width;
- ifsvals.center_y = cy / width;
- }
- else
- {
- aff2_compose(&elements[i]->trans, &trans,
- &ifsD->selected_orig[i].trans);
- }
- aff_element_decompose_trans(elements[i],&elements[i]->trans,
- width,height, ifsvals.center_x,
- ifsvals.center_y);
- aff_element_compute_trans(elements[i],width,height,
- ifsvals.center_x, ifsvals.center_y);
- }
-
- update_values();
- design_area_redraw();
-
- return FALSE;
- }
-
- static void
- design_area_redraw (void)
- {
- gint i;
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
-
- for (i=0;i<ifsvals.num_elements;i++)
- {
- aff_element_compute_boundary(elements[i],width,height,
- elements,ifsvals.num_elements);
- }
- gtk_widget_draw(ifsDesign->area,NULL);
- }
-
- /* Undo ring functions */
- static void
- undo_begin (void)
- {
- gint i,j;
- gint to_delete;
- gint new_index;
-
- if (undo_cur == UNDO_LEVELS-1)
- {
- to_delete = 1;
- undo_start = (undo_start + 1)%UNDO_LEVELS;
- }
- else
- {
- undo_cur++;
- to_delete = undo_num - undo_cur;
- }
-
- undo_num = undo_num - to_delete + 1;
- new_index = (undo_start+undo_cur)%UNDO_LEVELS;
-
- /* remove any redo elements or the oldest element if necessary */
- for (j=new_index;to_delete>0;j=(j+1)%UNDO_LEVELS,to_delete--)
- {
- for (i=0;i<undo_ring[j].ifsvals.num_elements;i++)
- if (undo_ring[j].elements[i])
- aff_element_free(undo_ring[j].elements[i]);
- g_free(undo_ring[j].elements);
- g_free(undo_ring[j].element_selected);
- }
-
- undo_ring[new_index].ifsvals = ifsvals;
- undo_ring[new_index].elements = g_new(AffElement *,ifsvals.num_elements);
- undo_ring[new_index].element_selected = g_new(gint,ifsvals.num_elements);
- undo_ring[new_index].current_element = ifsD->current_element;
-
- for (i=0;i<ifsvals.num_elements;i++)
- {
- undo_ring[new_index].elements[i] = NULL;
- undo_ring[new_index].element_selected[i] = element_selected[i];
- }
- }
-
- static void
- undo_update (gint el)
- {
- AffElement *elem;
- /* initialize */
-
- elem = NULL;
-
- if (!undo_ring[(undo_start+undo_cur)%UNDO_LEVELS].elements[el])
- undo_ring[(undo_start+undo_cur)%UNDO_LEVELS].elements[el]
- = elem = g_new(AffElement,1);
-
- *elem = *elements[el];
- elem->draw_boundary = NULL;
- elem->click_boundary = NULL;
- }
-
- static void
- undo_exchange (gint el)
- {
- gint i;
- AffElement **telements;
- gint *tselected;
- IfsComposeVals tifsvals;
- gint tcurrent;
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
-
- /* swap the arrays and values*/
- telements = elements;
- elements = undo_ring[el].elements;
- undo_ring[el].elements = telements;
-
- tifsvals = ifsvals;
- ifsvals = undo_ring[el].ifsvals;
- undo_ring[el].ifsvals = tifsvals;
-
- tselected = element_selected;
- element_selected = undo_ring[el].element_selected;
- undo_ring[el].element_selected = tselected;
-
- tcurrent = ifsD->current_element;
- ifsD->current_element = undo_ring[el].current_element;
- undo_ring[el].current_element = tcurrent;
-
- /* now swap back any unchanged elements */
- for (i=0;i<ifsvals.num_elements;i++)
- if (!elements[i])
- {
- elements[i] = undo_ring[el].elements[i];
- undo_ring[el].elements[i] = 0;
- }
- else
- aff_element_compute_trans(elements[i],width,height,
- ifsvals.center_x,ifsvals.center_y);
-
- set_current_element(ifsD->current_element);
-
- design_area_redraw();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
-
- static void
- undo (void)
- {
- if (undo_cur >= 0)
- {
- undo_exchange((undo_start+undo_cur)%UNDO_LEVELS);
- undo_cur--;
- }
- }
-
- static void
- redo (void)
- {
- if (undo_cur != undo_num - 1)
- {
- undo_cur++;
- undo_exchange((undo_start+undo_cur)%UNDO_LEVELS);
- }
- }
-
- static void
- design_area_select_all_callback (GtkWidget *w,
- gpointer data)
- {
- gint i;
-
- for (i=0;i<ifsvals.num_elements;i++)
- element_selected[i] = TRUE;
-
- design_area_redraw();
- }
-
- /* Interface functions */
-
- static void
- val_changed_update (void)
- {
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
- AffElement *cur = elements[ifsD->current_element];
-
- if (ifsD->in_update)
- return;
-
- undo_begin();
- undo_update(ifsD->current_element);
-
- cur->v = ifsD->current_vals;
- cur->v.theta *= G_PI/180.0;
- aff_element_compute_trans(cur,width,height,
- ifsvals.center_x, ifsvals.center_y);
- aff_element_compute_color_trans(cur);
-
- design_area_redraw();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
-
- /* Pseudo-widget representing a color mapping */
-
- #define COLOR_SAMPLE_SIZE 30
-
- static void
- color_map_set_preview_color (GtkWidget *preview,
- IfsColor *color)
- {
- gint i;
- guchar buf[3*COLOR_SAMPLE_SIZE];
-
- for (i=0;i<COLOR_SAMPLE_SIZE;i++)
- {
- buf[3*i] = (guint)(255.999*color->vals[0]);
- buf[3*i+1] = (guint)(255.999*color->vals[1]);
- buf[3*i+2] = (guint)(255.999*color->vals[2]);
- }
- for (i=0;i<COLOR_SAMPLE_SIZE;i++)
- gtk_preview_draw_row(GTK_PREVIEW(preview),buf,0,i,COLOR_SAMPLE_SIZE);
-
- gtk_widget_draw (preview, NULL);
- }
-
- static ColorMap *
- color_map_create (gchar *name,
- IfsColor *orig_color,
- IfsColor *data,
- gint fixed_point)
- {
- GtkWidget *frame;
- GtkWidget *arrow;
-
- ColorMap *color_map = g_new (ColorMap,1);
- color_map->name = name;
- color_map->color = data;
- color_map->fixed_point = fixed_point;
-
- color_map->hbox = gtk_hbox_new (FALSE,2);
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (color_map->hbox), frame, FALSE, FALSE, 0);
- gtk_widget_show (frame);
-
- color_map->orig_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
- gtk_preview_size (GTK_PREVIEW (color_map->orig_preview),
- COLOR_SAMPLE_SIZE, COLOR_SAMPLE_SIZE);
- gtk_container_add (GTK_CONTAINER(frame), color_map->orig_preview);
- gtk_widget_show (color_map->orig_preview);
-
- if (fixed_point)
- color_map_set_preview_color(color_map->orig_preview,data);
- else
- color_map_set_preview_color(color_map->orig_preview,orig_color);
-
- arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (color_map->hbox), arrow, FALSE, FALSE, 0);
- gtk_widget_show (arrow);
-
- color_map->button = gimp_color_button_double_new (color_map->name,
- COLOR_SAMPLE_SIZE, COLOR_SAMPLE_SIZE,
- color_map->color->vals, 3);
-
- gtk_box_pack_start (GTK_BOX (color_map->hbox), color_map->button,
- FALSE, FALSE, 0);
- gtk_widget_show (color_map->button);
-
- gtk_signal_connect (GTK_OBJECT (color_map->button), "color_changed",
- GTK_SIGNAL_FUNC (color_map_color_changed_cb),
- color_map);
-
- return color_map;
- }
-
- static void
- color_map_color_changed_cb (GtkWidget *widget,
- ColorMap *color_map)
- {
- undo_begin ();
- undo_update (ifsD->current_element);
-
- elements[ifsD->current_element]->v = ifsD->current_vals;
- elements[ifsD->current_element]->v.theta *= G_PI/180.0;
- aff_element_compute_color_trans(elements[ifsD->current_element]);
-
- update_values();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL,ifsD->preview);
- }
-
- static void
- color_map_update (ColorMap *color_map)
- {
- gimp_color_button_update (GIMP_COLOR_BUTTON (color_map->button));
-
- if (color_map->fixed_point)
- color_map_set_preview_color(color_map->orig_preview, color_map->color);
- }
-
- static void
- simple_color_set_sensitive (void)
- {
- gint sc = elements[ifsD->current_element]->v.simple_color;
-
- gtk_widget_set_sensitive(ifsD->target_cmap->hbox,sc);
- gtk_widget_set_sensitive(ifsD->hue_scale_pair->scale,sc);
- gtk_widget_set_sensitive(ifsD->hue_scale_pair->entry,sc);
- gtk_widget_set_sensitive(ifsD->value_scale_pair->scale,sc);
- gtk_widget_set_sensitive(ifsD->value_scale_pair->entry,sc);
-
- gtk_widget_set_sensitive(ifsD->red_cmap->hbox,!sc);
- gtk_widget_set_sensitive(ifsD->green_cmap->hbox,!sc);
- gtk_widget_set_sensitive(ifsD->blue_cmap->hbox,!sc);
- gtk_widget_set_sensitive(ifsD->black_cmap->hbox,!sc);
- }
-
- static void
- simple_color_toggled (GtkWidget *widget,
- gpointer data)
- {
- AffElement *cur = elements[ifsD->current_element];
- cur->v.simple_color = GTK_TOGGLE_BUTTON(widget)->active;
- ifsD->current_vals.simple_color = cur->v.simple_color;
- if (cur->v.simple_color)
- {
- aff_element_compute_color_trans(cur);
- val_changed_update();
- }
- simple_color_set_sensitive();
- }
-
- /* Generic mechanism for scale/entry combination (possibly without
- scale) */
-
- static ValuePair *
- value_pair_create (gpointer data,
- gdouble lower,
- gdouble upper,
- gboolean create_scale,
- ValuePairType type)
- {
-
- ValuePair *value_pair = g_new(ValuePair,1);
- value_pair->data.d = data;
- value_pair->type = type;
-
- value_pair->adjustment =
- gtk_adjustment_new (1.0, lower, upper,
- (upper-lower) / 100, (upper-lower) / 10,
- 0.0);
- /* We need to sink the adjustment, since we may not create a scale for
- * it, so nobody will assume the initial refcount
- */
- gtk_object_ref (value_pair->adjustment);
- gtk_object_sink (value_pair->adjustment);
- gtk_signal_connect (GTK_OBJECT (value_pair->adjustment), "value_changed",
- GTK_SIGNAL_FUNC (value_pair_scale_callback),
- value_pair);
-
- if (create_scale)
- {
- value_pair->scale = gtk_hscale_new(GTK_ADJUSTMENT (value_pair->adjustment));
- gtk_widget_ref (value_pair->scale);
-
- if (type == VALUE_PAIR_INT)
- gtk_scale_set_digits (GTK_SCALE (value_pair->scale), 0);
- else
- gtk_scale_set_digits (GTK_SCALE (value_pair->scale), 2);
-
- gtk_scale_set_draw_value (GTK_SCALE (value_pair->scale), FALSE);
- gtk_signal_connect (GTK_OBJECT (value_pair->scale),
- "button_release_event",
- (GtkSignalFunc) value_pair_button_release,
- NULL);
- }
- else
- value_pair->scale = NULL;
-
- /* We destroy the value pair when the entry is destroyed, so
- * we don't need to hold a refcount on the entry
- */
-
- value_pair->entry = gtk_entry_new ();
- gtk_widget_set_usize (value_pair->entry, ENTRY_WIDTH, 0);
- value_pair->entry_handler_id =
- gtk_signal_connect (GTK_OBJECT (value_pair->entry), "changed",
- GTK_SIGNAL_FUNC (value_pair_entry_callback),
- value_pair);
- gtk_signal_connect (GTK_OBJECT (value_pair->entry), "destroy",
- GTK_SIGNAL_FUNC (value_pair_destroy_callback),
- value_pair);
-
- return value_pair;
- }
-
- static void
- value_pair_update (ValuePair *value_pair)
- {
- gchar buffer[32];
-
- if (value_pair->type == VALUE_PAIR_INT)
- {
- GTK_ADJUSTMENT(value_pair->adjustment)->value = *value_pair->data.i;
- sprintf (buffer, "%d", *value_pair->data.i);
- }
- else
- {
- GTK_ADJUSTMENT(value_pair->adjustment)->value = *value_pair->data.d;
- sprintf (buffer, "%0.2f", *value_pair->data.d);
- }
- gtk_signal_emit_by_name (value_pair->adjustment, "value_changed");
-
- gtk_signal_handler_block(GTK_OBJECT(value_pair->entry),
- value_pair->entry_handler_id);
- gtk_entry_set_text (GTK_ENTRY (value_pair->entry), buffer);
- gtk_signal_handler_unblock(GTK_OBJECT(value_pair->entry),
- value_pair->entry_handler_id);
- }
-
- static void
- value_pair_button_release (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
- {
- val_changed_update ();
- }
-
- static void
- value_pair_scale_callback (GtkAdjustment *adjustment,
- ValuePair *value_pair)
- {
- gchar buffer[32];
- gint changed = FALSE;
-
- if (value_pair->type == VALUE_PAIR_DOUBLE)
- {
- if ((gfloat)*value_pair->data.d != adjustment->value)
- {
- changed = TRUE;
- *value_pair->data.d = adjustment->value;
- sprintf (buffer, "%0.2f", adjustment->value);
- }
- }
- else
- {
- if (*value_pair->data.i != (gint)adjustment->value)
- {
- changed = TRUE;
- *value_pair->data.i = adjustment->value;
- sprintf (buffer, "%d", (gint)adjustment->value);
- }
- }
- if (changed)
- {
- gtk_signal_handler_block(GTK_OBJECT(value_pair->entry),
- value_pair->entry_handler_id);
- gtk_entry_set_text (GTK_ENTRY (value_pair->entry), buffer);
- gtk_signal_handler_unblock(GTK_OBJECT(value_pair->entry),
- value_pair->entry_handler_id);
- }
- }
-
- static void
- value_pair_entry_callback (GtkWidget *widget,
- ValuePair *value_pair)
- {
- GtkAdjustment *adjustment = GTK_ADJUSTMENT (value_pair->adjustment);
- gdouble new_value;
- gdouble old_value;
-
- if (value_pair->type == VALUE_PAIR_INT)
- {
- old_value = *value_pair->data.i;
- new_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
- }
- else
- {
- old_value = *value_pair->data.d;
- new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
- }
-
- if (floor(0.5+old_value*10000) != floor(0.5+new_value*10000))
- {
- if ((new_value >= adjustment->lower) &&
- (new_value <= adjustment->upper))
- {
- if (value_pair->type == VALUE_PAIR_INT)
- *value_pair->data.i = new_value;
- else
- *value_pair->data.d = new_value;
- adjustment->value = new_value;
- gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed");
-
- val_changed_update();
- }
- }
- }
-
- static void
- value_pair_destroy_callback (GtkWidget *widget,
- ValuePair *value_pair)
- {
- if (value_pair->scale)
- gtk_object_unref (GTK_OBJECT (value_pair->scale));
- gtk_object_unref (value_pair->adjustment);
- }
-
- static void
- design_op_callback (GtkWidget *widget,
- gpointer data)
- {
- DesignOp op = (DesignOp)data;
-
- if (op != ifsDesign->op)
- {
- switch (ifsDesign->op)
- {
- case OP_TRANSLATE:
- gtk_signal_handler_block(GTK_OBJECT(ifsD->move_button),
- ifsD->move_handler);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ifsD->move_button),
- FALSE);
- gtk_signal_handler_unblock(GTK_OBJECT(ifsD->move_button),
- ifsD->move_handler);
- break;
- case OP_ROTATE:
- gtk_signal_handler_block(GTK_OBJECT(ifsD->rotate_button),
- ifsD->rotate_handler);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ifsD->rotate_button),
- FALSE);
- gtk_signal_handler_unblock(GTK_OBJECT(ifsD->rotate_button),
- ifsD->rotate_handler);
- break;
- case OP_STRETCH:
- gtk_signal_handler_block(GTK_OBJECT(ifsD->stretch_button),
- ifsD->stretch_handler);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ifsD->stretch_button),
- FALSE);
- gtk_signal_handler_unblock(GTK_OBJECT(ifsD->stretch_button),
- ifsD->stretch_handler);
- break;
- }
- ifsDesign->op = op;
- }
- else
- {
- GTK_TOGGLE_BUTTON(widget)->active = TRUE;
- }
- }
-
- static void
- design_op_update_callback (GtkWidget *widget,
- gpointer data)
- {
- DesignOp op = (DesignOp)data;
-
- if (op != ifsDesign->op)
- {
- switch (op)
- {
- case OP_TRANSLATE:
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(ifsD->move_button),
- TRUE);
- break;
- case OP_ROTATE:
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(ifsD->rotate_button),
- TRUE);
- break;
- case OP_STRETCH:
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(ifsD->stretch_button),
- TRUE);
- break;
- }
- }
- }
-
- static void
- recompute_center_cb (GtkWidget *widget,
- gpointer data)
- {
- recompute_center (TRUE);
- }
-
- static void
- recompute_center (gboolean save_undo)
- {
- gint i;
- gdouble x,y;
- gdouble center_x = 0.0;
- gdouble center_y = 0.0;
-
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
-
- if (save_undo)
- undo_begin();
-
- for (i=0;i<ifsvals.num_elements;i++)
- {
- if (save_undo)
- undo_update(i);
- aff_element_compute_trans(elements[i],1,ifsvals.aspect_ratio,
- ifsvals.center_x, ifsvals.center_y);
- aff2_fixed_point(&elements[i]->trans,&x,&y);
- center_x += x;
- center_y += y;
- }
-
- ifsvals.center_x = center_x/ifsvals.num_elements;
- ifsvals.center_y = center_y/ifsvals.num_elements;
-
- for (i=0;i<ifsvals.num_elements;i++)
- {
- aff_element_decompose_trans(elements[i],&elements[i]->trans,
- 1,ifsvals.aspect_ratio,
- ifsvals.center_x, ifsvals.center_y);
- }
-
- if (width > 1 && height > 1)
- {
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_trans(elements[i],width,height,
- ifsvals.center_x, ifsvals.center_y);
- design_area_redraw();
- update_values();
- }
- }
-
- static void
- auto_preview_callback (GtkWidget *widget,
- gpointer data)
- {
- if (ifsD->auto_preview)
- {
- ifsD->auto_preview = 0;
- }
- else
- {
- ifsD->auto_preview = 1;
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
- }
-
- static void
- flip_check_button_callback (GtkWidget *widget,
- gpointer data)
- {
- ifsD->current_vals.flip = GTK_TOGGLE_BUTTON(widget)->active;
- val_changed_update ();
- }
-
- static void
- ifs_compose_set_defaults (void)
- {
- gint i;
- IfsColor color;
- guchar rc,bc,gc;
-
- gimp_palette_get_foreground (&rc,&gc,&bc);
-
- color.vals[0] = (gdouble)rc/255;
- color.vals[1] = (gdouble)gc/255;
- color.vals[2] = (gdouble)bc/255;
-
- ifsvals.aspect_ratio = (gdouble)ifsD->drawable_height/ifsD->drawable_width;
-
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_free(elements[i]);
- count_for_naming = 0;
-
- ifsvals.num_elements = 3;
- elements = g_realloc(elements, ifsvals.num_elements*sizeof(AffElement *));
- element_selected = g_realloc(element_selected,
- ifsvals.num_elements*sizeof(gint));
-
- elements[0] = aff_element_new(0.3,0.37*ifsvals.aspect_ratio,color,
- ++count_for_naming);
- element_selected[0] = FALSE;
- elements[1] = aff_element_new(0.7,0.37*ifsvals.aspect_ratio,color,
- ++count_for_naming);
- element_selected[1] = FALSE;
- elements[2] = aff_element_new(0.5,0.7*ifsvals.aspect_ratio,color,
- ++count_for_naming);
- element_selected[2] = FALSE;
-
- ifsvals.center_x = 0.5;
- ifsvals.center_y = 0.5*ifsvals.aspect_ratio;
- ifsvals.iterations = ifsD->drawable_height*ifsD->drawable_width;
-
- ifsvals.subdivide = 3;
- ifsvals.max_memory = 4096;
-
- if (ifsOptD)
- {
- value_pair_update(ifsOptD->iterations_pair);
- value_pair_update(ifsOptD->subdivide_pair);
- value_pair_update(ifsOptD->radius_pair);
- value_pair_update(ifsOptD->memory_pair);
- }
-
- ifsvals.radius = 0.7;
-
- set_current_element(0);
- element_selected[0] = TRUE;
- recompute_center(FALSE);
-
- if (ifsD->selected_orig)
- g_free(ifsD->selected_orig);
-
- ifsD->selected_orig = g_new(AffElement,ifsvals.num_elements);
- }
-
- static void
- ifs_compose_defaults_callback (GtkWidget *widget,
- gpointer data)
- {
- gint i;
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
-
- undo_begin();
- for (i=0;i<ifsvals.num_elements;i++)
- undo_update(i);
-
- ifs_compose_set_defaults();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
-
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_trans(elements[i],width,height,
- ifsvals.center_x, ifsvals.center_y);
-
- design_area_redraw();
- }
-
- static void
- ifs_compose_new_callback (GtkWidget *widget,
- gpointer data)
- {
- IfsColor color;
- guchar rc,bc,gc;
- gint i;
- gdouble width = ifsDesign->area->allocation.width;
- gdouble height = ifsDesign->area->allocation.height;
- AffElement *elem;
-
- undo_begin();
-
- gimp_palette_get_foreground (&rc,&gc,&bc);
-
- color.vals[0] = (gdouble)rc/255;
- color.vals[1] = (gdouble)gc/255;
- color.vals[2] = (gdouble)bc/255;
-
- elem = aff_element_new(0.5, 0.5*height/width,color,
- ++count_for_naming);
-
- ifsvals.num_elements++;
- elements = g_realloc(elements, ifsvals.num_elements*sizeof(AffElement *));
- element_selected = g_realloc(element_selected,
- ifsvals.num_elements*sizeof(gint));
-
- for (i=0;i<ifsvals.num_elements-1;i++)
- element_selected[i] = FALSE;
- element_selected[ifsvals.num_elements-1] = TRUE;
-
- elements[ifsvals.num_elements-1] = elem;
- set_current_element(ifsvals.num_elements-1);
-
- ifsD->selected_orig = g_realloc(ifsD->selected_orig,
- ifsvals.num_elements*sizeof(AffElement));
- aff_element_compute_trans(elem,width,height,
- ifsvals.center_x, ifsvals.center_y);
-
- design_area_redraw();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
-
- static void
- ifs_compose_delete_callback (GtkWidget *widget,
- gpointer data)
- {
- gint i;
- gint new_current;
- if (ifsvals.num_elements <= 2)
- return;
-
- undo_begin();
- undo_update(ifsD->current_element);
-
- aff_element_free(elements[ifsD->current_element]);
-
- if (ifsD->current_element < ifsvals.num_elements-1)
- {
- undo_update(ifsvals.num_elements-1);
- elements[ifsD->current_element] = elements[ifsvals.num_elements-1];
- new_current = ifsD->current_element;
- }
- else
- new_current = ifsvals.num_elements-2;
-
- ifsvals.num_elements--;
-
- for (i=0;i<ifsvals.num_elements;i++)
- if (element_selected[i])
- {
- new_current = i;
- break;
- }
-
- element_selected[new_current] = TRUE;
- set_current_element(new_current);
-
- design_area_redraw();
-
- if (ifsD->auto_preview)
- ifs_compose_preview_callback(NULL, ifsD->preview);
- }
-
- static void
- ifs_compose_close_callback (GtkWidget *widget,
- GtkWidget **destroyed_widget)
- {
- *destroyed_widget = NULL;
- gtk_main_quit ();
- }
-
- static gint
- preview_idle_render (void)
- {
- gint i;
- gint width = GTK_WIDGET(ifsD->preview)->requisition.width;
- gint height = GTK_WIDGET(ifsD->preview)->requisition.height;
-
- gint iterations = PREVIEW_RENDER_CHUNK;
- if (iterations > ifsD->preview_iterations)
- iterations = ifsD->preview_iterations;
-
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_trans(elements[i], width, height,
- ifsvals.center_x, ifsvals.center_y);
-
- ifs_render(elements,ifsvals.num_elements,width,height,
- iterations,&ifsvals,0,height,
- ifsD->preview_data,NULL,NULL,TRUE);
-
- for (i=0;i<ifsvals.num_elements;i++)
- aff_element_compute_trans(elements[i],
- ifsDesign->area->allocation.width,
- ifsDesign->area->allocation.height,
- ifsvals.center_x, ifsvals.center_y);
-
- ifsD->preview_iterations -= iterations;
-
- for (i = 0; i < height; i++)
- gtk_preview_draw_row (GTK_PREVIEW (ifsD->preview),
- ifsD->preview_data + i * width * 3,
- 0, i, width);
- gtk_widget_draw (ifsD->preview, NULL);
-
- return (ifsD->preview_iterations != 0);
- }
-
- static void
- ifs_compose_preview_callback (GtkWidget *widget,
- GtkWidget *preview)
- {
- /* Expansion isn't really supported for previews */
- gint i;
- gint width = GTK_WIDGET(ifsD->preview)->requisition.width;
- gint height = GTK_WIDGET(ifsD->preview)->requisition.height;
- guchar rc,gc,bc;
- guchar *ptr;
-
- if (!ifsD->preview_data)
- ifsD->preview_data = g_new(guchar,3*width*height);
-
- gimp_palette_get_background ( &rc, &gc, &bc );
-
- ptr = ifsD->preview_data;
- for (i=0;i<width*height;i++)
- {
- *ptr++ = rc;
- *ptr++ = gc;
- *ptr++ = bc;
- }
-
- if (ifsD->preview_iterations == 0)
- gtk_idle_add ((GtkFunction)preview_idle_render, NULL);
-
- ifsD->preview_iterations = ifsvals.iterations*((gdouble)width*height/
- (ifsD->drawable_width*ifsD->drawable_height));
- }
-
- static void
- ifs_compose_ok_callback (GtkWidget *widget,
- GtkWidget *window)
- {
- ifscint.run = TRUE;
-
- gtk_widget_destroy (window);
- }
-