pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

lazza private pastebin - collaborative debugging tool What's a private pastebin?


Posted by Lazza on Sat 1 Nov 22:16
report abuse | download | new post

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Kaleidoscope
  5.  * Copyright (C) 1999, 2002 Kelly Martin, updated 2005 by Matthew Plough
  6.  * kelly@gimp.org
  7.  * Derived from WhirlPinch
  8.  * Copyright (C) 1997 Federico Mena Quintero
  9.  * federico@nuclecu.unam.mx
  10.  * Copyright (C) 1997 Scott Goehring
  11.  * scott@poverty.bloomington.in.us
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26.  */
  27.  
  28. /* Version 0.10-2
  29.  *
  30.  * Updated for GIMP 2. Still needs some dialog cleanup.
  31.  *
  32.  * Version 0.10
  33.  *
  34.  * Made the user interface rather less unintuitive
  35.  * Added the "wrap" option
  36.  *
  37.  * Version 0.02
  38.  *
  39.  * Added edge handling options.
  40.  *
  41.  * Version 0.01
  42.  *
  43.  * First version.
  44.  */
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48.  
  49. #include <gtk/gtk.h>
  50. #include <libgimp/gimp.h>
  51. #include <libgimp/gimpcompat.h>
  52.  
  53. #define PLUG_IN_NAME    "plug_in_kaleidoscope"
  54.  
  55. #include <libintl.h> /* i18n - gettext */
  56. #define _(String) gettext (String)
  57. #ifdef gettext_noop
  58. # define N_(String) gettext_noop (String)
  59. #else
  60. # define N_(String) (String)
  61. #endif
  62.  
  63. /***** Magic numbers *****/
  64.  
  65. #define PREVIEW_SIZE 128
  66. #define SCALE_WIDTH  200
  67. #define ENTRY_WIDTH  60
  68.  
  69. #define CHECK_SIZE  8
  70. #define CHECK_DARK  ((int) (1.0 / 3.0 * 255))
  71. #define CHECK_LIGHT ((int) (2.0 / 3.0 * 255))
  72.  
  73. #define BORDER_FILL 0
  74. #define BORDER_WRAP 1
  75. #define BORDER_SMEAR 2
  76.  
  77.  
  78. /***** Types *****/
  79.  
  80. typedef struct {
  81.   gdouble angle1;
  82.   gdouble angle2;
  83.   gint    nsegs;
  84.   gdouble cen_x;
  85.   gdouble cen_y;
  86.   gdouble off_x;
  87.   gdouble off_y;
  88.   gint    border;
  89. } kaleidoscope_vals_t;
  90.  
  91. typedef struct {
  92.   GtkWidget *preview;
  93.   guchar    *check_row_0;
  94.   guchar    *check_row_1;
  95.   guchar    *image;
  96.   guchar    *dimage;
  97.  
  98.   gint run;
  99. } kaleidoscope_interface_t;
  100.  
  101. typedef struct {
  102.   gint       col, row;
  103.   gint       img_width, img_height, img_bpp, img_has_alpha;
  104.   gint       tile_width, tile_height;
  105.   guchar     bg_color[4];
  106.   GimpDrawable *drawable;
  107.   GimpTile     *tile;
  108.   gint       wrap;
  109. } pixel_fetcher_t;
  110.  
  111.  
  112. /***** Prototypes *****/
  113.  
  114. static void query(void);
  115. static void run(const gchar    *name,
  116.                 gint      nparams,
  117.                 const GimpParam  *param,
  118.                 gint     *nreturn_vals,
  119.                 GimpParam **return_vals);
  120.  
  121. static void   kaleidoscope(void);
  122. static int    calc_undistorted_coords(double wx, double wy,
  123.                                       double angle1, double angle2, int nsegs,
  124.                                       double cen_x, double cen_y,
  125.                                       double off_x, double off_y,
  126.                                       double *x, double *y);
  127. static guchar bilinear(double x, double y, guchar *values);
  128.  
  129. static pixel_fetcher_t *pixel_fetcher_new(GimpDrawable *drawable, int wrap);
  130. static void             pixel_fetcher_set_bg_color(pixel_fetcher_t *pf, guchar r, guchar g, guchar b, guchar a);
  131. static void             pixel_fetcher_get_pixel(pixel_fetcher_t *pf, int x, int y, guchar *pixel);
  132. static void             pixel_fetcher_destroy(pixel_fetcher_t *pf);
  133.  
  134. static void build_preview_source_image(void);
  135.  
  136. static gint kaleidoscope_dialog(void);
  137. static void dialog_update_preview(void);
  138. static void dialog_create_value(char *title, GtkTable *table, int row, gdouble *value,
  139.                                 double left, double right, double step);
  140. static void dialog_scale_update(GtkAdjustment *adjustment, gdouble *value);
  141. static void dialog_entry_update(GtkWidget *widget, gdouble *value);
  142. static void dialog_create_int_value(char *title, GtkTable *table, int row, gint *value,
  143.                                     gint left, gint right, gint step);
  144. static void dialog_int_scale_update(GtkAdjustment *adjustment, gint *value);
  145. static void dialog_int_entry_update(GtkWidget *widget, gint *value);
  146.  
  147. static void dialog_create_toggle(char *title, GtkTable *table, int row, gint *value);
  148. static void dialog_toggle_update(GtkWidget *widget, gint *value);
  149.  
  150. static void dialog_close_callback(GtkWidget *widget, gpointer data);
  151. static void dialog_ok_callback(GtkWidget *widget, gpointer data);
  152. static void dialog_cancel_callback(GtkWidget *widget, gpointer data);
  153.  
  154.  
  155. /***** Variables *****/
  156.  
  157. GimpPlugInInfo PLUG_IN_INFO = {
  158.   NULL,   /* init_proc */
  159.   NULL,   /* quit_proc */
  160.   query,  /* query_proc */
  161.   run     /* run_proc */
  162. };
  163.  
  164. static kaleidoscope_vals_t wpvals = {
  165.   0.0,  /* angle1 */
  166.   0.0,  /* angle2 */
  167.   6,    /* nsegs */
  168.   0.0,  /* x center */
  169.   0.0,  /* y center */
  170.   0.0,  /* x offset */
  171.   0.0,   /* y offset */
  172.   0                                     /* border handling */
  173. }; /* wpvals */
  174.  
  175. static kaleidoscope_interface_t wpint = {
  176.   NULL,  /* preview */
  177.   NULL,  /* check_row_0 */
  178.   NULL,  /* check_row_1 */
  179.   NULL,  /* image */
  180.   NULL,  /* dimage */
  181.   FALSE  /* run */
  182. }; /* wpint */
  183.  
  184. static GimpDrawable *drawable;
  185.  
  186. static gint img_width, img_height, img_bpp, img_has_alpha;
  187. static gint sel_x1, sel_y1, sel_x2, sel_y2;
  188. static gint sel_width, sel_height;
  189. static gint preview_width, preview_height;
  190.  
  191. static double scale_x, scale_y;
  192. static double radius;
  193.  
  194.  
  195. /***** Functions *****/
  196.  
  197. /*****/
  198.  
  199.  
  200. /*****/
  201.  
  202. static void
  203. query(void)
  204. {
  205.   static GimpParamDef args[] = {
  206.     { GIMP_PDB_INT32,    "run_mode",  "Interactive, non-interactive" },
  207.     { GIMP_PDB_IMAGE,    "image",     "Input image" },
  208.     { GIMP_PDB_DRAWABLE, "drawable",  N_("Input drawable") },
  209.     { GIMP_PDB_FLOAT,    "angle1",    N_("Angle of leading edge of viewing slice") },
  210.     { GIMP_PDB_FLOAT,    "angle2",    N_("Rollback angle") },
  211.     { GIMP_PDB_INT32,    "nsegs",     N_("Number of segments") },
  212.     { GIMP_PDB_INT32,    "border",    N_("Fill (0) or wrap (1) on edge") }
  213.    
  214.   }; /* args */
  215.  
  216.   static GimpParamDef *return_vals  = NULL;
  217.   static int        nargs        = sizeof(args) / sizeof(args[0]);
  218.   static int        nreturn_vals = 0;
  219.  
  220.   gimp_install_procedure(PLUG_IN_NAME,
  221.                          _("Simulate looking at an image thru a kaleidoscope"),
  222.                          _("Simulate looking at an image thru a kaleidoscope"),
  223.                          "Kelly Martin",
  224.                          "Kelly Martin",
  225.                          "1999-2002",
  226.                          "<Image>/Filters/Distorts/Kaleidoscope",
  227.                          "RGB*, GRAY*",
  228.                          GIMP_PLUGIN,
  229.                          nargs,
  230.                          nreturn_vals,
  231.                          args,
  232.                          return_vals);
  233. } /* query */
  234.  
  235.  
  236. /*****/
  237.  
  238. static void
  239. run (const gchar    *name,
  240.      gint      nparams,
  241.      const GimpParam  *param,
  242.      gint     *nreturn_vals,
  243.      GimpParam **return_vals)
  244. {
  245.   static GimpParam values[1];
  246.  
  247.   GimpRunMode run_mode;
  248.   GimpPDBStatusType status;
  249.   double       xhsiz, yhsiz;
  250.   int          pwidth, pheight;
  251.  
  252.   status   = GIMP_PDB_SUCCESS;
  253.   run_mode = param[0].data.d_int32;
  254.  
  255.   values[0].type          = GIMP_PDB_STATUS;
  256.   values[0].data.d_status = status;
  257.  
  258.   *nreturn_vals = 1;
  259.   *return_vals  = values;
  260.  
  261.   /* Get the active drawable info */
  262.  
  263.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  264.  
  265.   img_width     = gimp_drawable_width(drawable->drawable_id);
  266.   img_height    = gimp_drawable_height(drawable->drawable_id);
  267.   img_bpp       = gimp_drawable_bpp(drawable->drawable_id);
  268.   img_has_alpha = gimp_drawable_has_alpha(drawable->drawable_id);
  269.  
  270.   gimp_drawable_mask_bounds(drawable->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  271.  
  272.   /* Calculate scaling parameters */
  273.  
  274.   sel_width  = sel_x2 - sel_x1;
  275.   sel_height = sel_y2 - sel_y1;
  276.  
  277.   xhsiz = (double) (sel_width - 1) / 2.0;
  278.   yhsiz = (double) (sel_height - 1) / 2.0;
  279.  
  280.   if (xhsiz < yhsiz) {
  281.     scale_x = yhsiz / xhsiz;
  282.     scale_y = 1.0;
  283.   } else if (xhsiz > yhsiz) {
  284.     scale_x = 1.0;
  285.     scale_y = xhsiz / yhsiz;
  286.   } else {
  287.     scale_x = 1.0;
  288.     scale_y = 1.0;
  289.   } /* else */
  290.  
  291.   radius = MAX(xhsiz, yhsiz);
  292.  
  293.   wpvals.cen_x = sel_width  / 2 + sel_x1;
  294.   wpvals.cen_y = sel_height / 2 + sel_y1;
  295.  
  296.   /* Calculate preview size */
  297.  
  298.   if (sel_width > sel_height) {
  299.     pwidth  = MIN(sel_width, PREVIEW_SIZE);
  300.     pheight = sel_height * pwidth / sel_width;
  301.   } else {
  302.     pheight = MIN(sel_height, PREVIEW_SIZE);
  303.     pwidth  = sel_width * pheight / sel_height;
  304.   } /* else */
  305.  
  306.   preview_width  = MAX(pwidth, 2); /* Min size is 2 */
  307.   preview_height = MAX(pheight, 2);
  308.  
  309.   /* See how we will run */
  310.  
  311.   /* if debugging, pause to allow attachment of gdb */
  312.   /*getch();*/
  313.   switch (run_mode) {
  314.   case GIMP_RUN_INTERACTIVE:
  315.     /* Possibly retrieve data */
  316.  
  317.     gimp_get_data(name, &wpvals);
  318.  
  319.     /* Get information from the dialog */
  320.  
  321.     if (!kaleidoscope_dialog())
  322.       return;
  323.  
  324.     break;
  325.  
  326.   case GIMP_RUN_NONINTERACTIVE:
  327.     /* Make sure all the arguments are present */
  328.      
  329.     if (nparams != 11)
  330.       status = GIMP_PDB_CALLING_ERROR;
  331.      
  332.     if (status == GIMP_PDB_SUCCESS) {
  333.       wpvals.angle1 = param[3].data.d_float;
  334.       wpvals.angle2 = param[4].data.d_float;
  335.       wpvals.nsegs  = param[5].data.d_int32;
  336.       wpvals.cen_x  = param[6].data.d_float;
  337.       wpvals.cen_y  = param[7].data.d_float;
  338.       wpvals.off_x  = param[8].data.d_float;
  339.       wpvals.off_y  = param[9].data.d_float;
  340.       wpvals.border = param[10].data.d_int32;
  341.     } /* if */
  342.      
  343.     break;
  344.      
  345.   case GIMP_RUN_WITH_LAST_VALS:
  346.     /* Possibly retrieve data */
  347.  
  348.     gimp_get_data(PLUG_IN_NAME, &wpvals);
  349.     break;
  350.  
  351.   default:
  352.     break;
  353.   } /* switch */
  354.  
  355.   /* Distort the image */
  356.  
  357.   if ((status == GIMP_PDB_SUCCESS) &&
  358.       (gimp_drawable_is_rgb(drawable->drawable_id) ||
  359.        gimp_drawable_is_gray(drawable->drawable_id))) {
  360.     /* Set the tile cache size */
  361.  
  362.     gimp_tile_cache_ntiles(2 * (drawable->width + gimp_tile_width() - 1) / gimp_tile_width());
  363.  
  364.     /* Run! */
  365.  
  366.     kaleidoscope();
  367.  
  368.     /* If run mode is interactive, flush displays */
  369.  
  370.     if (run_mode != GIMP_RUN_NONINTERACTIVE)
  371.       gimp_displays_flush();
  372.  
  373.     /* Store data */
  374.  
  375.     if (run_mode == GIMP_RUN_INTERACTIVE)
  376.       gimp_set_data(PLUG_IN_NAME, &wpvals, sizeof(kaleidoscope_vals_t));
  377.   } else if (status == GIMP_PDB_SUCCESS)
  378.     status = GIMP_PDB_EXECUTION_ERROR;
  379.  
  380.   values[0].data.d_status = status;
  381.  
  382.   gimp_drawable_detach(drawable);
  383. } /* run */
  384.  
  385.  
  386. /*****/
  387.  
  388. static void
  389. kaleidoscope(void)
  390. {
  391.   GimpPixelRgn        dest_rgn;
  392.   gint             progress, max_progress;
  393.   guchar          *top_row, *bot_row;
  394.   guchar          *top_p, *bot_p;
  395.   gint             row, col;
  396.   guchar           pixel[4][4];
  397.   guchar           values[4];
  398.   double           cx, cy;
  399.   double           angle1, angle2;
  400.   int              ix, iy;
  401.   int              i;
  402.   GimpRGB          bg_temp;
  403.   guchar           bg_color[4];
  404.   pixel_fetcher_t *pft;
  405.  
  406.   /* Initialize rows */
  407.  
  408.   top_row = g_malloc(img_bpp * sel_width);
  409.   bot_row = g_malloc(img_bpp * sel_width);
  410.  
  411.   /* Initialize pixel region */
  412.  
  413.   gimp_pixel_rgn_init(&dest_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
  414.  
  415.   pft = pixel_fetcher_new(drawable, wpvals.border == BORDER_WRAP);
  416.  
  417.   gimp_palette_get_background(&bg_temp);
  418.   bg_color[0] = (guchar)(bg_temp.r * 255);
  419.   bg_color[1] = (guchar)(bg_temp.g * 255);
  420.   bg_color[2] = (guchar)(bg_temp.b * 255);
  421.   bg_color[3] = (guchar)(bg_temp.a * 255);
  422.  
  423.  
  424.   pixel_fetcher_set_bg_color(pft,
  425.                              bg_color[0],
  426.                              bg_color[1],
  427.                              bg_color[2],
  428.                              (img_has_alpha ? 0 : 255));
  429.  
  430.   progress     = 0;
  431.   max_progress = sel_width * sel_height;
  432.  
  433.   gimp_progress_init(_("Kaleidoscoping..."));
  434.  
  435.   angle1   = wpvals.angle1 * G_PI / 180;
  436.   angle2   = wpvals.angle2 * G_PI / 180;
  437.  
  438.   for (row = sel_y1; row < (sel_y1 + sel_y2); row++) {
  439.     top_p = top_row;
  440.     bot_p = bot_row + img_bpp * (sel_width - 1);
  441.  
  442.     for (col = sel_x1; col < sel_x2; col++) {
  443.       if (calc_undistorted_coords(col, row, angle1, angle2,
  444.                                   wpvals.nsegs,
  445.                                   wpvals.cen_x, wpvals.cen_y,
  446.                                   wpvals.off_x, wpvals.off_y,
  447.                                   &cx, &cy)) {
  448.         /* We are inside the distortion area */
  449.  
  450.         /* Top */
  451.  
  452.         if (cx >= 0.0)
  453.           ix = (int) cx;
  454.         else
  455.           ix = -((int) -cx + 1);
  456.  
  457.         if (cy >= 0.0)
  458.           iy = (int) cy;
  459.         else
  460.           iy = -((int) -cy + 1);
  461.  
  462.         pixel_fetcher_get_pixel(pft, ix,     iy,     pixel[0]);
  463.         pixel_fetcher_get_pixel(pft, ix + 1, iy,     pixel[1]);
  464.         pixel_fetcher_get_pixel(pft, ix,     iy + 1, pixel[2]);
  465.         pixel_fetcher_get_pixel(pft, ix + 1, iy + 1, pixel[3]);
  466.  
  467.         for (i = 0; i < img_bpp; i++) {
  468.           values[0] = pixel[0][i];
  469.           values[1] = pixel[1][i];
  470.           values[2] = pixel[2][i];
  471.           values[3] = pixel[3][i];
  472.  
  473.           *top_p++ = bilinear(cx, cy, values);
  474.         } /* for */
  475.  
  476.       } else {
  477.         /* We are outside the distortion area; just copy the source pixels */
  478.  
  479.         /* Top */
  480.  
  481.         pixel_fetcher_get_pixel(pft, col, row, pixel[0]);
  482.  
  483.         for (i = 0; i < img_bpp; i++)
  484.           *top_p++ = pixel[0][i];
  485.  
  486.       } /* else */
  487.     } /* for */
  488.  
  489.     /* Paint rows to image */
  490.  
  491.     gimp_pixel_rgn_set_row(&dest_rgn, top_row, sel_x1, row, sel_width);
  492.  
  493.     /* Update progress */
  494.  
  495.     progress += sel_width;
  496.     gimp_progress_update((double) progress / max_progress);
  497.   } /* for */
  498.  
  499.   pixel_fetcher_destroy(pft);
  500.  
  501.   g_free(top_row);
  502.  
  503.   gimp_drawable_flush(drawable);
  504.   gimp_drawable_merge_shadow(drawable->drawable_id, TRUE);
  505.   gimp_drawable_update(drawable->drawable_id, sel_x1, sel_y1, sel_width, sel_height);
  506. } /* kaleidoscope */
  507.  
  508.  
  509. /*****/
  510.  
  511. static int
  512. calc_undistorted_coords(double wx, double wy,
  513.                         double angle1, double angle2, int nsegs,
  514.                         double cen_x, double cen_y,
  515.                         double off_x, double off_y,
  516.                         double *x, double *y)
  517. {
  518.   double dx, dy;
  519.   double r, ang;
  520.  
  521.   double awidth = G_PI/nsegs;
  522.   double mult;
  523.  
  524.   dx = wx - cen_x;
  525.   dy = wy - cen_y;
  526.  
  527.   r = sqrt(dx*dx+dy*dy);
  528.   if (r == 0.0) {
  529.     *x = wx + off_x;
  530.     *y = wy + off_y;
  531.     return TRUE;
  532.   }
  533.  
  534.   ang = atan2(dy,dx) - angle1 - angle2;
  535.   while (ang<0.0) ang = ang + 2*G_PI;
  536.  
  537.   mult = ceil(ang/awidth) - 1;
  538.   ang = ang - mult*awidth;
  539.   if (((int) mult) % 2 == 1) ang = awidth - ang;
  540.   ang = ang + angle1;
  541.  
  542.   *x = r*cos(ang) + off_x;
  543.   *y = r*sin(ang) + off_y;
  544.  
  545.   return TRUE;
  546. } /* calc_undistorted_coords */
  547.  
  548.  
  549. /*****/
  550.  
  551. static guchar
  552. bilinear(double x, double y, guchar *values)
  553. {
  554.   double m0, m1;
  555.  
  556.   x = fmod(x, 1.0);
  557.   y = fmod(y, 1.0);
  558.  
  559.   if (x < 0.0)
  560.     x += 1.0;
  561.  
  562.   if (y < 0.0)
  563.     y += 1.0;
  564.  
  565.   m0 = (double) values[0] + x * ((double) values[1] - values[0]);
  566.   m1 = (double) values[2] + x * ((double) values[3] - values[2]);
  567.  
  568.   return (guchar) (m0 + y * (m1 - m0));
  569. } /* bilinear */
  570.  
  571.  
  572. /*****/
  573.  
  574. static pixel_fetcher_t *
  575. pixel_fetcher_new(GimpDrawable *drawable, gint wrap)
  576. {
  577.   pixel_fetcher_t *pf;
  578.  
  579.   pf = g_malloc(sizeof(pixel_fetcher_t));
  580.  
  581.   pf->col           = -1;
  582.   pf->row           = -1;
  583.   pf->img_width     = gimp_drawable_width(drawable->drawable_id);
  584.   pf->img_height    = gimp_drawable_height(drawable->drawable_id);
  585.   pf->img_bpp       = gimp_drawable_bpp(drawable->drawable_id);
  586.   pf->img_has_alpha = gimp_drawable_has_alpha(drawable->drawable_id);
  587.   pf->tile_width    = gimp_tile_width();
  588.   pf->tile_height   = gimp_tile_height();
  589.   pf->bg_color[0]   = 0;
  590.   pf->bg_color[1]   = 0;
  591.   pf->bg_color[2]   = 0;
  592.   pf->bg_color[3]   = 0;
  593.   pf->wrap          = wrap;
  594.  
  595.   pf->drawable    = drawable;
  596.   pf->tile        = NULL;
  597.  
  598.   return pf;
  599. } /* pixel_fetcher_new */
  600.  
  601.  
  602. /*****/
  603.  
  604. static void
  605. pixel_fetcher_set_bg_color(pixel_fetcher_t *pf, guchar r, guchar g, guchar b, guchar a)
  606. {
  607.   pf->bg_color[0] = r;
  608.   pf->bg_color[1] = g;
  609.   pf->bg_color[2] = b;
  610.  
  611.   if (pf->img_has_alpha)
  612.     pf->bg_color[pf->img_bpp - 1] = a;
  613. } /* pixel_fetcher_set_bg_color */
  614.  
  615.  
  616. /*****/
  617.  
  618. static void
  619. pixel_fetcher_get_pixel(pixel_fetcher_t *pf, int x, int y, guchar *pixel)
  620. {
  621.   gint    col, row;
  622.   gint    coloff, rowoff;
  623.   guchar *p;
  624.   int     i;
  625.  
  626.   if (!pf->wrap &&
  627.       ((x < sel_x1) || (x >= sel_x2) ||
  628.        (y < sel_y1) || (y >= sel_y2))) {
  629.     for (i = 0; i < pf->img_bpp; i++)
  630.       pixel[i] = pf->bg_color[i];
  631.  
  632.     return;
  633.   } /* if */
  634.  
  635.   while (x < sel_x1)  { x += sel_x2 - sel_x1; }
  636.   while (x >= sel_x2) { x -= sel_x2 - sel_x1; }
  637.   while (y < sel_y1)  { y += sel_y2 - sel_y1; }
  638.   while (y >= sel_y2) { y -= sel_y2 - sel_y1; }
  639.  
  640.   col    = x / pf->tile_width;
  641.   coloff = x % pf->tile_width;
  642.   row    = y / pf->tile_height;
  643.   rowoff = y % pf->tile_height;
  644.  
  645.   if ((col != pf->col) ||
  646.       (row != pf->row) ||
  647.       (pf->tile == NULL)) {
  648.     if (pf->tile != NULL)
  649.       gimp_tile_unref(pf->tile, FALSE);
  650.  
  651.     pf->tile = gimp_drawable_get_tile(pf->drawable, FALSE, row, col);
  652.     gimp_tile_ref(pf->tile);
  653.  
  654.     pf->col = col;
  655.     pf->row = row;
  656.   } /* if */
  657.  
  658.   p = pf->tile->data + pf->img_bpp * (pf->tile->ewidth * rowoff + coloff);
  659.  
  660.   for (i = pf->img_bpp; i; i--)
  661.     *pixel++ = *p++;
  662. } /* pixel_fetcher_get_pixel */
  663.  
  664.  
  665. /*****/
  666.  
  667. static void
  668. pixel_fetcher_destroy(pixel_fetcher_t *pf)
  669. {
  670.   if (pf->tile != NULL)
  671.     gimp_tile_unref(pf->tile, FALSE);
  672.  
  673.   g_free(pf);
  674. } /* pixel_fetcher_destroy */
  675.  
  676.  
  677. /*****/
  678.  
  679. static void
  680. build_preview_source_image(void)
  681. {
  682.   double           left, right, bottom, top;
  683.   double           px, py;
  684.   double           dx, dy;
  685.   int              x, y;
  686.   guchar          *p;
  687.   guchar           pixel[4];
  688.   pixel_fetcher_t *pf;
  689.  
  690.   wpint.check_row_0 = g_malloc(preview_width * sizeof(guchar));
  691.   wpint.check_row_1 = g_malloc(preview_width * sizeof(guchar));
  692.   wpint.image       = g_malloc(preview_width * preview_height * 4 * sizeof(guchar));
  693.   wpint.dimage      = g_malloc(preview_width * preview_height * 3 * sizeof(guchar));
  694.  
  695.   left   = sel_x1;
  696.   right  = sel_x2 - 1;
  697.   bottom = sel_y2 - 1;
  698.   top    = sel_y1;
  699.  
  700.   dx = (right - left) / (preview_width - 1);
  701.   dy = (bottom - top) / (preview_height - 1);
  702.  
  703.   py = top;
  704.  
  705.   pf = pixel_fetcher_new(drawable, wpvals.border == BORDER_WRAP);
  706.  
  707.   p = wpint.image;
  708.  
  709.   for (y = 0; y < preview_height; y++) {
  710.     px = left;
  711.  
  712.     for (x = 0; x < preview_width; x++) {
  713.       /* Checks */
  714.  
  715.       if ((x / CHECK_SIZE) & 1) {
  716.         wpint.check_row_0[x] = CHECK_DARK;
  717.         wpint.check_row_1[x] = CHECK_LIGHT;
  718.       } else {
  719.         wpint.check_row_0[x] = CHECK_LIGHT;
  720.         wpint.check_row_1[x] = CHECK_DARK;
  721.       } /* else */
  722.  
  723.       /* Thumbnail image */
  724.  
  725.       pixel_fetcher_get_pixel(pf, (int) px, (int) py, pixel);
  726.  
  727.       if (img_bpp < 3) {
  728.         if (img_has_alpha)
  729.           pixel[3] = pixel[1];
  730.         else
  731.           pixel[3] = 255;
  732.  
  733.         pixel[1] = pixel[0];
  734.         pixel[2] = pixel[0];
  735.       } else
  736.         if (!img_has_alpha)
  737.           pixel[3] = 255;
  738.  
  739.       *p++ = pixel[0];
  740.       *p++ = pixel[1];
  741.       *p++ = pixel[2];
  742.       *p++ = pixel[3];
  743.  
  744.       px += dx;
  745.     } /* for */
  746.  
  747.     py += dy;
  748.   } /* for */
  749.  
  750.   pixel_fetcher_destroy(pf);
  751. } /* build_preview_source_image */
  752.  
  753.  
  754. /*****/
  755.  
  756. static gint
  757. kaleidoscope_dialog(void)
  758. {
  759.   GtkWidget  *dialog;
  760.   GtkWidget  *top_table;
  761.   GtkWidget  *frame;
  762.   GtkWidget  *table;
  763.   GtkWidget  *button;
  764.   gint        argc;
  765.   gchar     **argv;
  766.  
  767.   argc    = 1;
  768.   argv    = g_new(gchar *, 1);
  769.   argv[0] = g_strdup("kaleidoscope");
  770.  
  771.   gtk_init(&argc, &argv);
  772.   gtk_rc_parse (gimp_gtkrc ());
  773.  
  774.   gdk_set_use_xshm(gimp_use_xshm());
  775.  
  776.   gtk_preview_set_gamma(gimp_gamma());
  777.   gtk_preview_set_install_cmap(gimp_install_cmap());
  778.  
  779.   gtk_widget_set_default_visual(gtk_preview_get_visual());
  780.   gtk_widget_set_default_colormap(gtk_preview_get_cmap());
  781.  
  782.   build_preview_source_image();
  783.  
  784.   dialog = gtk_dialog_new();
  785.   gtk_window_set_title(GTK_WINDOW(dialog), _("Kaleidoscope"));
  786.   gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
  787.   gtk_container_border_width(GTK_CONTAINER(dialog), 0);
  788.   gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
  789.                      (GtkSignalFunc) dialog_close_callback,
  790.                      NULL);
  791.  
  792.   top_table = gtk_table_new(2, 3, FALSE);
  793.   gtk_container_border_width(GTK_CONTAINER(top_table), 6);
  794.   gtk_table_set_row_spacings(GTK_TABLE(top_table), 4);
  795.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), top_table, FALSE, FALSE, 0);
  796.   gtk_widget_show(top_table);
  797.  
  798.   /* Preview */
  799.  
  800.   frame = gtk_frame_new(NULL);
  801.   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
  802.   gtk_table_attach(GTK_TABLE(top_table), frame, 1, 2, 0, 1, 0, 0, 0, 0);
  803.   gtk_widget_show(frame);
  804.  
  805.   wpint.preview = gtk_preview_new(GTK_PREVIEW_COLOR);
  806.   gtk_preview_size(GTK_PREVIEW(wpint.preview), preview_width, preview_height);
  807.   gtk_container_add(GTK_CONTAINER(frame), wpint.preview);
  808.   gtk_widget_show(wpint.preview);
  809.  
  810.   /* Controls */
  811.  
  812.   table = gtk_table_new(8, 3, FALSE);
  813.   gtk_container_border_width(GTK_CONTAINER(table), 0);
  814.   gtk_table_attach(GTK_TABLE(top_table), table, 0, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 0, 0);
  815.   gtk_widget_show(table);
  816.  
  817.   dialog_create_value(_("Angle 1"), GTK_TABLE(table), 0, &wpvals.angle1, -360.0, 360.0, 1.0);
  818.        
  819.   dialog_create_value(_("Angle 2"), GTK_TABLE(table), 1, &wpvals.angle2, -360.0, 360.0, 1.0);
  820.        
  821.   dialog_create_int_value(_("Number of segments"), GTK_TABLE(table), 2, &wpvals.nsegs, 1, 16, 1);
  822.  
  823.   dialog_create_value(_("X center"), GTK_TABLE(table), 3, &wpvals.cen_x, sel_x1, sel_x2, 1.0);
  824.        
  825.   dialog_create_value(_("Y center"), GTK_TABLE(table), 4, &wpvals.cen_y, sel_y1, sel_y2, 1.0);
  826.  
  827.   dialog_create_value(_("X offset"), GTK_TABLE(table), 5, &wpvals.off_x, -img_width, img_width, 1.0);
  828.        
  829.   dialog_create_value(_("Y offset"), GTK_TABLE(table), 6, &wpvals.off_y, -img_height, img_height, 1.0);
  830.  
  831.   dialog_create_toggle(_("Wrap?"), GTK_TABLE(table), 7, &wpvals.border);
  832.        
  833.   /* Buttons */
  834.  
  835.   gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
  836.  
  837.   button = gtk_button_new_with_label(_("OK"));
  838.   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  839.   gtk_signal_connect(GTK_OBJECT(button), "clicked",
  840.                      (GtkSignalFunc) dialog_ok_callback,
  841.                      dialog);
  842.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  843.   gtk_widget_grab_default(button);
  844.   gtk_widget_show(button);
  845.  
  846.   button = gtk_button_new_with_label(_("Cancel"));
  847.   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  848.   gtk_signal_connect(GTK_OBJECT(button), "clicked",
  849.                      (GtkSignalFunc) dialog_cancel_callback,
  850.                      dialog);
  851.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  852.   gtk_widget_show(button);
  853.  
  854.   /* Done */
  855.  
  856.   gtk_widget_show(dialog);
  857.   dialog_update_preview();
  858.  
  859.   gtk_main();
  860.   gdk_flush();
  861.  
  862.   g_free(wpint.check_row_0);
  863.   g_free(wpint.check_row_1);
  864.   g_free(wpint.image);
  865.   g_free(wpint.dimage);
  866.  
  867.   return wpint.run;
  868. } /* kaleidoscope_dialog */
  869.  
  870.  
  871. /*****/
  872.  
  873. static void
  874. dialog_update_preview(void)
  875. {
  876.   double  left, right, bottom, top;
  877.   double  dx, dy;
  878.   double  px, py;
  879.   double  cx, cy;
  880.   int     ix, iy;
  881.   int     x, y;
  882.   double  scale_x, scale_y;
  883.   guchar *p_ul, *i, *p;
  884.   guchar *check_ul;
  885.   int     check;
  886.   guchar  outside[4];
  887.   GimpRGB bgcolor;
  888.   double  angle1, angle2;
  889.  
  890.   gimp_palette_get_background(&bgcolor);
  891.   outside[0] = (guchar)(bgcolor.r * 255);
  892.   outside[1] = (guchar)(bgcolor.g * 255);
  893.   outside[2] = (guchar)(bgcolor.b * 255);
  894.   outside[3] = (img_has_alpha ? 0 : 255);
  895.  
  896.   if (img_bpp < 3) {
  897.     outside[1] = outside[0];
  898.     outside[2] = outside[0];
  899.   } /* if */
  900.  
  901.   left   = sel_x1;
  902.   right  = sel_x2 - 1;
  903.   bottom = sel_y2 - 1;
  904.   top    = sel_y1;
  905.  
  906.   dx = (right - left) / (preview_width - 1);
  907.   dy = (bottom - top) / (preview_height - 1);
  908.  
  909.   scale_x = (double) preview_width / (right - left + 1);
  910.   scale_y = (double) preview_height / (bottom - top + 1);
  911.  
  912.   angle1   = wpvals.angle1 * G_PI / 180;
  913.   angle2   = wpvals.angle2 * G_PI / 180;
  914.  
  915.   py = top;
  916.  
  917.   p_ul = wpint.dimage;
  918.  
  919.   for (y = 0; y < preview_height; y++) {
  920.     px = left;
  921.  
  922.     if ((y / CHECK_SIZE) & 1)
  923.       check_ul = wpint.check_row_0;
  924.     else
  925.       check_ul = wpint.check_row_1;
  926.  
  927.     for (x = 0; x < preview_width; x++) {
  928.       calc_undistorted_coords(px, py, angle1, angle2, wpvals.nsegs,
  929.                               wpvals.cen_x, wpvals.cen_y,
  930.                               wpvals.off_x, wpvals.off_y,
  931.                               &cx, &cy);
  932.  
  933.       cx = (cx - left) * scale_x;
  934.       cy = (cy - top) * scale_y;
  935.  
  936.       ix = (int) (cx + 0.5);
  937.       iy = (int) (cy + 0.5);
  938.  
  939.       check = check_ul[x];
  940.      
  941.       if (wpvals.border == BORDER_WRAP) {
  942.         while (ix < 0) ix += preview_width;
  943.         while (ix >= preview_width) ix -= preview_width;
  944.         while (iy < 0) iy += preview_height;
  945.         while (iy >= preview_height) iy -= preview_height;
  946.       }
  947.  
  948.       if ((ix >= 0) && (ix < preview_width) &&
  949.           (iy >= 0) && (iy < preview_height))
  950.         i = wpint.image + 4 * (preview_width * iy + ix);
  951.       else
  952.         i = outside;
  953.  
  954.       p_ul[0] = check + ((i[0] - check) * i[3]) / 255;
  955.       p_ul[1] = check + ((i[1] - check) * i[3]) / 255;
  956.       p_ul[2] = check + ((i[2] - check) * i[3]) / 255;
  957.  
  958.       p_ul += 3;
  959.  
  960.       px += dx;
  961.     } /* for */
  962.  
  963.     py += dy;
  964.   } /* for */
  965.  
  966.   p = wpint.dimage;
  967.  
  968.   for (y = 0; y < preview_height; y++) {
  969.     gtk_preview_draw_row(GTK_PREVIEW(wpint.preview), p, 0, y, preview_width);
  970.  
  971.     p += preview_width * 3;
  972.   } /* for */
  973.  
  974.   gtk_widget_draw(wpint.preview, NULL);
  975.   gdk_flush();
  976. } /* dialog_update_preview */
  977.  
  978.  
  979. /*****/
  980.  
  981. static void
  982. dialog_create_value(char *title, GtkTable *table, int row, gdouble *value,
  983.                     double left, double right, double step)
  984. {
  985.   GtkWidget *label;
  986.   GtkWidget *scale;
  987.   GtkWidget *entry;
  988.   GtkObject *scale_data;
  989.   char       buf[256];
  990.  
  991.   label = gtk_label_new(title);
  992.   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  993.   gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  994.   gtk_widget_show(label);
  995.  
  996.   scale_data = gtk_adjustment_new(*value, left, right,
  997.                                   step,
  998.                                   step,
  999.                                   0.0);
  1000.  
  1001.   gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
  1002.                      (GtkSignalFunc) dialog_scale_update,
  1003.                      value);
  1004.  
  1005.   scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
  1006.   gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
  1007.   gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  1008.   gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
  1009.   gtk_scale_set_digits(GTK_SCALE(scale), 3);
  1010.   gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
  1011.   gtk_widget_show(scale);
  1012.  
  1013.   entry = gtk_entry_new();
  1014.   gtk_object_set_user_data(GTK_OBJECT(entry), scale_data);
  1015.   gtk_object_set_user_data(scale_data, entry);
  1016.   gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
  1017.   sprintf(buf, "%0.3f", *value);
  1018.   gtk_entry_set_text(GTK_ENTRY(entry), buf);
  1019.   gtk_signal_connect(GTK_OBJECT(entry), "changed",
  1020.                      (GtkSignalFunc) dialog_entry_update,
  1021.                      value);
  1022.   gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  1023.   gtk_widget_show(entry);
  1024. } /* dialog_create_value */
  1025.  
  1026.  
  1027. /*****/
  1028.  
  1029. static void
  1030. dialog_scale_update(GtkAdjustment *adjustment, gdouble *value)
  1031. {
  1032.   GtkWidget *entry;
  1033.   char       buf[256];
  1034.  
  1035.   if (*value != adjustment->value) {
  1036.     *value = adjustment->value;
  1037.  
  1038.     entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
  1039.     sprintf(buf, "%0.3f", *value);
  1040.  
  1041.     gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value);
  1042.     gtk_entry_set_text(GTK_ENTRY(entry), buf);
  1043.     gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value);
  1044.  
  1045.     dialog_update_preview();
  1046.   } /* if */
  1047. } /* dialog_scale_update */
  1048.  
  1049.  
  1050. /*****/
  1051.  
  1052. static void
  1053. dialog_entry_update(GtkWidget *widget, gdouble *value)
  1054. {
  1055.   GtkAdjustment *adjustment;
  1056.   gdouble        new_value;
  1057.  
  1058.   new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
  1059.  
  1060.   if (*value != new_value) {
  1061.     adjustment = gtk_object_get_user_data(GTK_OBJECT(widget));
  1062.  
  1063.     if ((new_value >= adjustment->lower) &&
  1064.         (new_value <= adjustment->upper)) {
  1065.       *value            = new_value;
  1066.       adjustment->value = new_value;
  1067.  
  1068.       gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed");
  1069.  
  1070.       dialog_update_preview();
  1071.     } /* if */
  1072.   } /* if */
  1073. } /* dialog_entry_update */
  1074.  
  1075. static void
  1076. dialog_create_int_value(char *title, GtkTable *table, int row, gint *value,
  1077.                         int left, int right, int step)
  1078. {
  1079.   GtkWidget *label;
  1080.   GtkWidget *scale;
  1081.   GtkWidget *entry;
  1082.   GtkObject *scale_data;
  1083.   char       buf[256];
  1084.  
  1085.   label = gtk_label_new(title);
  1086.   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  1087.   gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  1088.   gtk_widget_show(label);
  1089.  
  1090.   scale_data = gtk_adjustment_new(1.0 * (*value),
  1091.                                   1.0*left,
  1092.                                   1.0*right,
  1093.                                   1.0*step,
  1094.                                   1.0*step,
  1095.                                   0.0);
  1096.  
  1097.   gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
  1098.                      (GtkSignalFunc) dialog_int_scale_update,
  1099.                      value);
  1100.  
  1101.   scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
  1102.   gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
  1103.   gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  1104.   gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
  1105.   gtk_scale_set_digits(GTK_SCALE(scale), 3);
  1106.   gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
  1107.   gtk_widget_show(scale);
  1108.  
  1109.   entry = gtk_entry_new();
  1110.   gtk_object_set_user_data(GTK_OBJECT(entry), scale_data);
  1111.   gtk_object_set_user_data(scale_data, entry);
  1112.   gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
  1113.   sprintf(buf, "%d", *value);
  1114.   gtk_entry_set_text(GTK_ENTRY(entry), buf);
  1115.   gtk_signal_connect(GTK_OBJECT(entry), "changed",
  1116.                      (GtkSignalFunc) dialog_int_entry_update,
  1117.                      value);
  1118.   gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  1119.   gtk_widget_show(entry);
  1120. } /* dialog_create_int_value */
  1121.  
  1122.  
  1123. /*****/
  1124.  
  1125. static void
  1126. dialog_int_scale_update(GtkAdjustment *adjustment, gint *value)
  1127. {
  1128.   GtkWidget *entry;
  1129.   char       buf[256];
  1130.  
  1131.   if (*value != (int) adjustment->value) {
  1132.     *value = (int) adjustment->value;
  1133.  
  1134.     entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
  1135.     sprintf(buf, "%d", *value);
  1136.  
  1137.     gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value);
  1138.     gtk_entry_set_text(GTK_ENTRY(entry), buf);
  1139.     gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value);
  1140.  
  1141.     dialog_update_preview();
  1142.   } /* if */
  1143. } /* dialog_scale_update */
  1144.  
  1145.  
  1146. /*****/
  1147.  
  1148. static void
  1149. dialog_int_entry_update(GtkWidget *widget, gint *value)
  1150. {
  1151.   GtkAdjustment *adjustment;
  1152.   gint           new_int_value;
  1153.  
  1154.   new_int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
  1155.  
  1156.   if (*value != new_int_value) {
  1157.     adjustment = gtk_object_get_user_data(GTK_OBJECT(widget));
  1158.  
  1159.     if ((new_int_value >= adjustment->lower) &&
  1160.         (new_int_value <= adjustment->upper)) {
  1161.       *value            = new_int_value;
  1162.       adjustment->value = 1.0*new_int_value;
  1163.  
  1164.       gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed");
  1165.  
  1166.       dialog_update_preview();
  1167.     } /* if */
  1168.   } /* if */
  1169. } /* dialog_entry_update */
  1170.  
  1171.  
  1172. /*****/
  1173.  
  1174. static void
  1175. dialog_create_toggle(char *title, GtkTable *table, int row, gint *value)
  1176. {
  1177.   GtkWidget *label;
  1178.   GtkWidget *toggle;
  1179.  
  1180.   label = gtk_label_new(title);
  1181.   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  1182.   gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  1183.   gtk_widget_show(label);
  1184.  
  1185.   toggle = gtk_toggle_button_new();
  1186.  
  1187.   gtk_signal_connect(GTK_OBJECT(toggle), "clicked",
  1188.                      (GtkSignalFunc) dialog_toggle_update,
  1189.                      value);
  1190.  
  1191.   gtk_table_attach(table, toggle, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  1192.   gtk_widget_show(toggle);
  1193.  
  1194. } /* dialog_create_value */
  1195.  
  1196.  
  1197. /*****/
  1198.  
  1199. static void
  1200. dialog_toggle_update(GtkWidget *widget, gint *value)
  1201. {
  1202.   gint           new_int_value;
  1203.  
  1204.   new_int_value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  1205.  
  1206.   if (*value != new_int_value) {
  1207.     *value = new_int_value;
  1208.     dialog_update_preview();
  1209.   }
  1210.  
  1211. } /* dialog_entry_update */
  1212.  
  1213.  
  1214.  
  1215. /*****/
  1216.  
  1217. static void
  1218. dialog_close_callback(GtkWidget *widget, gpointer data)
  1219. {
  1220.   gtk_main_quit();
  1221. } /* dialog_close_callback */
  1222.  
  1223.  
  1224. /*****/
  1225.  
  1226. static void
  1227. dialog_ok_callback(GtkWidget *widget, gpointer data)
  1228. {
  1229.   wpint.run = TRUE;
  1230.   gtk_widget_destroy(GTK_WIDGET(data));
  1231. } /* dialog_ok_callback */
  1232.  
  1233.  
  1234. /*****/
  1235.  
  1236. static void
  1237. dialog_cancel_callback(GtkWidget *widget, gpointer data)
  1238. {
  1239.   gtk_widget_destroy(GTK_WIDGET(data));
  1240. } /* dialog_cancel_callback */
  1241.  
  1242.  
  1243. MAIN()

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post