home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimppatternmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-06  |  11.0 KB  |  413 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimppatternmenu.c
  5.  * Copyright (C) 1998 Andy Thomas 
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "string.h"
  24.  
  25. #include "gimp.h"
  26. #include "gimpui.h"
  27.  
  28. /* Idea is to have a function to call that returns a widget that 
  29.  * completely controls the selection of a pattern.
  30.  * you get a widget returned that you can use in a table say.
  31.  * In:- Initial pattern name. Null means use current selection.
  32.  *      pointer to func to call when pattern changes (GimpRunPatternCallback).
  33.  * Returned:- Pointer to a widget that you can use in UI.
  34.  * 
  35.  * Widget simply made up of a preview widget (20x20) containing the pattern
  36.  * and a button that can be clicked on to change the pattern.
  37.  */
  38.  
  39.  
  40. #define PSEL_DATA_KEY       "__psel_data"
  41. #define CELL_SIZE           20
  42. #define PREVIEW_EVENT_MASK  GDK_EXPOSURE_MASK       | \
  43.                             GDK_BUTTON_PRESS_MASK   | \
  44.                 GDK_BUTTON_RELEASE_MASK | \
  45.                             GDK_BUTTON1_MOTION_MASK 
  46.  
  47. struct __patterns_sel 
  48. {
  49.   gchar                  *dname;
  50.   GimpRunPatternCallback  cback;
  51.   GtkWidget              *pattern_preview;
  52.   GtkWidget              *device_patpopup; 
  53.   GtkWidget              *device_patpreview;
  54.   GtkWidget              *button;
  55.   GtkWidget              *top_hbox;
  56.   gchar                  *pattern_name;      /* Local copy */
  57.   gint                    width;
  58.   gint                    height;
  59.   gint                    bytes;
  60.   gchar                  *mask_data;         /* local copy */
  61.   gchar                  *pattern_popup_pnt; /* Pointer use to control the popup */
  62.   gpointer                data;
  63. };
  64.  
  65. typedef struct __patterns_sel PSelect;
  66.  
  67. static void
  68. pattern_popup_open (gint     x,
  69.             gint     y,
  70.             PSelect *psel)
  71. {
  72.   gint   x_org;
  73.   gint   y_org;
  74.   gint   scr_w;
  75.   gint   scr_h;
  76.   gchar *src;
  77.   gchar *buf;
  78.  
  79.   /* make sure the popup exists and is not visible */
  80.   if (psel->device_patpopup == NULL)
  81.     {
  82.       GtkWidget *frame;
  83.  
  84.       psel->device_patpopup = gtk_window_new (GTK_WINDOW_POPUP);
  85.       frame = gtk_frame_new (NULL);
  86.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  87.       gtk_container_add (GTK_CONTAINER (psel->device_patpopup), frame);
  88.       gtk_widget_show (frame);
  89.       psel->device_patpreview = gtk_preview_new (GTK_PREVIEW_COLOR);
  90.       gtk_container_add (GTK_CONTAINER (frame), psel->device_patpreview);
  91.       gtk_widget_show (psel->device_patpreview);
  92.     }
  93.   else
  94.     {
  95.       gtk_widget_hide (psel->device_patpopup);
  96.     }
  97.  
  98.   /* decide where to put the popup */
  99.   gdk_window_get_origin (psel->pattern_preview->window, &x_org, &y_org);
  100.   scr_w = gdk_screen_width ();
  101.   scr_h = gdk_screen_height ();
  102.   x = x_org + x - (psel->width >> 1);
  103.   y = y_org + y - (psel->height >> 1);
  104.   x = (x < 0) ? 0 : x;
  105.   y = (y < 0) ? 0 : y;
  106.   x = (x + psel->width > scr_w) ? scr_w - psel->width : x;
  107.   y = (y + psel->height > scr_h) ? scr_h - psel->height : y;
  108.   gtk_preview_size (GTK_PREVIEW (psel->device_patpreview), 
  109.             psel->width, psel->height);
  110.  
  111.   gtk_widget_popup (psel->device_patpopup, x, y);
  112.   
  113.   /*  Draw the pattern  */
  114.   buf = g_new (gchar, psel->width * 3);
  115.   src = psel->mask_data;
  116.   for (y = 0; y < psel->height; y++)
  117.     {
  118.       if (psel->bytes == 1)
  119.     for (x = 0; x < psel->width; x++)
  120.       {
  121.         buf[x*3+0] = src[x];
  122.         buf[x*3+1] = src[x];
  123.         buf[x*3+2] = src[x];
  124.       }
  125.       else
  126.     for (x = 0; x < psel->width; x++)
  127.       {
  128.         buf[x*3+0] = src[x*3+0];
  129.         buf[x*3+1] = src[x*3+1];
  130.         buf[x*3+2] = src[x*3+2];
  131.       }
  132.       gtk_preview_draw_row (GTK_PREVIEW (psel->device_patpreview), 
  133.                 (guchar *)buf, 0, y, psel->width);
  134.       src += psel->width * psel->bytes;
  135.     }
  136.   g_free (buf);
  137.   
  138.   /*  Draw the brush preview  */
  139.   gtk_widget_draw (psel->device_patpreview, NULL);
  140. }
  141.  
  142. static void
  143. pattern_popup_close (PSelect *psel)
  144. {
  145.   if (psel->device_patpopup != NULL)
  146.     gtk_widget_hide (psel->device_patpopup);
  147. }
  148.  
  149. static gint
  150. pattern_preview_events (GtkWidget *widget,
  151.             GdkEvent  *event,
  152.             gpointer   data)
  153. {
  154.   GdkEventButton *bevent;
  155.   PSelect        *psel = (PSelect*)data;
  156.  
  157.   if (psel->mask_data)
  158.     {
  159.       switch (event->type)
  160.     {
  161.     case GDK_EXPOSE:
  162.       break;
  163.       
  164.     case GDK_BUTTON_PRESS:
  165.       bevent = (GdkEventButton *) event;
  166.       
  167.       if (bevent->button == 1)
  168.         {
  169.           gtk_grab_add (widget);
  170.           pattern_popup_open (bevent->x, bevent->y, psel);
  171.         }
  172.       break;
  173.       
  174.     case GDK_BUTTON_RELEASE:
  175.       bevent = (GdkEventButton *) event;
  176.       
  177.       if (bevent->button == 1)
  178.         {
  179.           gtk_grab_remove (widget);
  180.           pattern_popup_close (psel);
  181.         }
  182.       break;
  183.     case GDK_DELETE:
  184.       break;
  185.       
  186.     default:
  187.       break;
  188.     }
  189.     }
  190.  
  191.   return FALSE;
  192. }
  193.  
  194. static void
  195. pattern_pre_update (GtkWidget *pattern_preview,
  196.             gint       width,
  197.             gint       height,
  198.             gint       bytes,
  199.             gchar     *mask_data)
  200. {
  201.   gint   x;
  202.   gint   y;
  203.   gchar *src;
  204.   gchar *buf;
  205.  
  206.   /*  Draw the pattern  */
  207.   buf = g_new (gchar, width * 3);
  208.   src = mask_data;
  209.   for (y = 0; y < CELL_SIZE && y < height; y++)
  210.     {
  211.       if (bytes == 1)
  212.     for (x = 0; x < width && x < CELL_SIZE; x++)
  213.       {
  214.         buf[x*3+0] = src[x];
  215.         buf[x*3+1] = src[x];
  216.         buf[x*3+2] = src[x];
  217.       }
  218.       else
  219.     for (x = 0; x < width && x < CELL_SIZE; x++)
  220.       {
  221.         buf[x*3+0] = src[x*3+0];
  222.         buf[x*3+1] = src[x*3+1];
  223.         buf[x*3+2] = src[x*3+2];
  224.       }
  225.       gtk_preview_draw_row (GTK_PREVIEW (pattern_preview), 
  226.                 (guchar *)buf, 0, y, (width < CELL_SIZE) ? width : CELL_SIZE);
  227.       src += width * bytes;
  228.     }
  229.   g_free (buf);
  230.  
  231.   /*  Draw the brush preview  */
  232.   gtk_widget_draw (pattern_preview, NULL);
  233. }
  234.  
  235. static void
  236. pattern_select_invoker (gchar    *name,
  237.             gint      width,
  238.             gint      height,
  239.             gint      bytes,
  240.             gchar    *mask_data,
  241.             gint      closing,
  242.             gpointer  data)
  243. {
  244.   gint     mask_d_sz;
  245.   PSelect *psel = (PSelect*)data;
  246.  
  247.   if (psel->mask_data != NULL)
  248.     g_free(psel->mask_data);
  249.  
  250.   psel->width  = width;
  251.   psel->height = height;
  252.   psel->bytes  = bytes;
  253.   mask_d_sz    = width * height * bytes;
  254.   psel->mask_data = g_malloc (mask_d_sz);
  255.   g_memmove (psel->mask_data, mask_data, mask_d_sz); 
  256.  
  257.   pattern_pre_update (psel->pattern_preview, 
  258.               psel->width, psel->height, psel->bytes, psel->mask_data);
  259.  
  260.   if (psel->cback != NULL)
  261.      (psel->cback)(name, width, height, bytes, mask_data, closing, psel->data);
  262.  
  263.   if(closing)
  264.     {
  265.       gtk_widget_set_sensitive (psel->button, TRUE);
  266.       psel->pattern_popup_pnt = NULL;
  267.     }
  268. }
  269.  
  270.  
  271. static void
  272. patterns_select_callback (GtkWidget *widget,
  273.               gpointer   data)
  274. {
  275.   PSelect *psel = (PSelect*)data;
  276.  
  277.   gtk_widget_set_sensitive (psel->button, FALSE);
  278.   psel->pattern_popup_pnt = 
  279.     gimp_interactive_selection_pattern ((psel->dname) ? psel->dname : 
  280.                                     "Pattern Plugin Selection",
  281.                     psel->pattern_name,
  282.                     pattern_select_invoker,psel);
  283. }
  284.  
  285. GtkWidget * 
  286. gimp_pattern_select_widget (gchar                  *dname,
  287.                 gchar                  *ipattern, 
  288.                 GimpRunPatternCallback  cback,
  289.                 gpointer                data)
  290. {
  291.   GtkWidget *frame;
  292.   GtkWidget *hbox;
  293.   GtkWidget *pattern;
  294.   GtkWidget *button;
  295.   gint       width;
  296.   gint       height;
  297.   gint       bytes;
  298.   gint       mask_data_size;
  299.   guint8    *mask_data;
  300.   gchar     *pattern_name;
  301.   PSelect   *psel;
  302.   
  303.   psel = g_new (PSelect, 1);
  304.  
  305.   hbox = gtk_hbox_new (FALSE, 3);
  306.   gtk_widget_show(hbox);
  307.  
  308.   frame = gtk_frame_new (NULL);
  309.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  310.   gtk_widget_show (frame);
  311.  
  312.   pattern = gtk_preview_new (GTK_PREVIEW_COLOR);
  313.   gtk_preview_size (GTK_PREVIEW (pattern), CELL_SIZE, CELL_SIZE); 
  314.   gtk_widget_show (pattern);
  315.   gtk_container_add (GTK_CONTAINER (frame), pattern); 
  316.  
  317.   gtk_widget_set_events (pattern, PREVIEW_EVENT_MASK);
  318.  
  319.   gtk_signal_connect (GTK_OBJECT (pattern), "event",
  320.               (GtkSignalFunc) pattern_preview_events,
  321.               (gpointer)psel);
  322.   
  323.   psel->cback             = cback;
  324.   psel->data              = data;
  325.   psel->mask_data         = NULL;
  326.   psel->device_patpopup   = psel->device_patpreview = NULL;
  327.   psel->pattern_preview   = pattern;
  328.   psel->pattern_name      = ipattern;
  329.   psel->dname             = dname;
  330.   psel->pattern_popup_pnt = NULL;
  331.  
  332.   /* Do initial pattern setup */
  333.   pattern_name = 
  334.     gimp_patterns_get_pattern_data (ipattern, 
  335.                     &width, 
  336.                     &height, 
  337.                     &bytes, 
  338.                     &mask_data_size, 
  339.                     &mask_data);
  340.  
  341.   if(pattern_name)
  342.     {
  343.       pattern_pre_update (psel->pattern_preview, 
  344.               width, height, bytes, mask_data);
  345.       psel->mask_data    = mask_data;
  346.       psel->pattern_name = pattern_name;
  347.       psel->width        = width;
  348.       psel->height       = height;
  349.       psel->bytes        = bytes;
  350.     }
  351.  
  352.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  353.  
  354.   button = gtk_button_new_with_label ("... ");
  355.   gtk_container_add (GTK_CONTAINER (hbox), button); 
  356.   gtk_widget_show (button);
  357.  
  358.   psel->button = button;
  359.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  360.                       (GtkSignalFunc) patterns_select_callback,
  361.                       (gpointer)psel);
  362.  
  363.   gtk_object_set_data (GTK_OBJECT(hbox), PSEL_DATA_KEY, (gpointer)psel);
  364.  
  365.   return hbox;
  366. }
  367.  
  368. void
  369. gimp_pattern_select_widget_close_popup (GtkWidget *widget)
  370. {
  371.   PSelect  *psel;
  372.  
  373.   psel = (PSelect *) gtk_object_get_data (GTK_OBJECT (widget), PSEL_DATA_KEY);
  374.  
  375.   if (psel && psel->pattern_popup_pnt)
  376.     {
  377.       gimp_patterns_close_popup (psel->pattern_popup_pnt);
  378.       psel->pattern_popup_pnt = NULL;
  379.     }
  380. }
  381.  
  382. void
  383. gimp_pattern_select_widget_set_popup (GtkWidget *widget,
  384.                       gchar     *pname)
  385. {
  386.   gint      width;
  387.   gint      height;
  388.   gint      bytes;
  389.   gint      mask_data_size;
  390.   guint8   *mask_data;
  391.   gchar    *pattern_name;
  392.   PSelect  *psel;
  393.   
  394.   psel = (PSelect*) gtk_object_get_data (GTK_OBJECT (widget), PSEL_DATA_KEY);
  395.  
  396.   if (psel)
  397.     {
  398.       pattern_name = 
  399.     gimp_patterns_get_pattern_data (pname,
  400.                     &width, 
  401.                     &height, 
  402.                     &bytes, 
  403.                     &mask_data_size,
  404.                     &mask_data);
  405.   
  406.       pattern_select_invoker (pname, width, height, bytes, mask_data, 0, psel);
  407.       
  408.       if (psel->pattern_popup_pnt)
  409.     gimp_patterns_set_popup (psel->pattern_popup_pnt, pname);
  410.     }
  411. }
  412.  
  413.