home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / gtm.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  20.3 KB  |  657 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * GTM plug-in --- GIMP Table Magic
  5.  * Allows images to be saved as HTML tables with different colored cells.
  6.  * It doesn't  have very much practical use other than being able to
  7.  * easily design a table by "painting" it in GIMP, or to make small HTML
  8.  * table images/icons.
  9.  *
  10.  * Copyright (C) 1997 Daniel Dunbar
  11.  * Email: ddunbar@diads.com
  12.  * WWW:   http://millennium.diads.com/gimp/
  13.  *
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27.  */
  28.  
  29. /* Version 1.0:
  30.  * Once I first found out that it was possible to have pixel level control
  31.  * of HTML tables I instantly realized that it would be possible, however
  32.  * pointless, to save an image as a, albeit huge, HTML table.
  33.  *
  34.  * One night when I was feeling in an adventourously stupid programming mood
  35.  * I decided to write a program to do it.
  36.  *
  37.  * At first I just wrote a really ugly hack to do it, which I then planned
  38.  * on using once just to see how it worked, and then posting a URL and 
  39.  * laughing about it on #gimp.  As it turns out, tigert thought it actually
  40.  * had potential to be a useful plugin, so I started adding features and
  41.  * and making a nice UI.
  42.  *
  43.  * It's still not very useful, but I did manage to significantly improve my
  44.  * C programming skills in the process, so it was worth it.
  45.  *
  46.  * If you happen to find it usefull I would appreciate any email about it.
  47.  *                                     - Daniel Dunbar
  48.  *                                       ddunbar@diads.com
  49.  */
  50.  
  51. #include "config.h"
  52.  
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <string.h>
  56.  
  57. #include <gtk/gtk.h>
  58.  
  59. #include <libgimp/gimp.h>
  60. #include <libgimp/gimpui.h>
  61.  
  62. #include "libgimp/stdplugins-intl.h"
  63.  
  64. #include "pixmaps/eek.xpm"
  65.  
  66.  
  67. /* Typedefs */
  68.  
  69. typedef struct
  70. {
  71.   gchar captiontxt[256];
  72.   gchar cellcontent[256];
  73.   gchar clwidth[256];
  74.   gchar clheight[256];
  75.   gint  fulldoc;
  76.   gint  caption;
  77.   gint  border;
  78.   gint  spantags;
  79.   gint  tdcomp;
  80.   gint  cellpadding;
  81.   gint  cellspacing;
  82. } GTMValues;
  83.  
  84. typedef struct
  85. {
  86.   gint run;
  87. } GTMInterface;
  88.  
  89. /* Variables */
  90.  
  91. static GTMInterface bint =
  92. {
  93.   FALSE  /* run */
  94. };
  95.  
  96. static GTMValues gtmvals =
  97. {
  98.   "Made with GIMP Table Magic",  /* caption text */
  99.   " ",  /* cellcontent text */
  100.   "",    /* cell width text */
  101.   "",    /* cell height text */
  102.   1,     /* fulldoc */
  103.   0,     /* caption */
  104.   2,     /* border */
  105.   0,     /* spantags */
  106.   0,     /* tdcomp */
  107.   4,     /* cellpadding */
  108.   0      /* cellspacing */
  109. };
  110.  
  111. /* Declare some local functions */
  112.  
  113. static void   query      (void);
  114. static void   run        (gchar   *name,
  115.                           gint     nparams,
  116.                           GimpParam  *param,
  117.                           gint    *nreturn_vals,
  118.                           GimpParam **return_vals);
  119.  
  120. static gint   save_image  (gchar     *filename,
  121.                GimpDrawable *drawable);
  122. static gint   save_dialog (gint32     image_ID);
  123.  
  124. static gint   color_comp               (guchar    *buffer,
  125.                     guchar    *buf2);
  126. static void   save_ok_callback         (GtkWidget *widget,
  127.                     gpointer   data);
  128. static void   gtm_caption_callback     (GtkWidget *widget,
  129.                     gpointer   data);
  130. static void   gtm_cellcontent_callback (GtkWidget *widget,
  131.                     gpointer   data);
  132. static void   gtm_clwidth_callback     (GtkWidget *widget,
  133.                     gpointer   data);
  134. static void   gtm_clheight_callback    (GtkWidget *widget,
  135.                     gpointer   data);
  136.  
  137. GimpPlugInInfo PLUG_IN_INFO =
  138. {
  139.   NULL,  /* init_proc  */
  140.   NULL,  /* quit_proc  */
  141.   query, /* query_proc */
  142.   run,   /* run_proc   */
  143. };
  144.  
  145.  
  146. MAIN ()
  147.  
  148. static void
  149. query (void)
  150. {
  151.   static GimpParamDef save_args[] =
  152.   {
  153.     { GIMP_PDB_INT32, "run_mode", "Interactive" },
  154.     { GIMP_PDB_IMAGE, "image", "Input image" },
  155.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  156.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  157.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }
  158.   };
  159.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  160.  
  161.   gimp_install_procedure ("file_GTM_save",
  162.                           "GIMP Table Magic",
  163.                           "Allows you to draw an HTML table in GIMP. See help for more info.",
  164.                           "Daniel Dunbar",
  165.                           "Daniel Dunbar",
  166.                           "1998",
  167.                           "<Save>/HTML",
  168.               "RGB*, GRAY*",
  169.                           GIMP_PLUGIN,
  170.                           nsave_args, 0,
  171.                           save_args, NULL);
  172.  
  173.   gimp_register_save_handler ("file_GTM_save",
  174.                   "html,htm",
  175.                   "");
  176. }
  177.  
  178. static void
  179. run (gchar   *name,
  180.      gint     nparams,
  181.      GimpParam  *param,
  182.      gint    *nreturn_vals,
  183.      GimpParam **return_vals)
  184. {
  185.   static GimpParam values[2];
  186.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  187.   GimpDrawable *drawable;
  188.  
  189.   INIT_I18N_UI();
  190.  
  191.   drawable = gimp_drawable_get (param[2].data.d_int32);
  192.  
  193.   *nreturn_vals = 1;
  194.   *return_vals  = values;
  195.   values[0].type          = GIMP_PDB_STATUS;
  196.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  197.  
  198.   gimp_get_data ("file_GTM_save", >mvals);
  199.  
  200.   if (save_dialog (param[1].data.d_int32))
  201.     {
  202.       if (save_image (param[3].data.d_string, drawable))
  203.     {
  204.       gimp_set_data ("file_GTM_save", >mvals, sizeof (GTMValues));
  205.     }
  206.       else
  207.     {
  208.       status = GIMP_PDB_EXECUTION_ERROR;
  209.     }
  210.     }
  211.   else
  212.     {
  213.       status = GIMP_PDB_CANCEL;
  214.     }
  215.  
  216.   values[0].data.d_status = status;
  217. }
  218.  
  219. static gint
  220. save_image (gchar     *filename,
  221.         GimpDrawable *drawable)
  222. {
  223.   int row,col, cols, rows, x, y;
  224.   int colcount, colspan, rowspan;
  225.   /* This works only in gcc - not allowed according */
  226.   /* to ANSI C */
  227.   /*int palloc[drawable->width][drawable->height];*/
  228.   int *palloc;
  229.   guchar *buffer, *buf2;
  230.   gchar *width, *height;
  231.   GimpPixelRgn pixel_rgn;
  232.   char *name;
  233.  
  234.   FILE *fp, *fopen();
  235.  
  236.   palloc = malloc(drawable->width * drawable->height * sizeof(int));
  237.  
  238.   fp = fopen(filename, "w");
  239.   if (gtmvals.fulldoc) {
  240.     fprintf (fp,"<HTML>\n<HEAD><TITLE>%s</TITLE></HEAD>\n<BODY>\n",filename);
  241.     fprintf (fp,"<H1>%s</H1>\n",filename);
  242.   }
  243.   fprintf (fp,"<TABLE BORDER=%d CELLPADDING=%d CELLSPACING=%d>\n",gtmvals.border,gtmvals.cellpadding,gtmvals.cellspacing);
  244.   if (gtmvals.caption)
  245.     fprintf (fp,"<CAPTION>%s</CAPTION>\n",gtmvals.captiontxt); 
  246.  
  247.   name = g_strdup_printf (_("Saving %s:"), filename);
  248.   gimp_progress_init (name);
  249.   g_free (name);
  250.  
  251.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
  252.  
  253.   cols = drawable->width;
  254.   rows = drawable->height;
  255.   buffer = g_new(guchar,drawable->bpp);
  256.   buf2 = g_new(guchar,drawable->bpp);
  257.  
  258.   width = malloc (2);
  259.   height = malloc (2);
  260.   sprintf(width," ");
  261.   sprintf(height," ");
  262.   if (strcmp (gtmvals.clwidth, "") != 0) {
  263.     width = malloc (strlen (gtmvals.clwidth) + 11);
  264.     sprintf(width," WIDTH=\"%s\"",gtmvals.clwidth);
  265.   }
  266.   if (strcmp (gtmvals.clheight, "") != 0) {
  267.     height = malloc (strlen (gtmvals.clheight) + 13);
  268.     sprintf(height," HEIGHT=\"%s\" ",gtmvals.clheight);
  269.   }  
  270.   
  271.   /* Initialize array to hold ROWSPAN and COLSPAN cell allocation table */
  272.  
  273.   for (row=0; row < rows; row++)
  274.     for (col=0; col < cols; col++)
  275.       palloc[drawable->width * row + col]=1;
  276.  
  277.   colspan=0;
  278.   rowspan=0;
  279.  
  280.   for (y = 0; y < rows; y++) {
  281.     fprintf (fp,"   <TR>\n");
  282.     for (x = 0; x < cols; x++) {
  283.       gimp_pixel_rgn_get_pixel(&pixel_rgn, buffer, x, y);
  284.  
  285.       /* Determine ROWSPAN and COLSPAN */
  286.  
  287.       if (gtmvals.spantags) { 
  288.     col=x;
  289.     row=y;
  290.     colcount=0;
  291.     colspan=0;
  292.     rowspan=0;
  293.     gimp_pixel_rgn_get_pixel(&pixel_rgn, buf2, col, row);
  294.     
  295.     while (color_comp(buffer,buf2) && palloc[drawable->width * row + col] == 1 && row < drawable->height) {
  296.       while (color_comp(buffer,buf2) && palloc[drawable->width * row + col] == 1 && col < drawable->width ) {
  297.         colcount++;
  298.         col++;
  299.         gimp_pixel_rgn_get_pixel(&pixel_rgn, buf2, col, row);
  300.       }
  301.       
  302.       if (colcount != 0) {
  303.         row++;
  304.         rowspan++;
  305.       }
  306.       
  307.       if (colcount < colspan || colspan == 0)
  308.         colspan=colcount;
  309.       
  310.       col=x;
  311.       colcount=0;
  312.       gimp_pixel_rgn_get_pixel(&pixel_rgn, buf2, col, row);
  313.     }
  314.     
  315.     if (colspan > 1 || rowspan > 1) {
  316.       for (row=0; row < rowspan; row++)
  317.         for (col=0; col < colspan; col++)
  318.           palloc[drawable->width * (row+y) + (col+x)]=0;
  319.       palloc[drawable->width * y + x]=2;
  320.     }
  321.       }
  322.  
  323.       if (palloc[drawable->width * y + x]==1)
  324.     fprintf (fp,"      <TD%s%sBGCOLOR=#%02x%02x%02x>",width,height,buffer[0],buffer[1],buffer[2]);
  325.  
  326.       if (palloc[drawable->width * y + x]==2)
  327.     fprintf (fp,"      <TD ROWSPAN=\"%d\" COLSPAN=\"%d\"%s%sBGCOLOR=#%02x%02x%02x>",rowspan,colspan,width,height,buffer[0],buffer[1],buffer[2]);
  328.  
  329.       if (palloc[drawable->width * y + x]!=0) {
  330.     if (gtmvals.tdcomp)
  331.       fprintf (fp,"%s</TD>\n",gtmvals.cellcontent);
  332.     else 
  333.       fprintf (fp,"\n      %s\n      </TD>\n",gtmvals.cellcontent);
  334.       }
  335.     }
  336.     fprintf (fp,"   </TR>\n");
  337.     gimp_progress_update ((double) y / (double) rows);
  338.   }
  339.  
  340.   if (gtmvals.fulldoc)
  341.     fprintf (fp,"</TABLE></BODY></HTML>\n");  
  342.   else fprintf (fp,"</TABLE>\n");
  343.   fclose(fp);
  344.   gimp_drawable_detach (drawable);
  345.   free(width);
  346.   free(height);
  347.  
  348.   free(palloc);
  349.  
  350.   return 1;
  351. }
  352.  
  353. static gint
  354. save_dialog (image_ID)
  355. {
  356.   GtkWidget *dlg;
  357.   GtkWidget *main_vbox;
  358.   GtkWidget *frame;
  359.   GtkWidget *vbox;
  360.   GtkWidget *table;
  361.   GtkWidget *spinbutton;
  362.   GtkObject *adj;
  363.   GtkWidget *entry;
  364.   GtkWidget *toggle;
  365.  
  366.   bint.run = FALSE;
  367.  
  368.   gimp_ui_init ("gtm", FALSE);
  369.  
  370.   dlg = gimp_dialog_new (_("GIMP Table Magic"), "gtm",
  371.              gimp_standard_help_func, "filters/gtm.html",
  372.              GTK_WIN_POS_MOUSE,
  373.              FALSE, TRUE, FALSE,
  374.  
  375.              _("OK"), save_ok_callback,
  376.              NULL, NULL, NULL, TRUE, FALSE,
  377.              _("Cancel"), gtk_widget_destroy,
  378.              NULL, 1, NULL, FALSE, TRUE,
  379.  
  380.              NULL);
  381.  
  382.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  383.                       GTK_SIGNAL_FUNC (gtk_main_quit),
  384.                       NULL);
  385.  
  386.   /* Initialize Tooltips */
  387.   gimp_help_init ();
  388.  
  389.   main_vbox = gtk_vbox_new (FALSE, 4);
  390.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  391.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox,
  392.               TRUE, TRUE, 0);
  393.  
  394.   if (gimp_image_width (image_ID) * gimp_image_height (image_ID) > 4096)
  395.     {
  396.       GtkWidget *eek;
  397.       GtkWidget *label;
  398.       GtkWidget *hbox;
  399.  
  400.       frame = gtk_frame_new (_("Warning"));
  401.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  402.       gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  403.  
  404.       hbox = gtk_hbox_new (FALSE, 4);
  405.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
  406.       gtk_container_add (GTK_CONTAINER (frame), hbox);
  407.       
  408.       eek = gimp_pixmap_new (eek_xpm);
  409.       gtk_box_pack_start (GTK_BOX (hbox), eek, FALSE, FALSE, 4);
  410.  
  411.       label = gtk_label_new (_("Are you crazy?\n\n"
  412.                    "You are about to create a huge\n"
  413.                    "HTML file which will most likely\n"
  414.                    "crash your browser."));
  415.       gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  416.  
  417.       gtk_widget_show_all (frame);
  418.     }
  419.  
  420.   /* HTML Page Options */
  421.   frame = gtk_frame_new (_("HTML Page Options"));
  422.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  423.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  424.  
  425.   vbox = gtk_vbox_new (FALSE, 2);
  426.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  427.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  428.   gtk_widget_show (vbox);
  429.  
  430.   toggle = gtk_check_button_new_with_label (_("Generate Full HTML Document"));
  431.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  432.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  433.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  434.               >mvals.fulldoc);
  435.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gtmvals.fulldoc);
  436.   gtk_widget_show (toggle);
  437.   gimp_help_set_help_data (toggle,
  438.                _("If checked GTM will output a full HTML document "
  439.                  "with <HTML>, <BODY>, etc. tags instead of just "
  440.                  "the table html."),
  441.                NULL);
  442.  
  443.   gtk_widget_show (main_vbox);
  444.   gtk_widget_show (frame);
  445.  
  446.   /* HTML Table Creation Options */
  447.   frame = gtk_frame_new (_("Table Creation Options"));
  448.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  449.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  450.  
  451.   table = gtk_table_new (4, 2, FALSE);
  452.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  453.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  454.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  455.   gtk_container_add (GTK_CONTAINER (frame), table);
  456.  
  457.   toggle = gtk_check_button_new_with_label (_("Use Cellspan"));
  458.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
  459.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  460.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  461.               >mvals.spantags);
  462.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gtmvals.spantags);
  463.   gtk_widget_show (toggle);
  464.   gimp_help_set_help_data (toggle,
  465.                _("If checked GTM will replace any rectangular "
  466.                  "sections of identically colored blocks with one "
  467.                  "large cell with ROWSPAN and COLSPAN values."),
  468.                NULL);
  469.  
  470.   toggle = gtk_check_button_new_with_label (_("Compress TD tags"));
  471.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 1, 2, GTK_FILL, 0, 0, 0);
  472.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  473.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  474.               >mvals.tdcomp);
  475.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gtmvals.tdcomp);
  476.   gtk_widget_show (toggle);
  477.   gimp_help_set_help_data (toggle,
  478.                _("Checking this tag will cause GTM to leave no "
  479.                  "whitespace between the TD tags and the "
  480.                  "cellcontent.  This is only necessary for pixel "
  481.                  "level positioning control."),
  482.                NULL);
  483.  
  484.   toggle = gtk_check_button_new_with_label (_("Caption"));
  485.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
  486.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  487.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  488.               >mvals.caption);
  489.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gtmvals.caption);
  490.   gtk_widget_show (toggle);
  491.   gimp_help_set_help_data (toggle,
  492.                _("Check if you would like to have the table "
  493.                  "captioned."),
  494.                NULL);
  495.  
  496.   entry = gtk_entry_new ();
  497.   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3,
  498.             GTK_FILL | GTK_EXPAND, 0, 0, 0);
  499.   gtk_widget_set_usize (entry, 200, 0);
  500.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  501.               GTK_SIGNAL_FUNC (gtm_caption_callback),
  502.               NULL);
  503.   gtk_entry_set_text (GTK_ENTRY (entry), gtmvals.captiontxt);
  504.   gtk_widget_show (entry);
  505.   gimp_help_set_help_data (entry, _("The text for the table caption."), NULL);
  506.  
  507.   gtk_object_set_data (GTK_OBJECT (toggle), "set_sensitive", entry);
  508.   gtk_widget_set_sensitive (entry, gtmvals.caption);
  509.  
  510.   entry = gtk_entry_new ();
  511.   gtk_widget_set_usize (entry, 200, 0);
  512.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  513.                  _("Cell Content:"), 1.0, 0.5,
  514.                  entry, 1, FALSE);
  515.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  516.               GTK_SIGNAL_FUNC (gtm_cellcontent_callback),
  517.               NULL);
  518.   gtk_entry_set_text (GTK_ENTRY (entry), gtmvals.cellcontent);
  519.   gtk_widget_show (entry);
  520.   gimp_help_set_help_data (entry, _("The text to go into each cell."), NULL);
  521.  
  522.   gtk_widget_show (table);
  523.   gtk_widget_show (frame);
  524.  
  525.   /* HTML Table Options */
  526.   frame = gtk_frame_new (_("Table Options"));
  527.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  528.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  529.  
  530.   table = gtk_table_new (5, 2, FALSE);
  531.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  532.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  533.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  534.   gtk_container_add (GTK_CONTAINER (frame), table);
  535.  
  536.   spinbutton = gimp_spin_button_new (&adj, gtmvals.border,
  537.                      0, 1000, 1, 10, 0, 1, 0);
  538.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  539.                  _("Border:"), 1.0, 0.5,
  540.                  spinbutton, 1, TRUE);
  541.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  542.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  543.                       >mvals.border);
  544.   gimp_help_set_help_data (spinbutton,
  545.                _("The number of pixels in the table border."),
  546.                NULL);
  547.  
  548.   entry = gtk_entry_new ();
  549.   gtk_widget_set_usize (entry, 60, 0);
  550.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  551.                  _("Width:"), 1.0, 0.5,
  552.                  entry, 1, TRUE);
  553.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  554.                       GTK_SIGNAL_FUNC (gtm_clwidth_callback),
  555.                       NULL);
  556.   gtk_entry_set_text (GTK_ENTRY (entry), gtmvals.clwidth);
  557.   gimp_help_set_help_data (entry,
  558.                _("The width for each table cell.  "
  559.                  "Can be a number or a percent."),
  560.                NULL);
  561.  
  562.   entry = gtk_entry_new ();
  563.   gtk_widget_set_usize (entry, 60, 0);
  564.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  565.                  _("Height:"), 1.0, 0.5,
  566.                  entry, 1, TRUE);
  567.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  568.                       GTK_SIGNAL_FUNC (gtm_clheight_callback),
  569.                       NULL);
  570.   gtk_entry_set_text (GTK_ENTRY (entry), gtmvals.clheight);
  571.   gimp_help_set_help_data (entry,
  572.                _("The height for each table cell.  "
  573.                  "Can be a number or a percent."),
  574.                NULL);
  575.  
  576.   spinbutton = gimp_spin_button_new (&adj, gtmvals.cellpadding,
  577.                      0, 1000, 1, 10, 0, 1, 0);
  578.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  579.                  _("Cell-Padding:"), 1.0, 0.5,
  580.                  spinbutton, 1, TRUE);
  581.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  582.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  583.                       >mvals.cellpadding);
  584.   gimp_help_set_help_data (spinbutton,
  585.                _("The amount of cellpadding."), NULL);
  586.  
  587.   spinbutton = gimp_spin_button_new (&adj, gtmvals.cellspacing,
  588.                      0, 1000, 1, 10, 0, 1, 0);
  589.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
  590.                  _("Cell-Spacing:"), 1.0, 0.5,
  591.                  spinbutton, 1, TRUE);
  592.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  593.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  594.                       >mvals.cellspacing);
  595.   gimp_help_set_help_data (spinbutton,
  596.                _("The amount of cellspacing."), NULL);
  597.  
  598.   gtk_widget_show (table);
  599.   gtk_widget_show (frame);
  600.  
  601.   gtk_widget_show (dlg);
  602.  
  603.   gtk_main ();
  604.   gdk_flush ();
  605.  
  606.   return bint.run;
  607. }
  608.  
  609. static gint
  610. color_comp (guchar *buffer,
  611.         guchar *buf2)
  612. {
  613.   if (buffer[0] == buf2[0] && buffer[1] == buf2[1] && buffer[2] == buf2[2])
  614.     return 1;
  615.   else
  616.     return 0;
  617. }  
  618.  
  619. /*  Save interface functions  */
  620.  
  621. static void
  622. save_ok_callback (GtkWidget *widget,
  623.           gpointer   data)
  624. {
  625.   bint.run = TRUE;
  626.  
  627.   gtk_widget_destroy (GTK_WIDGET (data));
  628. }
  629.  
  630. static void
  631. gtm_caption_callback (GtkWidget *widget,
  632.               gpointer   data)
  633. {
  634.   strcpy (gtmvals.captiontxt, gtk_entry_get_text (GTK_ENTRY (widget)));
  635. }
  636.  
  637. static void
  638. gtm_cellcontent_callback (GtkWidget *widget,
  639.               gpointer   data)
  640. {
  641.   strcpy (gtmvals.cellcontent, gtk_entry_get_text (GTK_ENTRY (widget)));
  642. }
  643.  
  644. static void
  645. gtm_clwidth_callback (GtkWidget *widget,
  646.               gpointer   data)
  647. {
  648.   strcpy (gtmvals.clwidth, gtk_entry_get_text (GTK_ENTRY (widget)));
  649. }
  650.  
  651. static void
  652. gtm_clheight_callback (GtkWidget *widget,
  653.                gpointer   data)
  654. {
  655.   strcpy (gtmvals.clheight, gtk_entry_get_text (GTK_ENTRY (widget)));
  656. }
  657.