home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / unofficial-plug-ins / mathmap / mathmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  53.0 KB  |  2,086 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * MathMap plug-in --- generate an image by means of a mathematical expression
  5.  * Copyright (C) 1997-2000 Mark Probst
  6.  * schani@unix.cslab.tuwien.ac.at
  7.  *
  8.  * Plug-In structure based on:
  9.  *   Whirl plug-in --- distort an image into a whirlpool
  10.  *   Copyright (C) 1997 Federico Mena Quintero
  11.  *   federico@nuclecu.unam.mx
  12.  *
  13.  * Version 0.11
  14.  *
  15.  * This program is free software; you can redistribute it and/or modify
  16.  * it under the terms of the GNU General Public License as published by
  17.  * the Free Software Foundation; either version 2 of the License, or
  18.  * (at your option) any later version.
  19.  *
  20.  * This program is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  * GNU General Public License for more details.
  24.  *
  25.  * You should have received a copy of the GNU General Public License
  26.  * along with this program; if not, write to the Free Software
  27.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  */
  29.  
  30. #define MATHMAP_VERSION       "0.11"
  31.  
  32. #define MATHMAP_MANUAL_URL    "http://www.complang.tuwien.ac.at/~schani/mathmap/manual.html"
  33.  
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <assert.h>
  37. #include <string.h>
  38. #include <unistd.h>
  39. #include <ctype.h>
  40.  
  41. #include <gtk/gtk.h>
  42. #include <libgimp/gimp.h>
  43.  
  44. #include "lispreader.h"
  45. #include "exprtree.h"
  46. #include "builtins.h"
  47. #include "postfix.h"
  48. #include "tags.h"
  49. #include "scanner.h"
  50. #include "vars.h"
  51. #include "userval.h"
  52. #include "internals.h"
  53. #include "macros.h"
  54. #include "jump.h"
  55. #include "mathmap.h"
  56. #include "colorwell.h"
  57. #include "noise.h"
  58. #ifdef USE_CGEN
  59. #include "cgen.h"
  60. #endif
  61.  
  62. #ifdef USE_CGEN
  63. #define EVAL_EXPR     eval_c_code
  64. #else
  65. #define EVAL_EXPR     eval_postfix
  66. #endif
  67.  
  68. /***** Macros *****/
  69.  
  70. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  71. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  72.  
  73.  
  74. /***** Magic numbers *****/
  75.  
  76. #define PREVIEW_SIZE 128
  77. #define SCALE_WIDTH  200
  78. #define ENTRY_WIDTH  60
  79.  
  80. /* Even more stuff from Quartics plugins */
  81. #define CHECK_SIZE  8
  82. #define CHECK_DARK  ((int) (1.0 / 3.0 * 255))
  83. #define CHECK_LIGHT ((int) (2.0 / 3.0 * 255))   
  84.  
  85.  
  86. #define DEFAULT_EXPRESSION      "origValXY(x+sin(y*10)*3,y+sin(x*10)*3)"
  87. #define DEFAULT_NUMBER_FRAMES   10
  88.  
  89. #define FLAG_INTERSAMPLING      1
  90. #define FLAG_OVERSAMPLING       2
  91. #define FLAG_ANIMATION          4
  92.  
  93. #define MAX_EXPRESSION_LENGTH   8192
  94.  
  95. #define NUM_GRADIENT_SAMPLES    1024
  96.  
  97. /***** Types *****/
  98.  
  99. typedef struct {
  100.     gint flags;
  101.     gint frames;
  102.     gfloat param_t;
  103.     gchar expression[MAX_EXPRESSION_LENGTH];
  104. } mathmap_vals_t;
  105.  
  106. typedef struct {
  107.     GtkWidget *preview;
  108.     guchar *wimage;
  109.     gint run;
  110. } mathmap_interface_t;
  111.  
  112. typedef struct {
  113.     GDrawable *drawable;
  114.     gint bpp;
  115.     gint row;
  116.     gint col;
  117.     GTile *tile;
  118.     guchar *fast_image_source;
  119.     int used;
  120. } input_drawable_t;
  121.  
  122. /***** Prototypes *****/
  123.  
  124. static void query(void);
  125. static void run(char    *name,
  126.         int      nparams,
  127.         GParam  *param,
  128.         int     *nreturn_vals,
  129.         GParam **return_vals);
  130.  
  131. static void init_internals (void);
  132.  
  133. static void expression_copy (gchar *dest, gchar *src);
  134.  
  135. static void mathmap (int frame_num);
  136. static gint32 mathmap_layer_copy(gint32 layerID);
  137.  
  138. extern int mmparse (void);
  139.  
  140. static void build_fast_image_source (input_drawable_t *drawable);
  141.  
  142. static void update_userval_table (void);
  143.  
  144. static void update_gradient (void);
  145. static gint mathmap_dialog (int);
  146. static void dialog_scale_update (GtkAdjustment *adjustment, gint *value);
  147. static void dialog_t_update (GtkAdjustment *adjustment, gfloat *value);
  148. static void dialog_text_changed (void);
  149. static void dialog_text_update (void);
  150. static void dialog_intersampling_update (GtkWidget *widget, gpointer data);
  151. static void dialog_oversampling_update (GtkWidget *widget, gpointer data);
  152. static void dialog_auto_preview_update (GtkWidget *widget, gpointer data);
  153. static void dialog_fast_preview_update (GtkWidget *widget, gpointer data);
  154. static void dialog_edge_behaviour_update (GtkWidget *widget, gpointer data);
  155. static void dialog_edge_color_changed (ColorWell *color_well, gpointer data);
  156. static void dialog_edge_color_set (void);
  157. static void dialog_animation_update (GtkWidget *widget, gpointer data);
  158. static void dialog_preview_callback (GtkWidget *widget, gpointer data);
  159. static void dialog_close_callback (GtkWidget *widget, gpointer data);
  160. static void dialog_ok_callback (GtkWidget *widget, gpointer data);
  161. static void dialog_cancel_callback (GtkWidget *widget, gpointer data);
  162. static void dialog_help_callback (GtkWidget *widget, gpointer data);
  163. static void dialog_about_callback (GtkWidget *widget, gpointer data);
  164. static void dialog_tree_changed (GtkTree *tree);
  165.  
  166. /***** Variables *****/
  167.  
  168. GPlugInInfo PLUG_IN_INFO = {
  169.     NULL,   /* init_proc */
  170.     NULL,   /* quit_proc */
  171.     query,  /* query_proc */
  172.     run     /* run_proc */
  173. }; /* PLUG_IN_INFO */
  174.  
  175.  
  176. static mathmap_vals_t mmvals = {
  177.     FLAG_INTERSAMPLING,      /* flags */
  178.     DEFAULT_NUMBER_FRAMES,   /* frames */
  179.     0.0,                     /* t */
  180.     DEFAULT_EXPRESSION       /* expression */
  181. }; /* mmvals */
  182.  
  183. static mathmap_interface_t wint = {
  184.     NULL,  /* preview */
  185.     NULL,  /* wimage */
  186.     FALSE  /* run */
  187. }; /* wint */
  188.  
  189. #define MAX_INPUT_DRAWABLES 64
  190.  
  191. static GRunModeType run_mode;
  192. static gint32 image_id;
  193. static gint32 layer_id;
  194. static input_drawable_t input_drawables[MAX_INPUT_DRAWABLES];
  195. static GDrawable *output_drawable;
  196.  
  197. static gint   tile_width, tile_height;
  198. gint   sel_x1, sel_y1, sel_x2, sel_y2;
  199. gint   sel_width, sel_height;
  200. gint   preview_width, preview_height;
  201.  
  202. static int imageWidth, imageHeight;
  203.  
  204. static double cen_x, cen_y;
  205. static double scale_x, scale_y;
  206. static double radius, radius2;
  207.  
  208. char error_string[1024];
  209.  
  210. GtkWidget *expression_entry = 0,
  211.     *frame_table,
  212.     *t_table,
  213.     *edge_color_well,
  214.     *uservalues_scrolled_window,
  215.     *uservalues_table;
  216. GtkColorSelectionDialog *color_selection_dialog;
  217.  
  218. exprtree *theExprtree = 0;
  219. int img_width, img_height,
  220.     originX,
  221.     originY,
  222.     outputBPP,
  223.     previewing = 0,
  224.     auto_preview = 1,
  225.     fast_preview = 1;
  226. int usesRA = 0,
  227.     expression_changed = 1;
  228. double currentX,
  229.     currentY,
  230.     currentR,
  231.     currentA,
  232.     currentT,
  233.     imageR,
  234.     imageX,
  235.     imageY,
  236.     imageW,
  237.     imageH,
  238.     middleX,
  239.     middleY;
  240. int intersamplingEnabled,
  241.     oversamplingEnabled,
  242.     animationEnabled = 1;
  243. int edge_behaviour_color = 1,
  244.     edge_behaviour_wrap = 2,
  245.     edge_behaviour_reflect = 3;
  246. int edge_behaviour_mode = 1;
  247. unsigned char edge_color[4] = { 0, 0, 0, 0 };
  248. int num_gradient_samples = NUM_GRADIENT_SAMPLES;
  249. tuple_t gradient_samples[NUM_GRADIENT_SAMPLES];
  250.  
  251. /***** Functions *****/
  252.  
  253. /*****/
  254.  
  255. static void
  256. expression_copy (gchar *dest, gchar *src)
  257. {
  258.     strncpy(dest, src, MAX_EXPRESSION_LENGTH);
  259.     dest[MAX_EXPRESSION_LENGTH - 1] = 0;
  260. }
  261.  
  262.  
  263. /*****/
  264.  
  265. MAIN()
  266.  
  267.  
  268. /*****/
  269.  
  270. static lisp_object_t*
  271. read_rc_file (void)
  272. {
  273.     static lisp_object_t *obj = 0;
  274.  
  275.     gchar *filename;
  276.     FILE *file;
  277.     lisp_stream_t stream;
  278.  
  279.     if (obj != 0)
  280.     return obj;
  281.  
  282.     filename = gimp_personal_rc_file("mathmaprc");
  283.     file = fopen(filename, "r");
  284.     g_free(filename);
  285.     if (file == 0)
  286.     {
  287.     filename = g_strconcat(gimp_data_directory(), G_DIR_SEPARATOR_S, "mathmaprc", NULL);
  288.     file = fopen(filename, "r");
  289.     g_free(filename);
  290.  
  291.     if (file == 0)
  292.         return 0;
  293.     }
  294.  
  295.     obj = lisp_read(lisp_stream_init_file(&stream, file));
  296.     fclose(file);
  297.  
  298.     return obj;
  299. }
  300.  
  301. static void
  302. register_lisp_obj (lisp_object_t *obj, char *symbol_prefix, char *menu_prefix)
  303. {
  304.     int symbol_prefix_len = strlen(symbol_prefix);
  305.     int menu_prefix_len = strlen(menu_prefix);
  306.  
  307.     for (; lisp_type(obj) != LISP_TYPE_NIL; obj = lisp_cdr(obj))
  308.     {
  309.     lisp_object_t *vars[2];
  310.     int is_group = 0;
  311.     lisp_object_t *name_obj, *data;
  312.     char *symbol, *menu;
  313.     int i;
  314.     int name_len;
  315.  
  316.     assert(lisp_type(obj) == LISP_TYPE_CONS);
  317.  
  318.     if (lisp_match_string("(group #?(string) . #?(list))", lisp_car(obj), vars))
  319.         is_group = 1;
  320.     else if (lisp_match_string("(expression #?(string) #?(string))", lisp_car(obj), vars))
  321.         is_group = 0;
  322.     else
  323.         assert(0);
  324.  
  325.     name_obj = vars[0];
  326.     data = vars[1];
  327.  
  328.     name_len = strlen(lisp_string(name_obj));
  329.  
  330.     symbol = g_malloc(symbol_prefix_len + name_len + 2);
  331.     strcpy(symbol, symbol_prefix);
  332.     strcat(symbol, "_");
  333.     strcat(symbol, lisp_string(name_obj));
  334.  
  335.     menu = g_malloc(menu_prefix_len + name_len + 2);
  336.     strcpy(menu, menu_prefix);
  337.     strcat(menu, "/");
  338.     strcat(menu, lisp_string(name_obj));
  339.  
  340.     for (i = symbol_prefix_len + 1; i < symbol_prefix_len + 1 + name_len; ++i)
  341.         if (symbol[i] == ' ')
  342.         symbol[i] = '_';
  343.         else
  344.         symbol[i] = tolower(symbol[i]);
  345.  
  346.     if (is_group)
  347.         register_lisp_obj(data, symbol, menu);
  348.     else
  349.     {
  350.         static GParamDef args[] = {
  351.         { PARAM_INT32,      "run_mode",         "Interactive, non-interactive" },
  352.         { PARAM_IMAGE,      "image",            "Input image" },
  353.         { PARAM_DRAWABLE,   "drawable",         "Input drawable" },
  354.         { PARAM_INT32,      "flags",            "1: Intersampling 2: Oversampling 4: Animate" },
  355.         { PARAM_INT32,      "frames",           "Number of frames" },
  356.         { PARAM_FLOAT,      "param_t",          "The parameter t (if not animating)" }
  357.         };
  358.         static GParamDef *return_vals  = NULL;
  359.         static int nargs = sizeof(args) / sizeof(args[0]);
  360.         static int nreturn_vals = 0;
  361.  
  362.         fprintf(stderr, "registering %s (%s)\n", symbol, menu);
  363.  
  364.         gimp_install_procedure(symbol,
  365.                    "Generate an image using a mathematical expression.",
  366.                    "Generates an image by means of a mathematical expression. The expression "
  367.                    "can also refer to the data of an original image. Thus, arbitrary "
  368.                    "distortions can be constructed. Even animations can be generated.",
  369.                    "Mark Probst",
  370.                    "Mark Probst",
  371.                    "April 2000, " MATHMAP_VERSION,
  372.                    menu,
  373.                    "RGB*, GRAY*",
  374.                    PROC_PLUG_IN,
  375.                    nargs,
  376.                    nreturn_vals,
  377.                    args,
  378.                    return_vals);
  379.     }
  380.  
  381.     g_free(menu);
  382.     g_free(symbol);
  383.     }
  384. }
  385.  
  386. static void
  387. register_examples (void)
  388. {
  389.     lisp_object_t *obj = read_rc_file();
  390.  
  391.     if (obj == 0)
  392.     return;
  393.  
  394.     register_lisp_obj(obj, "mathmap", "<Image>/Filters/Generic/MathMap");
  395.     lisp_free(obj);
  396. }
  397.  
  398. static char*
  399. expression_for_symbol (char *symbol, lisp_object_t *obj)
  400. {
  401.     for (; lisp_type(obj) != LISP_TYPE_NIL; obj = lisp_cdr(obj))
  402.     {
  403.     lisp_object_t *vars[2];
  404.     int is_group = 0;
  405.     char *name;
  406.     int i;
  407.     int name_len;
  408.  
  409.     assert(lisp_type(obj) == LISP_TYPE_CONS);
  410.  
  411.     if (lisp_match_string("(group #?(string) . #?(list))", lisp_car(obj), vars))
  412.         is_group = 1;
  413.     else if (lisp_match_string("(expression #?(string) #?(string))", lisp_car(obj), vars))
  414.         is_group = 0;
  415.     else
  416.         assert(0);
  417.  
  418.     name = lisp_string(vars[0]);
  419.     name_len = strlen(name);
  420.  
  421.     if (name_len > strlen(symbol))
  422.         continue;
  423.     if ((!is_group && name_len != strlen(symbol))
  424.         || (is_group && name_len == strlen(symbol)))
  425.         continue;
  426.     if (is_group && symbol[name_len] != '_')
  427.         continue;
  428.  
  429.     for (i = 0; i < name_len; ++i)
  430.         if ((name[i] == ' ' && symbol[i] != '_')
  431.         || (name[i] != ' ' && symbol[i] != tolower(name[i])))
  432.         break;
  433.  
  434.     if (i == name_len)
  435.     {
  436.         if (is_group)
  437.         {
  438.         char *exp = expression_for_symbol(symbol + name_len + 1, vars[1]);
  439.  
  440.         if (exp != 0)
  441.             return exp;
  442.         }
  443.         else
  444.         return lisp_string(vars[1]);
  445.     }
  446.     }
  447.  
  448.     return 0;
  449. }
  450.  
  451. static void
  452. query(void)
  453. {
  454.     static GParamDef args[] = {
  455.     { PARAM_INT32,      "run_mode",         "Interactive, non-interactive" },
  456.     { PARAM_IMAGE,      "image",            "Input image" },
  457.     { PARAM_DRAWABLE,   "drawable",         "Input drawable" },
  458.     { PARAM_INT32,      "flags",            "1: Intersampling 2: Oversampling 4: Animate" },
  459.     { PARAM_INT32,      "frames",           "Number of frames" },
  460.     { PARAM_FLOAT,      "param_t",          "The parameter t (if not animating)" },
  461.     { PARAM_STRING,     "expression",       "MathMap expression" }
  462.     };
  463.     static GParamDef *return_vals  = NULL;
  464.     static int nargs = sizeof(args) / sizeof(args[0]);
  465.     static int nreturn_vals = 0;
  466.  
  467.     gimp_install_procedure("plug_in_mathmap",
  468.                "Generate an image using a mathematical expression.",
  469.                "Generates an image by means of a mathematical expression. The expression "
  470.                "can also refer to the data of an original image. Thus, arbitrary "
  471.                "distortions can be constructed. Even animations can be generated.",
  472.                "Mark Probst",
  473.                "Mark Probst",
  474.                "April 2000, " MATHMAP_VERSION,
  475.                "<Image>/Filters/Generic/MathMap/MathMap",
  476.                "RGB*, GRAY*",
  477.                PROC_PLUG_IN,
  478.                nargs,
  479.                nreturn_vals,
  480.                args,
  481.                return_vals);
  482.  
  483.     register_examples();
  484. }
  485.  
  486. /*****/
  487.  
  488. static void
  489. run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals)
  490. {
  491.     static GParam values[1];
  492.  
  493.     GStatusType status;
  494.     double xhsiz, yhsiz;
  495.     int pwidth, pheight;
  496.  
  497.     int mutable_expression = 1;
  498.  
  499.     fprintf(stderr, "started as %s\n", name);
  500.     if (strncmp(name, "mathmap_", 8) == 0)
  501.     {
  502.     char *exp = expression_for_symbol(name + 8, read_rc_file());
  503.  
  504.     fprintf(stderr, "found %s\n", exp);
  505.  
  506.     if (exp != 0)
  507.     {
  508.         strcpy(mmvals.expression, exp);
  509.         mutable_expression = 0;
  510.     }
  511.     }
  512.  
  513.     status   = STATUS_SUCCESS;
  514.     run_mode = param[0].data.d_int32;
  515.  
  516.     image_id = param[1].data.d_int32;
  517.     layer_id = gimp_image_get_active_layer(image_id);
  518.  
  519.     values[0].type = PARAM_STATUS;
  520.     values[0].data.d_status = status;
  521.  
  522.     *nreturn_vals = 1;
  523.     *return_vals = values;
  524.  
  525.     /* Get the active drawable info */
  526.  
  527.     input_drawables[0].drawable = gimp_drawable_get(param[2].data.d_drawable);
  528.     input_drawables[0].bpp = gimp_drawable_bpp(input_drawables[0].drawable->id);
  529.     input_drawables[0].row = input_drawables[0].col = -1;
  530.     input_drawables[0].tile = 0;
  531.     input_drawables[0].fast_image_source = 0;
  532.     input_drawables[0].used = 1;
  533.  
  534.     outputBPP = input_drawables[0].bpp;
  535.  
  536.     tile_width = gimp_tile_width();
  537.     tile_height = gimp_tile_height();
  538.  
  539.     img_width = gimp_drawable_width(input_drawables[0].drawable->id);
  540.     img_height = gimp_drawable_height(input_drawables[0].drawable->id);
  541.  
  542.     gimp_drawable_mask_bounds(input_drawables[0].drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  543.  
  544.     originX = sel_x1;
  545.     originY = sel_y1;
  546.  
  547.     sel_width  = sel_x2 - sel_x1;
  548.     sel_height = sel_y2 - sel_y1;
  549.  
  550.     cen_x = (double) (sel_x2 - 1 + sel_x1) / 2.0;
  551.     cen_y = (double) (sel_y2 - 1 + sel_y1) / 2.0;
  552.  
  553.     xhsiz = (double) (sel_width - 1) / 2.0;
  554.     yhsiz = (double) (sel_height - 1) / 2.0;
  555.  
  556.     if (xhsiz < yhsiz) {
  557.     scale_x = yhsiz / xhsiz;
  558.     scale_y = 1.0;
  559.     } else if (xhsiz > yhsiz) {
  560.     scale_x = 1.0;
  561.     scale_y = xhsiz / yhsiz;
  562.     } else {
  563.     scale_x = 1.0;
  564.     scale_y = 1.0;
  565.     } /* else */
  566.  
  567.     radius  = MAX(xhsiz, yhsiz);
  568.     radius2 = radius * radius;
  569.  
  570.     /* Calculate preview size */
  571.  
  572.     if (sel_width > sel_height) {
  573.     pwidth  = MIN(sel_width, PREVIEW_SIZE);
  574.     pheight = sel_height * pwidth / sel_width;
  575.     } else {
  576.     pheight = MIN(sel_height, PREVIEW_SIZE);
  577.     pwidth  = sel_width * pheight / sel_height;
  578.     } /* else */
  579.  
  580.     preview_width  = MAX(pwidth, 2);  /* Min size is 2 */
  581.     preview_height = MAX(pheight, 2);
  582.  
  583.     init_builtins();
  584.     init_tags();
  585.     init_internals();
  586.     init_macros();
  587.     init_noise();
  588.  
  589.     /* See how we will run */
  590.  
  591.     switch (run_mode) {
  592.     case RUN_INTERACTIVE:
  593.         /* Possibly retrieve data */
  594.  
  595.         gimp_get_data(name, &mmvals);
  596.  
  597.         /* Get information from the dialog */
  598.  
  599.         update_gradient();
  600.  
  601.         if (!mathmap_dialog(mutable_expression))
  602.         return;
  603.  
  604.         break;
  605.  
  606.     case RUN_NONINTERACTIVE:
  607.         /* Make sure all the arguments are present */
  608.  
  609.         if (nparams != 5)
  610.         status = STATUS_CALLING_ERROR;
  611.  
  612.         if (status == STATUS_SUCCESS)
  613.         {
  614.         expression_copy(mmvals.expression, param[3].data.d_string);
  615.         mmvals.flags = param[4].data.d_int32;
  616.         }
  617.  
  618.         break;
  619.  
  620.     case RUN_WITH_LAST_VALS:
  621.         /* Possibly retrieve data */
  622.  
  623.         gimp_get_data(name, &mmvals);
  624.         break;
  625.  
  626.     default:
  627.         break;
  628.     } /* switch */
  629.  
  630.     /* Mathmap the image */
  631.  
  632.     if ((status == STATUS_SUCCESS)
  633.     && (gimp_drawable_color(input_drawables[0].drawable->id)
  634.         || gimp_drawable_gray(input_drawables[0].drawable->id)))
  635.     {
  636.     intersamplingEnabled = mmvals.flags & FLAG_INTERSAMPLING;
  637.     oversamplingEnabled = mmvals.flags & FLAG_OVERSAMPLING;
  638.     animationEnabled = mmvals.flags & FLAG_ANIMATION;
  639.  
  640.     update_gradient();
  641.  
  642.     /* Set the tile cache size */
  643.  
  644.     gimp_tile_cache_ntiles((input_drawables[0].drawable->width + gimp_tile_width() - 1)
  645.                    / gimp_tile_width());
  646.  
  647.     /* Run! */
  648.  
  649.     if (animationEnabled)
  650.     {
  651.         int frameNum;
  652.  
  653.         for (frameNum = 0; frameNum < mmvals.frames; ++frameNum)
  654.         {
  655.         gint32 layer;
  656.         char layerName[100];
  657.  
  658.         currentT = (double)frameNum / (double)mmvals.frames;
  659.         layer = mathmap_layer_copy(layer_id);
  660.         sprintf(layerName, "Frame %d", frameNum + 1);
  661.         gimp_layer_set_name(layer, layerName);
  662.         output_drawable = gimp_drawable_get(layer);
  663.         mathmap(frameNum);
  664.         gimp_image_add_layer(image_id, layer, 0);
  665.         }
  666.     }
  667.     else
  668.     {
  669.         currentT = mmvals.param_t;
  670.         output_drawable = input_drawables[0].drawable;
  671.         mathmap(-1);
  672.     }
  673.  
  674.     /* If run mode is interactive, flush displays */
  675.  
  676.     if (run_mode != RUN_NONINTERACTIVE)
  677.         gimp_displays_flush();
  678.  
  679.     /* Store data */
  680.  
  681.     if (run_mode == RUN_INTERACTIVE)
  682.         gimp_set_data(name, &mmvals, sizeof(mathmap_vals_t));
  683.     } else if (status == STATUS_SUCCESS)
  684.     status = STATUS_EXECUTION_ERROR;
  685.  
  686.     values[0].data.d_status = status;
  687.  
  688.     gimp_drawable_detach(input_drawables[0].drawable);
  689. } /* run */
  690.  
  691.  
  692. /*****/
  693.  
  694. static internal_t *xy_internal = 0, *ra_internal = 0;
  695.  
  696. inline void
  697. calc_ra (void)
  698. {
  699.     if (ra_internal->is_used)
  700.     {
  701.     double x = currentX,
  702.         y = currentY;
  703.  
  704.     currentR = sqrt(x * x + y * y);
  705.     if (currentR == 0.0)
  706.         currentA = 0.0;
  707.     else
  708.         currentA = acos(x / currentR) * 180 / G_PI;
  709.  
  710.     if (y < 0)
  711.         currentA = 360 - currentA;
  712.     }
  713. }
  714.  
  715. static void
  716. init_internals (void)
  717. {
  718.     xy_internal = register_internal("xy", xy_tag_number, 2);
  719.     ra_internal = register_internal("ra", ra_tag_number, 2);
  720.     register_internal("t", nil_tag_number, 1);
  721.     register_internal("XY", xy_tag_number, 2);
  722.     register_internal("WH", xy_tag_number, 2);
  723.     register_internal("R", nil_tag_number, 1);
  724. }
  725.  
  726. static void
  727. update_image_internals (void)
  728. {
  729.     internal_t *internal;
  730.     tuple_info_t dummy;
  731.  
  732.     internal = lookup_internal("t", &dummy);
  733.     internal->value.data[0] = currentT;
  734.  
  735.     internal = lookup_internal("XY", &dummy);
  736.     internal->value.data[0] = imageX;
  737.     internal->value.data[1] = imageY;
  738.     
  739.     internal = lookup_internal("WH", &dummy);
  740.     internal->value.data[0] = imageW;
  741.     internal->value.data[1] = imageH;
  742.     
  743.     internal = lookup_internal("R", &dummy);
  744.     internal->value.data[0] = imageR;
  745. }
  746.  
  747. static void
  748. update_pixel_internals (void)
  749. {
  750.     xy_internal->value.data[0] = currentX;
  751.     xy_internal->value.data[1] = currentY;
  752.  
  753.     ra_internal->value.data[0] = currentR;
  754.     ra_internal->value.data[1] = currentA;
  755. }
  756.  
  757. /*****/
  758.  
  759. static gint32 
  760. mathmap_layer_copy(gint32 layerID)
  761. {
  762.     GParam *return_vals;
  763.     int nreturn_vals;
  764.     gint32 nlayer;
  765.  
  766.     return_vals = gimp_run_procedure ("gimp_layer_copy", 
  767.                       &nreturn_vals,
  768.                       PARAM_LAYER, layerID,
  769.                       PARAM_INT32, TRUE,
  770.                       PARAM_END);
  771.  
  772.     if (return_vals[0].data.d_status == STATUS_SUCCESS)
  773.     nlayer = return_vals[1].data.d_layer;
  774.     else
  775.     nlayer = -1;
  776.     gimp_destroy_params(return_vals, nreturn_vals);
  777.     return nlayer;
  778.  
  779. /*****/
  780.  
  781. static void
  782. update_gradient (void)
  783. {
  784.     gdouble *samples;
  785.     int i;
  786.  
  787.     samples = gimp_gradients_sample_uniform(num_gradient_samples);
  788.  
  789.     for (i = 0; i < num_gradient_samples; ++i)
  790.     gradient_samples[i] = color_to_tuple(samples[i * 4 + 0], samples[i * 4 + 1],
  791.                          samples[i * 4 + 2], samples[i * 4 + 3]);
  792. }
  793.  
  794. /*****/
  795.  
  796. static int
  797. generate_code (void)
  798. {
  799.     static int result;
  800.  
  801.     result = 1;
  802.  
  803.     if (expression_changed)
  804.     {
  805.     if (run_mode == RUN_INTERACTIVE && expression_entry != 0)
  806.         dialog_text_update();
  807.  
  808.     theExprtree = 0;
  809.     usesRA = 0;
  810.  
  811.     untag_uservals();
  812.  
  813.     DO_JUMP_CODE {
  814.         clear_all_variables();
  815.         internals_clear_used();
  816.         scanFromString(mmvals.expression);
  817.         mmparse();
  818.         endScanningFromString();
  819.  
  820.         assert(theExprtree != 0);
  821.  
  822.         if (theExprtree->result.number != rgba_tag_number || theExprtree->result.length != 4)
  823.         {
  824.         sprintf(error_string, "The expression must have the result type rgba:4.");
  825.         JUMP(1);
  826.         }
  827.  
  828. #ifdef USE_CGEN
  829.         assert(gen_and_load_c_code(theExprtree));
  830. #else
  831.         make_postfix(theExprtree);
  832.         output_postfix();
  833. #endif
  834.  
  835.         expression_changed = 0;
  836.     } WITH_JUMP_HANDLER {
  837.         gimp_message(error_string);
  838.         make_empty_postfix();
  839.  
  840.         result = 0;
  841.     } END_JUMP_HANDLER;
  842.  
  843.     clear_untagged_uservals();
  844.     untag_uservals();
  845.     update_userval_table();
  846.     }
  847.  
  848.     update_image_internals();
  849.  
  850.     return result;
  851. }
  852.  
  853. /*****/
  854.  
  855. void
  856. write_tuple_to_pixel (tuple_t *tuple, guchar *dest)
  857. {
  858.     float redf,
  859.     greenf,
  860.     bluef,
  861.     alphaf;
  862.  
  863.     tuple_to_color(tuple, &redf, &greenf, &bluef, &alphaf);
  864.  
  865.     if (outputBPP == 1 || outputBPP == 2)
  866.     dest[0] = (0.299 * redf + 0.587 * greenf + 0.114 * bluef) * 255;
  867.     else if (outputBPP == 3 || outputBPP == 4)
  868.     {
  869.     dest[0] = redf * 255;
  870.     dest[1] = greenf * 255;
  871.     dest[2] = bluef * 255;
  872.     }
  873.     else
  874.     assert(0);
  875.  
  876.     if (outputBPP == 2 || outputBPP == 4)
  877.     dest[outputBPP - 1] = alphaf * 255;
  878. }
  879.  
  880. /*****/
  881.  
  882. static void
  883. unref_tiles (void)
  884. {
  885.     int i;
  886.  
  887.     for (i = 0; i < MAX_INPUT_DRAWABLES; ++i)
  888.     if (input_drawables[i].used != 0 && input_drawables[i].tile != 0)
  889.     {
  890.         gimp_tile_unref(input_drawables[i].tile, FALSE);
  891.         input_drawables[i].tile = 0;
  892.     }
  893. }
  894.  
  895. /*****/
  896.  
  897. int
  898. alloc_input_drawable (GDrawable *drawable)
  899. {
  900.     int i;
  901.  
  902.     for (i = 0; i < MAX_INPUT_DRAWABLES; ++i)
  903.     if (!input_drawables[i].used)
  904.         break;
  905.     if (i == MAX_INPUT_DRAWABLES)
  906.     return -1;
  907.  
  908.     input_drawables[i].drawable = drawable;
  909.     input_drawables[i].bpp = gimp_drawable_bpp(drawable->id);
  910.     input_drawables[i].row = -1;
  911.     input_drawables[i].col = -1;
  912.     input_drawables[i].tile = 0;
  913.     input_drawables[i].fast_image_source = 0;
  914.     input_drawables[i].used = 1;
  915.  
  916.     return i;
  917. }
  918.  
  919. void
  920. free_input_drawable (int index)
  921. {
  922.     assert(input_drawables[index].used);
  923.     if (input_drawables[index].tile != 0)
  924.     {
  925.     gimp_tile_unref(input_drawables[index].tile, FALSE);
  926.     input_drawables[index].tile = 0;
  927.     }
  928.     if (input_drawables[index].fast_image_source != 0)
  929.     {
  930.     g_free(input_drawables[index].fast_image_source);
  931.     input_drawables[index].fast_image_source = 0;
  932.     }
  933.     input_drawables[index].drawable = 0;
  934.     input_drawables[index].used = 0;
  935. }
  936.  
  937. GDrawable*
  938. get_input_drawable (int index)
  939. {
  940.     assert(input_drawables[index].used);
  941.  
  942.     return input_drawables[index].drawable;
  943. }
  944.  
  945. /*****/
  946.  
  947. static void
  948. mathmap (int frame_num)
  949. {
  950.     GPixelRgn dest_rgn;
  951.     gpointer  pr;
  952.     gint      progress, max_progress;
  953.     guchar   *dest_row;
  954.     guchar   *dest;
  955.     gint      row, col;
  956.     int i;
  957.     gchar progress_info[30];
  958.  
  959.     previewing = 0;
  960.  
  961.     num_ops = 0;
  962.  
  963.     outputBPP = gimp_drawable_bpp(output_drawable->id);
  964.  
  965.     if (generate_code())
  966.     {
  967.     /* Initialize pixel region */
  968.  
  969.     gimp_pixel_rgn_init(&dest_rgn, output_drawable, sel_x1, sel_y1, sel_width, sel_height,
  970.                 TRUE, TRUE);
  971.  
  972.     imageWidth = sel_width;
  973.     imageW = imageWidth;
  974.     imageHeight = sel_height;
  975.     imageH = imageHeight;
  976.  
  977.     middleX = imageWidth / 2.0;
  978.     middleY = imageHeight / 2.0;
  979.  
  980.     if (middleX > imageWidth - middleX)
  981.         imageX = middleX;
  982.     else
  983.         imageX = imageWidth - middleX;
  984.  
  985.     if (middleY > imageHeight - middleY)
  986.         imageY = middleY;
  987.     else
  988.         imageY = imageHeight - middleY;
  989.     
  990.     imageR = sqrt(imageX * imageX + imageY * imageY);
  991.  
  992.     progress     = 0;
  993.     max_progress = sel_width * sel_height;
  994.  
  995.     if (frame_num >= 0)
  996.         sprintf(progress_info, "Mathmapping frame %d...", frame_num + 1);
  997.     else
  998.         strcpy(progress_info, "Mathmapping...");
  999.     gimp_progress_init(progress_info);
  1000.  
  1001.     for (pr = gimp_pixel_rgns_register(1, &dest_rgn);
  1002.          pr != NULL; pr = gimp_pixel_rgns_process(pr))
  1003.     {
  1004.         if (oversamplingEnabled)
  1005.         {
  1006.         unsigned char *line1,
  1007.             *line2,
  1008.             *line3;
  1009.  
  1010.         dest_row = dest_rgn.data;
  1011.  
  1012.         line1 = (unsigned char*)malloc((sel_width + 1) * outputBPP);
  1013.         line2 = (unsigned char*)malloc(sel_width * outputBPP);
  1014.         line3 = (unsigned char*)malloc((sel_width + 1) * outputBPP);
  1015.  
  1016.         for (col = 0; col <= dest_rgn.w; ++col)
  1017.         {
  1018.             currentX = col + dest_rgn.x - sel_x1 - middleX;
  1019.             currentY = -(0.0 + dest_rgn.y - sel_y1 - middleY);
  1020.             calc_ra();
  1021.             update_pixel_internals();
  1022.             write_tuple_to_pixel(EVAL_EXPR(), line1 + col * outputBPP);
  1023.         }
  1024.  
  1025.         for (row = 0; row < dest_rgn.h; ++row)
  1026.         {
  1027.             dest = dest_row;
  1028.  
  1029.             for (col = 0; col < dest_rgn.w; ++col)
  1030.             {
  1031.             currentX = col + dest_rgn.x - sel_x1 + 0.5 - middleX;
  1032.             currentY = -(row + dest_rgn.y - sel_y1 + 0.5 - middleY);
  1033.             calc_ra();
  1034.             update_pixel_internals();
  1035.             write_tuple_to_pixel(EVAL_EXPR(), line2 + col * outputBPP);
  1036.             }
  1037.             for (col = 0; col <= dest_rgn.w; ++col)
  1038.             {
  1039.             currentX = col + dest_rgn.x - sel_x1 - middleX;
  1040.             currentY = -(row + dest_rgn.y - sel_y1 + 1.0 - middleY);
  1041.             calc_ra();
  1042.             update_pixel_internals();
  1043.             write_tuple_to_pixel(EVAL_EXPR(), line3 + col * outputBPP);
  1044.             }
  1045.         
  1046.             for (col = 0; col < dest_rgn.w; ++col)
  1047.             {
  1048.             for (i = 0; i < outputBPP; ++i)
  1049.                 dest[i] = (line1[col*outputBPP+i]
  1050.                        + line1[(col+1)*outputBPP+i]
  1051.                        + 2*line2[col*outputBPP+i]
  1052.                        + line3[col*outputBPP+i]
  1053.                        + line3[(col+1)*outputBPP+i]) / 6;
  1054.             dest += outputBPP;
  1055.             }
  1056.  
  1057.             memcpy(line1, line3, (imageWidth + 1) * outputBPP);
  1058.  
  1059.             dest_row += dest_rgn.rowstride;
  1060.         }
  1061.         }
  1062.         else
  1063.         {
  1064.         dest_row = dest_rgn.data;
  1065.  
  1066.         for (row = dest_rgn.y; row < (dest_rgn.y + dest_rgn.h); row++)
  1067.         {
  1068.             dest = dest_row;
  1069.  
  1070.             for (col = dest_rgn.x; col < (dest_rgn.x + dest_rgn.w); col++)
  1071.             {
  1072.             currentX = col - sel_x1 - middleX;
  1073.             currentY = -(row - sel_y1 - middleY);
  1074.             calc_ra();
  1075.             update_pixel_internals();
  1076.             write_tuple_to_pixel(EVAL_EXPR(), dest);
  1077.             dest += outputBPP;
  1078.             }
  1079.         
  1080.             dest_row += dest_rgn.rowstride;
  1081.         }
  1082.         }
  1083.  
  1084.         /* Update progress */
  1085.         progress += dest_rgn.w * dest_rgn.h;
  1086.         gimp_progress_update((double) progress / max_progress);
  1087.     }
  1088.  
  1089.     unref_tiles();
  1090.  
  1091.     gimp_drawable_flush(output_drawable);
  1092.     gimp_drawable_merge_shadow(output_drawable->id, TRUE);
  1093.     gimp_drawable_update(output_drawable->id, sel_x1, sel_y1, sel_width, sel_height);
  1094.  
  1095. #ifndef USE_CGEN
  1096.     fprintf(stderr, "executed %d instructions\n", num_ops);
  1097. #endif
  1098.     }
  1099. } /* mathmap */
  1100.  
  1101. /*****/
  1102.  
  1103. void
  1104. mathmap_get_pixel(int drawable_index, int x, int y, guchar *pixel)
  1105. {
  1106.     gint newcol, newrow;
  1107.     gint newcoloff, newrowoff;
  1108.     guchar *p;
  1109.     int i;
  1110.     input_drawable_t *drawable;
  1111.  
  1112.     if (drawable_index < 0 || drawable_index >= MAX_INPUT_DRAWABLES || !input_drawables[drawable_index].used
  1113.     || x < 0 || x >= img_width
  1114.     || y < 0 || y >= img_height)
  1115.     {
  1116.     for (i = 0; i < outputBPP; ++i)
  1117.         pixel[i] = edge_color[i];
  1118.     return;
  1119.     }
  1120.  
  1121.     drawable = &input_drawables[drawable_index];
  1122.  
  1123.     newcol = x / tile_width;
  1124.     newcoloff = x % tile_width;
  1125.     newrow = y / tile_height;
  1126.     newrowoff = y % tile_height;
  1127.  
  1128.     if (drawable->col != newcol || drawable->row != newrow || drawable->tile == NULL)
  1129.     {
  1130.     if (drawable->tile != NULL)
  1131.         gimp_tile_unref(drawable->tile, FALSE);
  1132.  
  1133.     drawable->tile = gimp_drawable_get_tile(drawable->drawable, FALSE, newrow, newcol);
  1134.     assert(drawable->tile != 0);
  1135.     gimp_tile_ref(drawable->tile);
  1136.  
  1137.     drawable->col = newcol;
  1138.     drawable->row = newrow;
  1139.     }
  1140.  
  1141.     p = drawable->tile->data + drawable->tile->bpp * (drawable->tile->ewidth * newrowoff + newcoloff);
  1142.  
  1143.     if (drawable->bpp == 1 || drawable->bpp == 2)
  1144.     pixel[0] = pixel[1] = pixel[2] = p[0];
  1145.     else if (drawable->bpp == 3 || drawable->bpp == 4)
  1146.     for (i = 0; i < 3; ++i)
  1147.         pixel[i] = p[i];
  1148.     else
  1149.     assert(0);
  1150.  
  1151.     if (drawable->bpp == 1 || drawable->bpp == 3)
  1152.     pixel[3] = 255;
  1153.     else
  1154.     pixel[3] = p[drawable->bpp - 1];
  1155. }
  1156.  
  1157. void
  1158. mathmap_get_fast_pixel(int drawable_index, int x, int y, guchar *pixel)
  1159. {
  1160.     input_drawable_t *drawable;
  1161.  
  1162.     if (drawable_index < 0 || drawable_index >= MAX_INPUT_DRAWABLES || !input_drawables[drawable_index].used
  1163.     || x < 0 || x >= preview_width
  1164.     || y < 0 || y >= preview_height)
  1165.     {
  1166.     int i;
  1167.  
  1168.     for (i = 0; i < outputBPP; ++i)
  1169.         pixel[i] = edge_color[i];
  1170.     return;
  1171.     }
  1172.  
  1173.     drawable = &input_drawables[drawable_index];
  1174.  
  1175.     if (drawable->fast_image_source == 0)
  1176.     build_fast_image_source(drawable);
  1177.  
  1178.     memcpy(pixel, drawable->fast_image_source + (x + y * preview_width) * 4, 4);
  1179. }
  1180.  
  1181. /*****/
  1182.  
  1183. static void
  1184. build_fast_image_source (input_drawable_t *drawable)
  1185. {
  1186.     guchar *p;
  1187.     int x, y;
  1188.  
  1189.     assert(drawable->fast_image_source == 0);
  1190.  
  1191.     p = drawable->fast_image_source = g_malloc(preview_width * preview_height * 4);
  1192.  
  1193.     for (y = 0; y < preview_height; ++y)
  1194.     {
  1195.     for (x = 0; x < preview_width; ++x)
  1196.     {
  1197.         mathmap_get_pixel(drawable - input_drawables,
  1198.                   sel_x1 + x * sel_width / preview_width,
  1199.                   sel_y1 + y * sel_height / preview_height, p);
  1200.         p += 4;
  1201.     }
  1202.     }
  1203. }
  1204.  
  1205. /*****/
  1206.  
  1207. static GtkWidget*
  1208. tree_from_lisp_object (GtkWidget *root_item, lisp_object_t *obj)
  1209. {
  1210.     GtkWidget *tree = gtk_tree_new();
  1211.  
  1212.     if (root_item != 0)
  1213.     gtk_tree_item_set_subtree(GTK_TREE_ITEM(root_item), tree);
  1214.  
  1215.     for (; lisp_type(obj) != LISP_TYPE_NIL; obj = lisp_cdr(obj))
  1216.     {
  1217.     lisp_object_t *vars[2];
  1218.     GtkWidget *item = 0;
  1219.  
  1220.     assert(lisp_type(obj) == LISP_TYPE_CONS);
  1221.  
  1222.     if (lisp_match_string("(group #?(string) . #?(list))", lisp_car(obj), vars))
  1223.     {
  1224.         item = gtk_tree_item_new_with_label(lisp_string(vars[0]));
  1225.         gtk_tree_append(GTK_TREE(tree), item);
  1226.         gtk_widget_show(item);
  1227.         tree_from_lisp_object(item, vars[1]);
  1228.     }
  1229.     else if (lisp_match_string("(expression #?(string) #?(string))", lisp_car(obj), vars))
  1230.     {
  1231.         item = gtk_tree_item_new_with_label(lisp_string(vars[0]));
  1232.         gtk_tree_append(GTK_TREE(tree), item);
  1233.         gtk_widget_show(item);
  1234.         gtk_object_set_user_data(GTK_OBJECT(item),
  1235.                      strcpy((char*)malloc(strlen(lisp_string(vars[1])) + 1),
  1236.                         lisp_string(vars[1])));
  1237.     }
  1238.     else
  1239.         assert(0);
  1240.     }
  1241.  
  1242.     gtk_widget_show(tree);
  1243.  
  1244.     if (root_item != 0)
  1245.     gtk_tree_item_expand(GTK_TREE_ITEM(root_item));
  1246.  
  1247.     return tree;
  1248. }
  1249.  
  1250. static GtkWidget*
  1251. read_tree_from_rc (void)
  1252. {
  1253.     GtkWidget *tree;
  1254.     lisp_object_t *obj = read_rc_file();
  1255.  
  1256.     if (obj == 0)
  1257.     {
  1258.     tree = gtk_tree_new();
  1259.     gtk_widget_show(tree);
  1260.     return tree;
  1261.     }
  1262.  
  1263.     tree = tree_from_lisp_object(0, obj);
  1264.     lisp_free(obj);
  1265.  
  1266.     return tree;
  1267. }
  1268.  
  1269. /*****/
  1270.  
  1271. static void
  1272. update_userval_table (void)
  1273. {
  1274.     if (uservalues_table != 0)
  1275.     {
  1276.     gtk_container_remove(GTK_CONTAINER(GTK_BIN(uservalues_scrolled_window)->child), uservalues_table);
  1277.     uservalues_table = 0;
  1278.     }
  1279.  
  1280.     uservalues_table = make_userval_table();
  1281.  
  1282.     if (uservalues_table != 0)
  1283.     {
  1284. #if GTK_MAJOR_VERSION < 1 || (GTK_MAJOR_VERSION == 1 && GTK_MINOR_VERSION < 1)
  1285.     gtk_container_add(GTK_CONTAINER(uservalues_scrolled_window), uservalues_table);
  1286. #else
  1287.     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(uservalues_scrolled_window), uservalues_table);
  1288. #endif
  1289.     }
  1290. }
  1291.  
  1292.  
  1293. /*****/
  1294.  
  1295. static gint
  1296. mathmap_dialog (int mutable_expression)
  1297. {
  1298.     GtkWidget *dialog;
  1299.     GtkWidget *top_table, *middle_table;
  1300.     GtkWidget *vbox;
  1301.     GtkWidget *frame;
  1302.     GtkWidget *table;
  1303.     GtkWidget *button;
  1304.     GtkWidget *label;
  1305.     GtkWidget *toggle;
  1306.     GtkWidget *alignment;
  1307.     GtkWidget *root_tree;
  1308.     GtkWidget *scale;
  1309.     GtkWidget *vscrollbar;
  1310.     GtkWidget *notebook;
  1311.     GtkObject *adjustment;
  1312.     GSList *edge_group = 0;
  1313.     gint        argc,
  1314.     position = 0;
  1315.     gchar     **argv;
  1316.     guchar     *color_cube;
  1317.  
  1318.     argc    = 1;
  1319.     argv    = g_new(gchar *, 1);
  1320.     argv[0] = g_strdup("mathmap");
  1321.  
  1322.     gtk_init(&argc, &argv);
  1323.  
  1324.     gtk_preview_set_gamma(gimp_gamma());
  1325.     gtk_preview_set_install_cmap(gimp_install_cmap());
  1326.     color_cube = gimp_color_cube();
  1327.     gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]);
  1328.  
  1329.     gtk_widget_set_default_visual(gtk_preview_get_visual());
  1330.     gtk_widget_set_default_colormap(gtk_preview_get_cmap());
  1331.  
  1332.     wint.wimage = g_malloc(preview_width * preview_height * 3 * sizeof(guchar));
  1333.  
  1334.     dialog = gtk_dialog_new();
  1335.     gtk_window_set_title(GTK_WINDOW(dialog), "MathMap");
  1336.     gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
  1337.     gtk_container_border_width(GTK_CONTAINER(dialog), 0);
  1338.     gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
  1339.                (GtkSignalFunc) dialog_close_callback,
  1340.                NULL);
  1341.  
  1342.     top_table = gtk_hbox_new(FALSE, 0);
  1343.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), top_table, TRUE, TRUE, 0);
  1344.     gtk_widget_show(top_table);
  1345.  
  1346.     /* Preview */
  1347.  
  1348.     vbox = gtk_vbox_new(FALSE, 0);
  1349.     gtk_box_pack_start(GTK_BOX(top_table), vbox, FALSE, FALSE, 0);
  1350.     gtk_widget_show(vbox);
  1351.     frame = gtk_frame_new(NULL);
  1352.     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
  1353.     gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
  1354.     gtk_widget_show(frame);
  1355.  
  1356.     wint.preview = gtk_preview_new(GTK_PREVIEW_COLOR);
  1357.     gtk_preview_size(GTK_PREVIEW(wint.preview), preview_width, preview_height);
  1358.     gtk_container_add(GTK_CONTAINER(frame), wint.preview);
  1359.     gtk_widget_show(wint.preview);
  1360.  
  1361.     button = gtk_button_new_with_label("Preview");
  1362.     gtk_signal_connect(GTK_OBJECT(button), "clicked",
  1363.                (GtkSignalFunc)dialog_preview_callback, 0);
  1364.     gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
  1365.     gtk_widget_show(button);
  1366.  
  1367.     /* Notebook */
  1368.  
  1369.     notebook = gtk_notebook_new();
  1370.     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
  1371.     gtk_box_pack_start(GTK_BOX(top_table), notebook, TRUE, TRUE, 0);
  1372.     gtk_widget_show(notebook);
  1373.  
  1374.     /* Settings */
  1375.  
  1376.     middle_table = gtk_table_new(3, 2, FALSE);
  1377.     gtk_container_border_width(GTK_CONTAINER(middle_table), 6);
  1378.     gtk_table_set_col_spacings(GTK_TABLE(middle_table), 4);
  1379.     gtk_widget_show(middle_table);
  1380.  
  1381.             /* Sampling */
  1382.  
  1383.             table = gtk_table_new(2, 1, FALSE);
  1384.         gtk_container_border_width(GTK_CONTAINER(table), 6);
  1385.         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
  1386.     
  1387.         frame = gtk_frame_new(NULL);
  1388.         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  1389.         gtk_container_add(GTK_CONTAINER(frame), table);
  1390.         gtk_table_attach(GTK_TABLE(middle_table), frame, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1391.  
  1392.         gtk_widget_show(table);
  1393.         gtk_widget_show(frame);
  1394.  
  1395.                 /* Intersampling */
  1396.  
  1397.         toggle = gtk_check_button_new_with_label("Intersampling");
  1398.         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),
  1399.                         mmvals.flags & FLAG_INTERSAMPLING);
  1400.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1401.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1402.                    (GtkSignalFunc)dialog_intersampling_update, 0);
  1403.         gtk_widget_show(toggle);
  1404.  
  1405.         /* Oversampling */
  1406.         
  1407.         toggle = gtk_check_button_new_with_label("Oversampling");
  1408.         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),
  1409.                         mmvals.flags & FLAG_OVERSAMPLING);
  1410.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
  1411.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1412.                    (GtkSignalFunc)dialog_oversampling_update, 0);
  1413.         gtk_widget_show(toggle);
  1414.  
  1415.         /* Preview Options */
  1416.  
  1417.             table = gtk_table_new(2, 1, FALSE);
  1418.         gtk_container_border_width(GTK_CONTAINER(table), 6);
  1419.         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
  1420.     
  1421.         frame = gtk_frame_new(NULL);
  1422.         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  1423.         gtk_container_add(GTK_CONTAINER(frame), table);
  1424.         gtk_table_attach(GTK_TABLE(middle_table), frame, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
  1425.  
  1426.         gtk_widget_show(table);
  1427.         gtk_widget_show(frame);
  1428.  
  1429.             /* Auto Preview */
  1430.  
  1431.             toggle = gtk_check_button_new_with_label("Auto Preview");
  1432.         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), auto_preview);
  1433.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1434.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1435.                    (GtkSignalFunc)dialog_auto_preview_update, 0);
  1436.         gtk_widget_show(toggle);
  1437.  
  1438.             /* Fast Preview */
  1439.  
  1440.         toggle = gtk_check_button_new_with_label("Fast Preview");
  1441.         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), fast_preview);
  1442.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
  1443.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1444.                    (GtkSignalFunc)dialog_fast_preview_update, 0);
  1445.         gtk_widget_show(toggle);
  1446.  
  1447.         /* Edge Behaviour */
  1448.  
  1449.         table = gtk_table_new(2, 3, FALSE);
  1450.         gtk_container_border_width(GTK_CONTAINER(table), 6);
  1451.         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
  1452.  
  1453.         frame = gtk_frame_new("Edge Behaviour");
  1454.         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  1455.         gtk_container_add(GTK_CONTAINER(frame), table);
  1456.         gtk_table_attach(GTK_TABLE(middle_table), frame, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
  1457.  
  1458.         gtk_widget_show(table);
  1459.         gtk_widget_show(frame);
  1460.  
  1461.             /* Color */
  1462.  
  1463.             toggle = gtk_radio_button_new_with_label(edge_group, "Color");
  1464.         edge_group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
  1465.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1466.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1467.                    (GtkSignalFunc)dialog_edge_behaviour_update, &edge_behaviour_color);
  1468.         gtk_widget_show(toggle);
  1469.  
  1470.         edge_color_well = color_well_new();
  1471.         gtk_signal_connect(GTK_OBJECT(edge_color_well), "color-changed",
  1472.                    (GtkSignalFunc)dialog_edge_color_changed, 0);
  1473.         dialog_edge_color_set();
  1474.         gtk_widget_show(edge_color_well);
  1475.         gtk_table_attach(GTK_TABLE(table), edge_color_well, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
  1476.  
  1477.             /* Wrap */
  1478.  
  1479.             toggle = gtk_radio_button_new_with_label(edge_group, "Wrap");
  1480.         edge_group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
  1481.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
  1482.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1483.                    (GtkSignalFunc)dialog_edge_behaviour_update, &edge_behaviour_wrap);
  1484.         gtk_widget_show(toggle);
  1485.  
  1486.             /* Reflect */
  1487.  
  1488.             toggle = gtk_radio_button_new_with_label(edge_group, "Reflect");
  1489.         edge_group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
  1490.         gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
  1491.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1492.                    (GtkSignalFunc)dialog_edge_behaviour_update, &edge_behaviour_reflect);
  1493.         gtk_widget_show(toggle);
  1494.  
  1495.         /* Animation */
  1496.         
  1497.         table = gtk_table_new(3, 1, FALSE);
  1498.         gtk_container_border_width(GTK_CONTAINER(table), 6);
  1499.         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
  1500.         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
  1501.     
  1502.         frame = gtk_frame_new(NULL);
  1503.         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  1504.         gtk_container_add(GTK_CONTAINER(frame), table);
  1505.  
  1506.         alignment = gtk_alignment_new(0, 0, 0, 0);
  1507.         gtk_container_add(GTK_CONTAINER(alignment), frame);
  1508.         gtk_table_attach(GTK_TABLE(middle_table), alignment, 1, 2, 0, 3, GTK_FILL, 0, 0, 0);
  1509.  
  1510.         gtk_widget_show(table);
  1511.         gtk_widget_show(frame);
  1512.         gtk_widget_show(alignment);
  1513.  
  1514.             /* Animation Toggle */
  1515.  
  1516.             alignment = gtk_alignment_new(0, 0, 0, 0);
  1517.         toggle = gtk_check_button_new_with_label("Animate");
  1518.         gtk_container_add(GTK_CONTAINER(alignment), toggle);
  1519.         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),
  1520.                         mmvals.flags & FLAG_ANIMATION);
  1521.         gtk_table_attach(GTK_TABLE(table), alignment, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1522.         gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
  1523.                    (GtkSignalFunc)dialog_animation_update, 0);
  1524.         gtk_widget_show(toggle);
  1525.         gtk_widget_show(alignment);
  1526.  
  1527.         /* Number of Frames */
  1528.  
  1529.         frame_table = gtk_table_new(1, 2, FALSE);
  1530.         gtk_table_set_col_spacings(GTK_TABLE(frame_table), 4);
  1531.         gtk_table_attach(GTK_TABLE(table), frame_table, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
  1532.  
  1533.         label = gtk_label_new("Frames");
  1534.         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  1535.         gtk_table_attach(GTK_TABLE(frame_table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1536.         adjustment = gtk_adjustment_new(mmvals.frames, 2, 100, 1.0, 1.0, 0.0);
  1537.         scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
  1538.         gtk_widget_set_usize(scale, 100, 0);
  1539.         gtk_table_attach (GTK_TABLE (frame_table), scale, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
  1540.         gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  1541.         gtk_scale_set_digits(GTK_SCALE(scale),0);
  1542.         gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  1543.         gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  1544.                     (GtkSignalFunc) dialog_scale_update,
  1545.                     &mmvals.frames);
  1546.         gtk_widget_show(label);
  1547.         gtk_widget_show(scale);
  1548.  
  1549.         gtk_widget_show(frame_table);
  1550.         gtk_widget_set_sensitive(frame_table, mmvals.flags & FLAG_ANIMATION);
  1551.  
  1552.         /* t */
  1553.  
  1554.         t_table = gtk_table_new(1, 2, FALSE);
  1555.         gtk_table_set_col_spacings(GTK_TABLE(t_table), 4);
  1556.         gtk_table_attach(GTK_TABLE(table), t_table, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
  1557.  
  1558.         label = gtk_label_new("Parameter t");
  1559.         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  1560.         gtk_table_attach(GTK_TABLE(t_table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
  1561.         adjustment = gtk_adjustment_new(mmvals.param_t, 0.0, 1.0, 0.01, 0.1, 0.0);
  1562.         scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
  1563.         gtk_widget_set_usize(scale, 100, 0);
  1564.         gtk_table_attach (GTK_TABLE (t_table), scale, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
  1565.         gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  1566.         gtk_scale_set_digits(GTK_SCALE(scale),2);
  1567.         gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_CONTINUOUS);
  1568.         gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  1569.                     (GtkSignalFunc) dialog_t_update,
  1570.                     &mmvals.param_t);
  1571.         gtk_widget_show(label);
  1572.         gtk_widget_show(scale);
  1573.  
  1574.         gtk_widget_show(t_table);
  1575.         gtk_widget_set_sensitive(t_table, !(mmvals.flags & FLAG_ANIMATION));
  1576.  
  1577.     label = gtk_label_new("Settings");
  1578.     gtk_widget_show(label);
  1579.     gtk_notebook_append_page_menu(GTK_NOTEBOOK(notebook), middle_table, label, label);
  1580.  
  1581.         /* Expression */
  1582.  
  1583.     if (mutable_expression)
  1584.     {
  1585.         table = gtk_hbox_new(FALSE, 0);
  1586.         gtk_widget_show(table);
  1587.  
  1588.         label = gtk_label_new("Expression");
  1589.         gtk_widget_show(label);
  1590.         gtk_notebook_append_page_menu(GTK_NOTEBOOK(notebook), table, label, label);
  1591.  
  1592.         expression_entry = gtk_text_new(NULL, NULL);
  1593.         gtk_signal_connect(GTK_OBJECT(expression_entry), "changed",
  1594.                    (GtkSignalFunc)dialog_text_changed,
  1595.                    (gpointer)NULL);
  1596.         gtk_text_set_editable(GTK_TEXT(expression_entry), TRUE);
  1597.         gtk_box_pack_start(GTK_BOX(table), expression_entry, TRUE, TRUE, 0);
  1598.         gtk_widget_show(expression_entry);
  1599.         /* gtk_text_freeze(GTK_TEXT(expression_entry)); */
  1600.         gtk_widget_realize(expression_entry);
  1601.         /* gtk_text_thaw(GTK_TEXT(expression_entry)); */
  1602.         gtk_editable_insert_text(GTK_EDITABLE(expression_entry), mmvals.expression,
  1603.                      strlen(mmvals.expression), &position);
  1604.  
  1605.         vscrollbar = gtk_vscrollbar_new(GTK_TEXT(expression_entry)->vadj);
  1606.         gtk_box_pack_start(GTK_BOX(table), vscrollbar, FALSE, FALSE, 0);
  1607.         gtk_widget_show (vscrollbar);
  1608.     }
  1609.  
  1610.     /* User Values */
  1611.  
  1612.     uservalues_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  1613.     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(uservalues_scrolled_window),
  1614.                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  1615.     gtk_widget_show(uservalues_scrolled_window);
  1616.  
  1617.     uservalues_table = 0;
  1618.  
  1619.     label = gtk_label_new("User Values");
  1620.     gtk_widget_show(label);
  1621.     gtk_notebook_append_page_menu(GTK_NOTEBOOK(notebook), uservalues_scrolled_window, label, label);
  1622.  
  1623.     /* Examples */
  1624.  
  1625.     if (mutable_expression)
  1626.     {
  1627.         table = gtk_scrolled_window_new (NULL, NULL);
  1628.         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(table),
  1629.                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  1630.         gtk_widget_show (table);
  1631.  
  1632.         root_tree = read_tree_from_rc();
  1633.         gtk_signal_connect(GTK_OBJECT(root_tree), "selection_changed",
  1634.                    (GtkSignalFunc)dialog_tree_changed,
  1635.                    (gpointer)NULL);
  1636. #if GTK_MAJOR_VERSION < 1 || (GTK_MAJOR_VERSION == 1 && GTK_MINOR_VERSION < 1)
  1637.         gtk_container_add(GTK_CONTAINER(table), root_tree);
  1638. #else
  1639.         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(table), root_tree);
  1640. #endif
  1641.         gtk_tree_set_selection_mode(GTK_TREE(root_tree), GTK_SELECTION_BROWSE);
  1642.         gtk_tree_set_view_lines(GTK_TREE(root_tree), FALSE);
  1643.         gtk_tree_set_view_mode(GTK_TREE(root_tree), FALSE);
  1644.         gtk_widget_show(root_tree);
  1645.  
  1646.         label = gtk_label_new("Examples");
  1647.         gtk_widget_show(label);
  1648.         gtk_notebook_append_page_menu(GTK_NOTEBOOK(notebook), table, label, label);
  1649.     }
  1650.  
  1651.     /* Buttons */
  1652.  
  1653.     gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
  1654.  
  1655.     button = gtk_button_new_with_label("OK");
  1656.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  1657.     gtk_signal_connect(GTK_OBJECT(button), "clicked",
  1658.                (GtkSignalFunc) dialog_ok_callback,
  1659.                dialog);
  1660.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  1661.     gtk_widget_grab_default(button);
  1662.     gtk_widget_show(button);
  1663.  
  1664.     button = gtk_button_new_with_label("Cancel");
  1665.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  1666.     gtk_signal_connect(GTK_OBJECT(button), "clicked",
  1667.                (GtkSignalFunc) dialog_cancel_callback,
  1668.                dialog);
  1669.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  1670.     gtk_widget_show(button);
  1671.  
  1672.     button = gtk_button_new_with_label("Help");
  1673.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  1674.     gtk_signal_connect(GTK_OBJECT(button), "clicked",
  1675.                (GtkSignalFunc) dialog_help_callback,
  1676.                dialog);
  1677.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  1678.     gtk_widget_show(button);
  1679.  
  1680.     button = gtk_button_new_with_label("About");
  1681.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  1682.     gtk_signal_connect(GTK_OBJECT(button), "clicked",
  1683.                (GtkSignalFunc) dialog_about_callback,
  1684.                dialog);
  1685.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  1686.     gtk_widget_show(button);
  1687.  
  1688.     /* Done */
  1689.  
  1690.     if (!mutable_expression)
  1691.     dialog_update_preview();
  1692.  
  1693.     gtk_widget_show(dialog);
  1694.  
  1695.     gtk_main();
  1696.     gdk_flush();
  1697.  
  1698.     unref_tiles();
  1699.  
  1700.     g_free(wint.wimage);
  1701.  
  1702.     return wint.run;
  1703. } /* mathmap_dialog */
  1704.  
  1705.  
  1706. /*****/
  1707.  
  1708. void
  1709. dialog_update_preview(void)
  1710. {
  1711.     double  left, right, bottom, top;
  1712.     double  dx, dy;
  1713.     int     x, y;
  1714.     double  scale_x, scale_y;
  1715.     guchar *p_ul, *p_lr, *p;
  1716.     gint check,check_0,check_1; 
  1717.  
  1718.     update_uservals();
  1719.  
  1720.     previewing = fast_preview;
  1721.  
  1722.     intersamplingEnabled = mmvals.flags & FLAG_INTERSAMPLING;
  1723.     oversamplingEnabled = mmvals.flags & FLAG_OVERSAMPLING;
  1724.  
  1725.     currentT = mmvals.param_t;
  1726.  
  1727.     left   = sel_x1;
  1728.     right  = sel_x2 - 1;
  1729.     bottom = sel_y2 - 1;
  1730.     top    = sel_y1;
  1731.  
  1732.     dx = (right - left) / (preview_width - 1);
  1733.     dy = (bottom - top) / (preview_height - 1);
  1734.  
  1735.     scale_x = (double) (preview_width - 1) / (right - left);
  1736.     scale_y = (double) (preview_height - 1) / (bottom - top);
  1737.  
  1738.     p_ul = wint.wimage;
  1739.     p_lr = wint.wimage + 3 * (preview_width * preview_height - 1);
  1740.  
  1741.     imageWidth = sel_width;
  1742.     imageW = imageWidth;
  1743.     imageHeight = sel_height;
  1744.     imageH = imageHeight;
  1745.  
  1746.     middleX = imageWidth / 2.0;
  1747.     middleY = imageHeight / 2.0;
  1748.  
  1749.     if (middleX > imageWidth - middleX)
  1750.     imageX = middleX;
  1751.     else
  1752.     imageX = imageWidth - middleX;
  1753.  
  1754.     if (middleY > imageHeight - middleY)
  1755.     imageY = middleY;
  1756.     else
  1757.     imageY = imageHeight - middleY;
  1758.     
  1759.     imageR = sqrt(imageX * imageX + imageY * imageY);
  1760.  
  1761.     if (generate_code())
  1762.     {
  1763.     for (y = 0; y < preview_height; y++)
  1764.     {
  1765.         if ((y / CHECK_SIZE) & 1) {
  1766.         check_0 = CHECK_DARK;
  1767.         check_1 = CHECK_LIGHT;
  1768.         } else {
  1769.         check_0 = CHECK_LIGHT;
  1770.         check_1 = CHECK_DARK;
  1771.         }                        
  1772.         for (x = 0; x < preview_width; x++)
  1773.         {
  1774.         tuple_t *result;
  1775.         float redf,
  1776.             greenf,
  1777.             bluef,
  1778.             alphaf;
  1779.  
  1780.         currentX = x * imageWidth / preview_width - middleX;
  1781.         currentY = -(y * imageHeight / preview_height - middleY);
  1782.         calc_ra();
  1783.         update_pixel_internals();
  1784.         result = EVAL_EXPR();
  1785.         tuple_to_color(result, &redf, &greenf, &bluef, &alphaf);
  1786.  
  1787.         if (input_drawables[0].bpp < 2)
  1788.             redf = greenf = bluef = 0.299 * redf + 0.587 * greenf + 0.114 * bluef;
  1789.  
  1790.         p_ul[0] = redf * 255;
  1791.         p_ul[1] = greenf * 255;
  1792.         p_ul[2] = bluef * 255;
  1793.  
  1794.         if (outputBPP == 2 || outputBPP == 4)
  1795.         {
  1796.             if (((x) / CHECK_SIZE) & 1)
  1797.             check = check_0;
  1798.             else
  1799.             check = check_1;
  1800.             p_ul[0] = check + (p_ul[0] - check) * alphaf;
  1801.             p_ul[1] = check + (p_ul[1] - check) * alphaf;
  1802.             p_ul[2] = check + (p_ul[2] - check) * alphaf;
  1803.         }
  1804.  
  1805.         p_ul += 3;
  1806.         }
  1807.     }
  1808.  
  1809.     p = wint.wimage;
  1810.  
  1811.     for (y = 0; y < preview_height; y++)
  1812.     {
  1813.         gtk_preview_draw_row(GTK_PREVIEW(wint.preview), p, 0, y, preview_width);
  1814.  
  1815.         p += preview_width * 3;
  1816.     }
  1817.  
  1818.     gtk_widget_draw(wint.preview, NULL);
  1819.     gdk_flush();
  1820.     }
  1821. } /* dialog_update_preview */
  1822.  
  1823.  
  1824. /*****/
  1825.  
  1826. static void
  1827. dialog_scale_update(GtkAdjustment *adjustment, gint *value)
  1828. {
  1829.     *value = (gint)adjustment->value;
  1830. } /* dialog_scale_update */
  1831.  
  1832.  
  1833. /*****/
  1834.  
  1835. static void
  1836. dialog_t_update(GtkAdjustment *adjustment, gfloat *value)
  1837. {
  1838.     *value = (gfloat)adjustment->value;
  1839.  
  1840.     if (auto_preview)
  1841.     dialog_update_preview();
  1842. } /* dialog_scale_update */
  1843.  
  1844.  
  1845. /*****/
  1846.  
  1847. static void
  1848. dialog_text_changed (void)
  1849. {
  1850.     expression_changed = 1;
  1851. }
  1852.  
  1853. /*****/
  1854.  
  1855. static void
  1856. dialog_text_update (void)
  1857. {
  1858.     guint length = gtk_text_get_length(GTK_TEXT(expression_entry));
  1859.     char *expression = (char*)malloc(length + 1);
  1860.     int i;
  1861.  
  1862.     for (i = 0; i < length; ++i)
  1863.     expression[i] = GTK_TEXT_INDEX(GTK_TEXT(expression_entry), i);
  1864.     expression[i] = '\0';
  1865.  
  1866.     expression_copy(mmvals.expression, expression);
  1867.  
  1868.     free(expression);
  1869. } /* dialog_text_update */
  1870.  
  1871. /*****/
  1872.  
  1873. static void
  1874. dialog_oversampling_update (GtkWidget *widget, gpointer data)
  1875. {
  1876.     mmvals.flags &= ~FLAG_OVERSAMPLING;
  1877.  
  1878.     if (GTK_TOGGLE_BUTTON(widget)->active)
  1879.     mmvals.flags |= FLAG_OVERSAMPLING;
  1880. }
  1881.  
  1882. /*****/
  1883.  
  1884. static void
  1885. dialog_auto_preview_update (GtkWidget *widget, gpointer data)
  1886. {
  1887.     auto_preview = GTK_TOGGLE_BUTTON(widget)->active;
  1888. }
  1889.  
  1890. /*****/
  1891.  
  1892. static void
  1893. dialog_fast_preview_update (GtkWidget *widget, gpointer data)
  1894. {
  1895.     fast_preview = GTK_TOGGLE_BUTTON(widget)->active;
  1896.     if (auto_preview)
  1897.     dialog_update_preview();
  1898. }
  1899.  
  1900. /*****/
  1901.  
  1902. static void
  1903. dialog_edge_behaviour_update (GtkWidget *widget, gpointer data)
  1904. {
  1905.     edge_behaviour_mode = *(int*)data;
  1906.     if (edge_behaviour_mode == edge_behaviour_color)
  1907.     {
  1908.     gtk_widget_set_sensitive(edge_color_well, 1);
  1909.     }
  1910.     else
  1911.     {
  1912.     gtk_widget_set_sensitive(edge_color_well, 0);
  1913.     }
  1914.  
  1915.     if (auto_preview)
  1916.     dialog_update_preview();
  1917. }
  1918.  
  1919. static void
  1920. dialog_edge_color_set (void)
  1921. {
  1922.     gdouble color[4];
  1923.     int i;
  1924.  
  1925.     for (i = 0; i < 4; ++i)
  1926.     color[i] = edge_color[i] / 255.0;
  1927.  
  1928.     color_well_set_color(COLOR_WELL(edge_color_well), color);
  1929. }
  1930.  
  1931. static void
  1932. dialog_edge_color_changed (ColorWell *color_well, gpointer data)
  1933. {
  1934.     gdouble color[4];
  1935.     int i;
  1936.  
  1937.     color_well_get_color(color_well, color);
  1938.     for (i = 0; i < 4; ++i)
  1939.     edge_color[i] = color[i] * 255.0;
  1940.     if (auto_preview)
  1941.     dialog_update_preview();
  1942. }
  1943.  
  1944. /*****/
  1945.  
  1946. static void
  1947. dialog_intersampling_update (GtkWidget *widget, gpointer data)
  1948. {
  1949.     mmvals.flags &= ~FLAG_INTERSAMPLING;
  1950.  
  1951.     if (GTK_TOGGLE_BUTTON(widget)->active)
  1952.     mmvals.flags |= FLAG_INTERSAMPLING;
  1953.  
  1954.     expression_changed = 1;
  1955.  
  1956.     if (auto_preview)
  1957.     dialog_update_preview();
  1958. }
  1959.  
  1960. /*****/
  1961.  
  1962. static void
  1963. dialog_animation_update (GtkWidget *widget, gpointer data)
  1964. {
  1965.     mmvals.flags &= ~FLAG_ANIMATION;
  1966.  
  1967.     if (GTK_TOGGLE_BUTTON(widget)->active)
  1968.     mmvals.flags |= FLAG_ANIMATION;
  1969.  
  1970.     gtk_widget_set_sensitive(frame_table, mmvals.flags & FLAG_ANIMATION);
  1971.     gtk_widget_set_sensitive(t_table, !(mmvals.flags & FLAG_ANIMATION));
  1972. }
  1973.  
  1974. /*****/
  1975.  
  1976. static void
  1977. dialog_preview_callback (GtkWidget *widget, gpointer data)
  1978. {
  1979.     update_gradient();
  1980.     dialog_update_preview();
  1981. }
  1982.  
  1983. /*****/
  1984.  
  1985. static void
  1986. dialog_close_callback (GtkWidget *widget, gpointer data)
  1987. {
  1988.     gtk_main_quit();
  1989. } /* dialog_close_callback */
  1990.  
  1991.  
  1992. /*****/
  1993.  
  1994. static void
  1995. dialog_ok_callback (GtkWidget *widget, gpointer data)
  1996. {
  1997.     if (generate_code())
  1998.     {
  1999.     wint.run = TRUE;
  2000.     gtk_widget_destroy(GTK_WIDGET(data));
  2001.     }
  2002. } /* dialog_ok_callback */
  2003.  
  2004.  
  2005. /*****/
  2006.  
  2007. static void
  2008. dialog_cancel_callback (GtkWidget *widget, gpointer data)
  2009. {
  2010.     gtk_widget_destroy(GTK_WIDGET(data));
  2011. } /* dialog_cancel_callback */
  2012.  
  2013. /*****/
  2014.  
  2015. static void
  2016. dialog_help_callback (GtkWidget *widget, gpointer data)
  2017. {
  2018.     char *proc_blurb, *proc_help, *proc_author, *proc_copyright, *proc_date;
  2019.     int proc_type, nparams, nreturn_vals;
  2020.     GParamDef *params, *return_vals;
  2021.     gint baz;
  2022.  
  2023.     if (gimp_query_procedure ("extension_web_browser",
  2024.                   &proc_blurb, &proc_help, 
  2025.                   &proc_author, &proc_copyright, &proc_date,
  2026.                   &proc_type, &nparams, &nreturn_vals,
  2027.                   ¶ms, &return_vals)) 
  2028.     gimp_run_procedure ("extension_web_browser", &baz,
  2029.                 PARAM_INT32, RUN_NONINTERACTIVE,
  2030.                 PARAM_STRING, MATHMAP_MANUAL_URL,
  2031.                 PARAM_INT32, 1,
  2032.                 PARAM_END);
  2033.     else 
  2034.     {
  2035.     gchar *message = g_strdup_printf("See %s", MATHMAP_MANUAL_URL);
  2036.  
  2037.     gimp_message(message);
  2038.     g_free(message);
  2039.     }                                            
  2040. } /* dialog_help_callback */
  2041.  
  2042. /*****/
  2043.  
  2044. static void
  2045. dialog_about_callback (GtkWidget *widget, gpointer data)
  2046. {
  2047.     gimp_message("MathMap " MATHMAP_VERSION "\n"
  2048.          "written by\n"
  2049.          "Mark Probst <schani@complang.tuwien.ac.at>");
  2050. } /* dialog_about_callback */
  2051.  
  2052. /*****/
  2053.  
  2054. static void
  2055. dialog_tree_changed (GtkTree *tree)
  2056. {
  2057.     GList *selection;
  2058.     GtkWidget *tree_item;
  2059.  
  2060.     selection = GTK_TREE_SELECTION(tree);
  2061.  
  2062.     if (g_list_length(selection) != 1)
  2063.     return;
  2064.  
  2065.     tree_item = GTK_WIDGET(selection->data);
  2066.  
  2067.     if (gtk_object_get_user_data(GTK_OBJECT(tree_item)) != 0)
  2068.     {
  2069.     char *expression = (char*)gtk_object_get_user_data(GTK_OBJECT(tree_item));
  2070.     gint position = 0;
  2071.  
  2072.     tree_item = GTK_WIDGET(selection->data);
  2073.     
  2074.     gtk_editable_delete_text(GTK_EDITABLE(expression_entry), 0,
  2075.                  gtk_text_get_length(GTK_TEXT(expression_entry)));
  2076.     gtk_editable_insert_text(GTK_EDITABLE(expression_entry), expression, strlen(expression),
  2077.                  &position);
  2078.  
  2079.     expression_copy(mmvals.expression, expression);
  2080.     }
  2081.  
  2082.     if (auto_preview)
  2083.     dialog_update_preview();
  2084. }
  2085.