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

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpbrushmenu.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.  
  29. /* Idea is to have a function to call that returns a widget that 
  30.  * completely controls the selection of a brush.
  31.  * you get a widget returned that you can use in a table say.
  32.  * In:- Initial brush name. Null means use current selection.
  33.  *      pointer to func to call when brush changes (GimpRunBrushCallback).
  34.  * Returned:- Pointer to a widget that you can use in UI.
  35.  * 
  36.  * Widget simply made up of a preview widget (20x20) containing the brush mask
  37.  * and a button that can be clicked on to change the brush.
  38.  */
  39.  
  40.  
  41. #define BSEL_DATA_KEY     "__bsel_data"
  42. #define CELL_SIZE         20
  43. #define BRUSH_EVENT_MASK  GDK_EXPOSURE_MASK       | \
  44.                           GDK_BUTTON_PRESS_MASK   | \
  45.               GDK_BUTTON_RELEASE_MASK | \
  46.                           GDK_BUTTON1_MOTION_MASK 
  47.  
  48. struct __brushes_sel 
  49. {
  50.   gchar                *dname;
  51.   GimpRunBrushCallback  cback;
  52.   GtkWidget            *brush_preview;
  53.   GtkWidget            *device_brushpopup; 
  54.   GtkWidget            *device_brushpreview;
  55.   GtkWidget            *button;
  56.   GtkWidget            *top_hbox;
  57.   gchar                *brush_name;       /* Local copy */
  58.   gdouble               opacity;
  59.   gint                  spacing;
  60.   gint                  paint_mode;
  61.   gint                  width;
  62.   gint                  height;
  63.   gchar                *mask_data;        /* local copy */
  64.   void                 *brush_popup_pnt;  /* Pointer use to control the popup */
  65.   gpointer              data;
  66. };
  67.  
  68. typedef struct __brushes_sel BSelect;
  69.  
  70. static void
  71. brush_popup_open (gint      x,
  72.           gint      y,
  73.           BSelect  *bsel)
  74. {
  75.   gint    x_org;
  76.   gint    y_org;
  77.   gint    scr_w;
  78.   gint    scr_h;
  79.   gchar  *src;
  80.   gchar  *buf;
  81.   guchar *b;
  82.   guchar *s;
  83.  
  84.   /* make sure the popup exists and is not visible */
  85.   if (bsel->device_brushpopup == NULL)
  86.     {
  87.       GtkWidget *frame;
  88.  
  89.       bsel->device_brushpopup = gtk_window_new (GTK_WINDOW_POPUP);
  90.       frame = gtk_frame_new (NULL);
  91.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  92.       gtk_container_add (GTK_CONTAINER (bsel->device_brushpopup), frame);
  93.       gtk_widget_show (frame);
  94.       bsel->device_brushpreview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
  95.       gtk_container_add (GTK_CONTAINER (frame), bsel->device_brushpreview);
  96.       gtk_widget_show (bsel->device_brushpreview);
  97.     }
  98.   else
  99.     {
  100.       gtk_widget_hide (bsel->device_brushpopup);
  101.     }
  102.  
  103.   /* decide where to put the popup */
  104.   gdk_window_get_origin (bsel->brush_preview->window, &x_org, &y_org);
  105.   scr_w = gdk_screen_width ();
  106.   scr_h = gdk_screen_height ();
  107.   x = x_org + x - (bsel->width >> 1);
  108.   y = y_org + y - (bsel->height >> 1);
  109.   x = (x < 0) ? 0 : x;
  110.   y = (y < 0) ? 0 : y;
  111.   x = (x + bsel->width > scr_w) ? scr_w - bsel->width : x;
  112.   y = (y + bsel->height > scr_h) ? scr_h - bsel->height : y;
  113.   gtk_preview_size (GTK_PREVIEW (bsel->device_brushpreview), bsel->width, bsel->height);
  114.  
  115.   gtk_widget_popup (bsel->device_brushpopup, x, y);
  116.   
  117.   /*  Draw the brush  */
  118.   buf = g_new (gchar, bsel->width);
  119.   
  120.   memset (buf, 255, sizeof(bsel->width));
  121.   
  122.   src = bsel->mask_data;
  123.   
  124.   for (y = 0; y < bsel->height; y++)
  125.     {
  126.       int j;
  127.       s = src;
  128.       b = buf;
  129.       for (j = 0; j < bsel->width ; j++)
  130.     *b++ = 255 - *s++;
  131.  
  132.       gtk_preview_draw_row (GTK_PREVIEW (bsel->device_brushpreview), 
  133.                 (guchar *)buf, 0, y, bsel->width);
  134.       src += bsel->width;
  135.     }
  136.   g_free (buf);
  137.   
  138.   /*  Draw the brush preview  */
  139.   gtk_widget_draw (bsel->device_brushpreview, NULL);
  140. }
  141.  
  142. static void
  143. brush_popup_close (BSelect *bsel)
  144. {
  145.   if (bsel->device_brushpopup != NULL)
  146.     gtk_widget_hide (bsel->device_brushpopup);
  147. }
  148.  
  149. static gint
  150. brush_preview_events (GtkWidget    *widget,
  151.               GdkEvent     *event,
  152.               gpointer      data)
  153. {
  154.   GdkEventButton *bevent;
  155.   BSelect        *bsel = (BSelect*)data;
  156.  
  157.   if (bsel->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.           brush_popup_open (bevent->x, bevent->y, bsel);
  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.           brush_popup_close (bsel);
  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. brush_pre_update (GtkWidget *brush_preview,
  196.           gint       brush_width,
  197.           gint       brush_height,
  198.           gchar     *mask_data)
  199. {
  200.   gint    y;
  201.   gint    i;
  202.   gchar  *src;
  203.   gchar  *buf;
  204.   guchar *b;
  205.   guchar *s;
  206.   gint    offset_x;
  207.   gint    offset_y;
  208.   gint    yend;
  209.   gint    ystart;
  210.   gint    width,height;
  211.  
  212.   /*  Draw the brush  */
  213.   buf = g_new (gchar, CELL_SIZE); 
  214.  
  215.  /* Limit to cell size */
  216.   width = (brush_width > CELL_SIZE) ? CELL_SIZE: brush_width;
  217.   height = (brush_height > CELL_SIZE) ? CELL_SIZE: brush_height;
  218.  
  219.   /* Set buffer to white */  
  220.   memset (buf, 255, CELL_SIZE);
  221.   for (i = 0; i < CELL_SIZE; i++)
  222.     gtk_preview_draw_row (GTK_PREVIEW (brush_preview),
  223.               (guchar *)buf, 0, i, CELL_SIZE);
  224.   
  225.   offset_x = ((CELL_SIZE - width) >> 1);
  226.   offset_y = ((CELL_SIZE - height) >> 1);
  227.  
  228.   ystart = CLAMP (offset_y, 0, CELL_SIZE);
  229.   yend   = CLAMP (offset_y + height, 0, CELL_SIZE);
  230.  
  231.   src = mask_data;
  232.  
  233.   for (y = ystart; y < yend; y++)
  234.     {
  235.       gint j;
  236.  
  237.       s = src;
  238.       b = buf;
  239.       for (j = 0; j < width ; j++)
  240.     *b++ = 255 - *s++;
  241.  
  242.       gtk_preview_draw_row (GTK_PREVIEW (brush_preview), 
  243.                 (guchar *)buf, offset_x, y, width);
  244.       src += brush_width;
  245.     }
  246.   g_free (buf);
  247.  
  248.   /*  Draw the brush preview  */
  249.   gtk_widget_draw (brush_preview, NULL);
  250. }
  251.  
  252. static void
  253. brush_select_invoker (gchar   *name,
  254.               gdouble  opacity,
  255.               gint     spacing,
  256.               gint     paint_mode,
  257.               gint     width,
  258.               gint     height,
  259.               gchar   *mask_data,
  260.               gint     closing,
  261.               gpointer data)
  262. {
  263.   gint     mask_d_sz;
  264.   BSelect *bsel = (BSelect *) data;
  265.  
  266.   if(bsel->mask_data != NULL)
  267.     g_free(bsel->mask_data);
  268.  
  269.   bsel->width  = width;
  270.   bsel->height = height;
  271.   mask_d_sz    = width * height;
  272.   bsel->mask_data = g_malloc (mask_d_sz);
  273.   g_memmove (bsel->mask_data, mask_data, mask_d_sz); 
  274.  
  275.   brush_pre_update (bsel->brush_preview,
  276.             bsel->width, bsel->height, bsel->mask_data);
  277.   bsel->opacity = opacity;
  278.   bsel->spacing = spacing;
  279.   bsel->paint_mode = paint_mode;
  280.  
  281.   if (bsel->cback != NULL)
  282.     (bsel->cback) (name, opacity, spacing, paint_mode, 
  283.            width, height, mask_data, closing, bsel->data);
  284.  
  285.   if (closing)
  286.     {
  287.       gtk_widget_set_sensitive (bsel->button, TRUE);
  288.       bsel->brush_popup_pnt = NULL;
  289.     }
  290. }
  291.  
  292. static void
  293. brush_select_callback (GtkWidget *widget,
  294.                gpointer   data)
  295. {
  296.   BSelect *bsel = (BSelect*)data;
  297.  
  298.   gtk_widget_set_sensitive (bsel->button,FALSE);
  299.  
  300.   bsel->brush_popup_pnt = 
  301.     gimp_interactive_selection_brush ((bsel->dname) ? bsel->dname 
  302.                                     : "Brush Plugin Selection",
  303.                       bsel->brush_name,
  304.                       bsel->opacity,
  305.                       bsel->spacing,
  306.                       bsel->paint_mode,
  307.                       brush_select_invoker,
  308.                       bsel);
  309. }
  310.  
  311. GtkWidget * 
  312. gimp_brush_select_widget (gchar                *dname,
  313.               gchar                *ibrush, 
  314.               gdouble               opacity,
  315.               gint                  spacing,
  316.               gint                  paint_mode,
  317.               GimpRunBrushCallback  cback,
  318.               gpointer              data)
  319. {
  320.   GtkWidget *frame;
  321.   GtkWidget *hbox;
  322.   GtkWidget *brush;
  323.   GtkWidget *button;
  324.   gint       width;
  325.   gint       height;
  326.   gint       init_spacing;
  327.   GimpLayerModeEffects init_paint_mode;
  328.   gdouble    init_opacity;
  329.   gint       mask_data_size;
  330.   guint8    *mask_data;
  331.   gchar     *brush_name;
  332.   BSelect   *bsel;
  333.  
  334.   bsel = g_new (BSelect, 1);
  335.  
  336.   hbox = gtk_hbox_new (FALSE, 3);
  337.   gtk_widget_show (hbox);
  338.  
  339.   frame = gtk_frame_new (NULL);
  340.   gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_OUT);
  341.   gtk_widget_show (frame);
  342.  
  343.   brush = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
  344.   gtk_preview_size (GTK_PREVIEW (brush), CELL_SIZE, CELL_SIZE); 
  345.   gtk_widget_show (brush);
  346.   gtk_container_add (GTK_CONTAINER (frame), brush); 
  347.  
  348.   gtk_widget_set_events (brush, BRUSH_EVENT_MASK);
  349.  
  350.   gtk_signal_connect (GTK_OBJECT (brush), "event",
  351.               (GtkSignalFunc) brush_preview_events,
  352.               (gpointer)bsel);
  353.  
  354.   bsel->cback             = cback;
  355.   bsel->data              = data;
  356.   bsel->mask_data         = NULL;
  357.   bsel->device_brushpopup = bsel->device_brushpreview = NULL;
  358.   bsel->brush_preview     = brush;
  359.   bsel->brush_name        = ibrush;
  360.   bsel->dname             = dname;
  361.   bsel->brush_popup_pnt   = NULL;
  362.  
  363.   /* Do initial brush setup */
  364.   brush_name = gimp_brushes_get_brush_data (ibrush,
  365.                         &init_opacity,
  366.                         &init_spacing,
  367.                         &init_paint_mode,
  368.                         &width,
  369.                         &height,
  370.                         &mask_data_size,
  371.                         &mask_data);
  372.   if (brush_name)
  373.     {
  374.       brush_pre_update (bsel->brush_preview, width, height, mask_data);
  375.       bsel->mask_data  = mask_data;
  376.       bsel->brush_name = brush_name;
  377.       bsel->width      = width;
  378.       bsel->height     = height;
  379.       if (opacity != -1)
  380.     bsel->opacity = opacity;
  381.       else
  382.     bsel->opacity = init_opacity;
  383.       if (spacing != -1)
  384.     bsel->spacing = spacing;
  385.       else
  386.     bsel->spacing = init_spacing;
  387.       if (paint_mode != -1)
  388.     bsel->paint_mode = paint_mode;
  389.       else
  390.     bsel->paint_mode = init_paint_mode;
  391.     }
  392.  
  393.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  394.  
  395.   button = gtk_button_new_with_label ("... ");
  396.   gtk_container_add (GTK_CONTAINER (hbox), button); 
  397.   gtk_widget_show(button);
  398.  
  399.   bsel->button = button;
  400.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  401.                       (GtkSignalFunc) brush_select_callback,
  402.                       (gpointer)bsel);
  403.  
  404.   gtk_object_set_data (GTK_OBJECT (hbox), BSEL_DATA_KEY, (gpointer) bsel);
  405.  
  406.   return hbox;
  407. }
  408.  
  409.  
  410. void
  411. gimp_brush_select_widget_close_popup (GtkWidget *widget)
  412. {
  413.   BSelect  *bsel;
  414.  
  415.   bsel = (BSelect *) gtk_object_get_data (GTK_OBJECT (widget), BSEL_DATA_KEY);
  416.  
  417.   if (bsel && bsel->brush_popup_pnt)
  418.     {
  419.       gimp_brushes_close_popup (bsel->brush_popup_pnt);
  420.       bsel->brush_popup_pnt = NULL;
  421.     }
  422. }
  423.  
  424. void
  425. gimp_brush_select_widget_set_popup (GtkWidget *widget,
  426.                     gchar     *bname,
  427.                     gdouble    opacity,
  428.                     gint       spacing,
  429.                     gint       paint_mode)
  430. {
  431.   gint     width;
  432.   gint     height;
  433.   gint     init_spacing;
  434.   GimpLayerModeEffects init_paint_mode;
  435.   gdouble  init_opacity;
  436.   gint     mask_data_size;
  437.   guint8  *mask_data;
  438.   gchar   *brush_name;
  439.   BSelect *bsel;
  440.   
  441.   bsel = (BSelect *) gtk_object_get_data (GTK_OBJECT (widget), BSEL_DATA_KEY);
  442.  
  443.   if (bsel)
  444.     {
  445.       brush_name = gimp_brushes_get_brush_data (bname,
  446.                         &init_opacity,
  447.                         &init_spacing,
  448.                         &init_paint_mode,
  449.                         &width,
  450.                         &height,
  451.                         &mask_data_size,
  452.                         &mask_data);
  453.  
  454.       if (opacity == -1.0)
  455.     opacity = init_opacity;
  456.  
  457.       if (spacing == -1)
  458.     spacing = init_spacing;
  459.  
  460.       if (paint_mode == -1)
  461.     paint_mode = init_paint_mode;
  462.   
  463.       brush_select_invoker (bname, opacity, spacing, paint_mode,
  464.                 width, height, mask_data, 0, bsel);
  465.  
  466.       if (bsel->brush_popup_pnt)
  467.     gimp_brushes_set_popup (bsel->brush_popup_pnt, 
  468.                 bname, opacity, spacing, paint_mode);
  469.     }
  470. }
  471.