home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / gimpcontextpreview.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  26.1 KB  |  974 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * GimpContextPreview Widget
  5.  * Copyright (C) 1999 Sven Neumann
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program 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
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include "config.h"
  23.  
  24. #include <string.h>
  25.  
  26. #include <gtk/gtk.h>
  27.  
  28. #include "apptypes.h"
  29.  
  30. #include "appenv.h"
  31. #include "brush_scale.h"
  32. #include "gimpbrush.h"
  33. #include "gimpbrushpipe.h"
  34. #include "gimpcontextpreview.h"
  35. #include "gimpdnd.h"
  36. #include "gradient_header.h"
  37. #include "patterns.h"
  38. #include "temp_buf.h"
  39.  
  40. #include "libgimp/gimplimits.h"
  41.  
  42. /*  the pixmaps for the [scale|pipe]_indicators  */
  43. #define indicator_width 7
  44. #define indicator_height 7
  45.  
  46. #define WHT {255, 255, 255}
  47. #define BLK {  0,   0,   0}
  48. #define RED {255, 127, 127}
  49.  
  50. static unsigned char scale_indicator_bits[7][7][3] = 
  51. {
  52.   { WHT, WHT, WHT, WHT, WHT, WHT, WHT },
  53.   { WHT, WHT, WHT, BLK, WHT, WHT, WHT },
  54.   { WHT, WHT, WHT, BLK, WHT, WHT, WHT },
  55.   { WHT, BLK, BLK, BLK, BLK, BLK, WHT },
  56.   { WHT, WHT, WHT, BLK, WHT, WHT, WHT },
  57.   { WHT, WHT, WHT, BLK, WHT, WHT, WHT },
  58.   { WHT, WHT, WHT, WHT, WHT, WHT, WHT }
  59. };
  60.  
  61. static unsigned char pipe_indicator_bits[7][7][3] = 
  62. {
  63.   { WHT, WHT, WHT, WHT, WHT, WHT, WHT },
  64.   { WHT, WHT, WHT, WHT, WHT, WHT, RED },
  65.   { WHT, WHT, WHT, WHT, WHT, RED, RED },
  66.   { WHT, WHT, WHT, WHT, RED, RED, RED },
  67.   { WHT, WHT, WHT, RED, RED, RED, RED },
  68.   { WHT, WHT, RED, RED, RED, RED, RED },
  69.   { WHT, RED, RED, RED, RED, RED, RED }
  70. };
  71.  
  72. static unsigned char scale_pipe_indicator_bits[7][7][3] = 
  73. {
  74.   { WHT, WHT, WHT, WHT, WHT, WHT, WHT },
  75.   { WHT, WHT, WHT, BLK, WHT, WHT, RED },
  76.   { WHT, WHT, WHT, BLK, WHT, RED, RED },
  77.   { WHT, BLK, BLK, BLK, BLK, BLK, RED },
  78.   { WHT, WHT, WHT, BLK, RED, RED, RED },
  79.   { WHT, WHT, RED, BLK, RED, RED, RED },
  80.   { WHT, RED, RED, RED, RED, RED, RED }
  81. };
  82.  
  83.  
  84. /* how long to wait after mouse-down before showing popup */
  85. #define POPUP_DELAY_MS      150
  86.  
  87. /*  size of the gradient popup  */
  88. #define GRADIENT_POPUP_WIDTH  128
  89. #define GRADIENT_POPUP_HEIGHT 32
  90.  
  91. #define DRAG_PREVIEW_SIZE 32
  92.  
  93. /*  event mask for the context_preview  */
  94. #define CONTEXT_PREVIEW_EVENT_MASK  (GDK_BUTTON_PRESS_MASK |   \
  95.                      GDK_BUTTON_RELEASE_MASK | \
  96.                      GDK_ENTER_NOTIFY_MASK |   \
  97.                      GDK_LEAVE_NOTIFY_MASK)
  98.  
  99. /*  shared widgets for the popups  */
  100. /* XXX: It is pretty dangerous making these variables statics,
  101.  * I'd feel safer if they were per-instance and private. -- austin */
  102. static GtkWidget *gcp_popup = NULL;
  103. static GtkWidget *gcp_popup_preview = NULL;
  104. static guint gcp_pipe_timer = 0;
  105. static guint gcp_pipe_index = 0;
  106. static guint gcp_popup_timer = 0;
  107.  
  108. /*  dnd stuff  */
  109. static GtkTargetEntry context_preview_target_table[3][1] =
  110. {
  111.   { GIMP_TARGET_BRUSH },
  112.   { GIMP_TARGET_PATTERN },
  113.   { GIMP_TARGET_GRADIENT }
  114. };
  115. static guint n_targets = 1;
  116.  
  117. /*  signals  */
  118. enum
  119. {
  120.   CLICKED,
  121.   LAST_SIGNAL
  122. };
  123.  
  124. static guint gimp_context_preview_signals[LAST_SIGNAL] = { 0 };
  125. static GtkPreviewClass *parent_class = NULL;
  126.  
  127. static gpointer gimp_context_preview_get_data             (GimpContextPreview *,
  128.                                gpointer);
  129. static gint     gimp_context_preview_button_press_event   (GtkWidget *, 
  130.                                GdkEventButton *);
  131. static gint     gimp_context_preview_button_release_event (GtkWidget *, 
  132.                                GdkEventButton *);
  133. static void     gimp_context_preview_popup_open           (GimpContextPreview *, 
  134.                                gint, gint);
  135. static void     gimp_context_preview_popup_close          (void);
  136. static gboolean gimp_context_preview_data_matches_type    (GimpContextPreview *,
  137.                                gpointer);
  138. static void     gimp_context_preview_draw_brush           (GimpContextPreview *);
  139. static void     gimp_context_preview_draw_brush_popup     (GimpContextPreview *);
  140. static gint     gimp_context_preview_animate_pipe         (GimpContextPreview *);
  141. static void     gimp_context_preview_draw_pattern         (GimpContextPreview *);
  142. static void     gimp_context_preview_draw_pattern_popup   (GimpContextPreview *);
  143. static void     gimp_context_preview_draw_gradient        (GimpContextPreview *);
  144. static void     gimp_context_preview_draw_gradient_popup  (GimpContextPreview *);
  145.  
  146. static gint brush_dirty_callback  (GimpBrush *, GimpContextPreview *);
  147. static gint brush_rename_callback (GimpBrush *, GimpContextPreview *);
  148.  
  149. static void
  150. gimp_context_preview_destroy (GtkObject *object)
  151. {
  152.   g_return_if_fail (GIMP_IS_CONTEXT_PREVIEW (object));
  153.  
  154.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  155.     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
  156. }
  157.  
  158. static void
  159. gimp_context_preview_class_init (GimpContextPreviewClass *class)
  160. {
  161.   GtkObjectClass *object_class;
  162.   GtkWidgetClass *widget_class;
  163.  
  164.   object_class = (GtkObjectClass*) class;
  165.   widget_class = (GtkWidgetClass*) class;
  166.  
  167.   parent_class = gtk_type_class (gtk_preview_get_type ());
  168.  
  169.   gimp_context_preview_signals[CLICKED] = 
  170.     gtk_signal_new ("clicked",
  171.             GTK_RUN_FIRST,
  172.             object_class->type,
  173.             GTK_SIGNAL_OFFSET (GimpContextPreviewClass, clicked),
  174.             gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  175.   gtk_object_class_add_signals (object_class, gimp_context_preview_signals, 
  176.                 LAST_SIGNAL);
  177.  
  178.   class->clicked = NULL;
  179.  
  180.   widget_class->button_press_event = gimp_context_preview_button_press_event;
  181.   widget_class->button_release_event = gimp_context_preview_button_release_event;
  182.  
  183.   object_class->destroy = gimp_context_preview_destroy;
  184. }
  185.  
  186. static void
  187. gimp_context_preview_init (GimpContextPreview *gcp)
  188. {
  189.   gcp->data          = NULL;
  190.   gcp->type          = GCP_LAST;
  191.   gcp->width         = 0;
  192.   gcp->height        = 0;
  193.   gcp->popup_width   = 0;
  194.   gcp->popup_height  = 0;
  195.   gcp->show_popup    = FALSE;
  196.   gcp->show_tooltips = FALSE;
  197.  
  198.   GTK_PREVIEW (gcp)->type   = GTK_PREVIEW_COLOR;
  199.   GTK_PREVIEW (gcp)->bpp    = 3;
  200.   GTK_PREVIEW (gcp)->dither = GDK_RGB_DITHER_NORMAL;
  201.  
  202.   gtk_widget_set_events (GTK_WIDGET (gcp), CONTEXT_PREVIEW_EVENT_MASK);
  203. }
  204.  
  205. GtkType
  206. gimp_context_preview_get_type (void)
  207. {
  208.   static GtkType gcp_type = 0;
  209.  
  210.   if (!gcp_type)
  211.     {
  212.       GtkTypeInfo gcp_info =
  213.       {
  214.     "GimpContextPreview",
  215.     sizeof (GimpContextPreview),
  216.     sizeof (GimpContextPreviewClass),
  217.     (GtkClassInitFunc) gimp_context_preview_class_init,
  218.     (GtkObjectInitFunc) gimp_context_preview_init,
  219.     /* reserved_1 */ NULL,
  220.     /* reserved_2 */ NULL,
  221.         (GtkClassInitFunc) NULL
  222.       };
  223.  
  224.       gcp_type = gtk_type_unique (gtk_preview_get_type (), &gcp_info);
  225.     }
  226.   
  227.   return gcp_type;
  228. }
  229.  
  230. GtkWidget *
  231. gimp_context_preview_new (GimpContextPreviewType  type,
  232.               gint                    width,
  233.               gint                    height,
  234.               gboolean                show_popup,
  235.               gboolean                show_tooltips,
  236.               GtkSignalFunc           drop_data_callback,
  237.               gpointer                drop_data_data)
  238. {
  239.   GimpContextPreview *gcp;
  240.  
  241.   g_return_val_if_fail (type >= 0 && type < GCP_LAST, NULL);
  242.   g_return_val_if_fail (width > 0 && height > 0, NULL);
  243.  
  244.   gcp = gtk_type_new (gimp_context_preview_get_type ());
  245.  
  246.   gcp->type          = type;
  247.   gcp->width         = width;
  248.   gcp->height        = height;
  249.   gcp->show_popup    = show_popup;
  250.   gcp->show_tooltips = show_tooltips;
  251.  
  252.   gtk_preview_size (GTK_PREVIEW (gcp), width, height);
  253.  
  254.   /*  drag dest  */
  255.   gtk_drag_dest_set (GTK_WIDGET (gcp),
  256.              GTK_DEST_DEFAULT_HIGHLIGHT |
  257.              GTK_DEST_DEFAULT_MOTION |
  258.              GTK_DEST_DEFAULT_DROP,
  259.               context_preview_target_table[type], n_targets,
  260.              GDK_ACTION_COPY); 
  261.  
  262.   switch (type)
  263.     {
  264.     case GCP_BRUSH:
  265.       gimp_dnd_brush_dest_set (GTK_WIDGET (gcp),
  266.                    (GimpDndDropBrushFunc) drop_data_callback,
  267.                    drop_data_data);
  268.       break;
  269.     case GCP_PATTERN:
  270.       gimp_dnd_pattern_dest_set (GTK_WIDGET (gcp),
  271.                  (GimpDndDropPatternFunc) drop_data_callback,
  272.                  drop_data_data);
  273.       break;
  274.     case GCP_GRADIENT:
  275.       gimp_dnd_gradient_dest_set (GTK_WIDGET (gcp),
  276.                   (GimpDndDropGradientFunc) drop_data_callback,
  277.                   drop_data_data);
  278.       break;
  279.     default: 
  280.       break;
  281.     }
  282.  
  283.   return GTK_WIDGET (gcp);
  284. }
  285.  
  286. void
  287. gimp_context_preview_update (GimpContextPreview *gcp,
  288.                  gpointer            data)
  289. {
  290.   g_return_if_fail (GIMP_IS_CONTEXT_PREVIEW (gcp));
  291.   g_return_if_fail (gimp_context_preview_data_matches_type (gcp, data));
  292.  
  293.   if (!gcp->data)
  294.     {
  295.       if (gcp->show_popup)
  296.     gtk_drag_source_set (GTK_WIDGET (gcp),
  297.                  GDK_BUTTON2_MASK,
  298.                  context_preview_target_table[gcp->type], n_targets,
  299.                  GDK_ACTION_COPY);
  300.       else
  301.     gtk_drag_source_set (GTK_WIDGET (gcp),
  302.                  GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
  303.                  context_preview_target_table[gcp->type], n_targets,
  304.                  GDK_ACTION_COPY);
  305.  
  306.       switch (gcp->type)
  307.     {
  308.     case GCP_BRUSH:
  309.       gimp_dnd_brush_source_set
  310.         (GTK_WIDGET (gcp),
  311.          (GimpDndDragBrushFunc) gimp_context_preview_get_data,
  312.          NULL);
  313.       break;
  314.     case GCP_PATTERN:
  315.       gimp_dnd_pattern_source_set
  316.         (GTK_WIDGET (gcp),
  317.          (GimpDndDragPatternFunc) gimp_context_preview_get_data,
  318.          NULL);
  319.       break;
  320.     case GCP_GRADIENT:
  321.       gimp_dnd_gradient_source_set
  322.         (GTK_WIDGET (gcp),
  323.          (GimpDndDragGradientFunc) gimp_context_preview_get_data,
  324.          NULL);
  325.       break;
  326.     default: 
  327.       break;
  328.     }
  329.     }
  330.  
  331.   if (gcp->data && gcp->type == GCP_BRUSH)
  332.     gtk_signal_disconnect_by_data (GTK_OBJECT (gcp->data), gcp);
  333.  
  334.   gcp->data = data;
  335.   if (GTK_IS_OBJECT (gcp->data))
  336.     gtk_signal_connect (GTK_OBJECT (gcp->data), "destroy",
  337.             gtk_widget_destroyed, &gcp->data);
  338.   switch (gcp->type)
  339.     {
  340.     case GCP_BRUSH:
  341.       gimp_context_preview_draw_brush (gcp);
  342.       gtk_signal_connect (GTK_OBJECT (gcp->data), "dirty",
  343.               GTK_SIGNAL_FUNC (brush_dirty_callback), gcp);
  344.       gtk_signal_connect (GTK_OBJECT (gcp->data), "rename",
  345.               GTK_SIGNAL_FUNC (brush_rename_callback), gcp);
  346.       break;
  347.     case GCP_PATTERN:
  348.       gimp_context_preview_draw_pattern (gcp);
  349.       break;
  350.     case GCP_GRADIENT:
  351.       gimp_context_preview_draw_gradient (gcp);
  352.       break;
  353.     default: 
  354.       break;
  355.     }
  356.   gtk_widget_queue_draw (GTK_WIDGET (gcp));
  357.  
  358.   if (gcp->show_tooltips)
  359.     {
  360.       gchar *name = NULL;
  361.  
  362.       switch (gcp->type)
  363.     {
  364.     case GCP_BRUSH:
  365.       {
  366.         GimpBrush *brush = GIMP_BRUSH (gcp->data);
  367.         name = brush->name;
  368.       }
  369.       break;
  370.     case GCP_PATTERN:
  371.       {
  372.         GPattern *pattern = (GPattern *) (gcp->data);
  373.         name = pattern->name;
  374.       }
  375.       break;
  376.     case GCP_GRADIENT:
  377.       {
  378.         gradient_t *gradient = (gradient_t *) (gcp->data);
  379.         name = gradient->name;
  380.       }
  381.       break;
  382.     default:
  383.       break;
  384.     }
  385.       gimp_help_set_help_data (GTK_WIDGET (gcp), name, NULL);
  386.     }
  387. }
  388.  
  389. static gpointer
  390. gimp_context_preview_get_data (GimpContextPreview *gcp,
  391.                    gpointer            data)
  392. {
  393.   g_return_val_if_fail (GIMP_IS_CONTEXT_PREVIEW (gcp), NULL);
  394.  
  395.   return gcp->data;
  396. }
  397.  
  398. static gint
  399. gimp_context_preview_button_press_event (GtkWidget      *widget,
  400.                      GdkEventButton *bevent)
  401. {
  402.   if (bevent->button == 1)
  403.     {
  404.       if (GIMP_CONTEXT_PREVIEW (widget)->show_popup)
  405.     {
  406.       gdk_pointer_grab (widget->window, FALSE, GDK_BUTTON_RELEASE_MASK,
  407.                 NULL, NULL, bevent->time);
  408.       gimp_context_preview_popup_open (GIMP_CONTEXT_PREVIEW (widget), 
  409.                        bevent->x, bevent->y);
  410.     }
  411.     }
  412.   return FALSE;
  413. }
  414.   
  415. static gint
  416. gimp_context_preview_button_release_event (GtkWidget      *widget,
  417.                        GdkEventButton *bevent)
  418. {
  419.   gboolean fast_click = TRUE;
  420.  
  421.   if (bevent->button == 1)
  422.     {
  423.       if (GIMP_CONTEXT_PREVIEW (widget)->show_popup)
  424.         {
  425.       gdk_pointer_ungrab (bevent->time);
  426.  
  427.       /* user clicked quickly if the timeout is still running */
  428.       fast_click = gcp_popup_timer;
  429.  
  430.       gimp_context_preview_popup_close ();
  431.     }
  432.  
  433.       if (fast_click)
  434.     gtk_signal_emit_by_name (GTK_OBJECT (widget), "clicked");
  435.     }
  436.   return FALSE;
  437. }
  438.  
  439.  
  440. typedef struct {
  441.   GimpContextPreview *gcp;
  442.   gint              x;
  443.   gint              y;  
  444. } popup_timeout_args_t;
  445.  
  446.  
  447. static gboolean
  448. gimp_context_preview_popup_timeout (gpointer data)
  449. {
  450.   popup_timeout_args_t *popup_timeout_args = data;
  451.   GimpContextPreview *gcp;
  452.   gint x, y;
  453.   gint x_org, y_org;
  454.   gint scr_w, scr_h;
  455.  
  456.   gcp_popup_timer = 0;
  457.  
  458.   g_return_val_if_fail (popup_timeout_args != NULL, FALSE);
  459.  
  460.   gcp = popup_timeout_args->gcp;
  461.   x   = popup_timeout_args->x;
  462.   y   = popup_timeout_args->y;
  463.  
  464.   g_return_val_if_fail (gcp != NULL, FALSE);
  465.   if (!gcp->data)
  466.     return FALSE;
  467.  
  468.   switch (gcp->type)
  469.     {
  470.     case GCP_BRUSH:
  471.       {
  472.     GimpBrush *brush = GIMP_BRUSH (gcp->data);
  473.     gcp->popup_width  = brush->mask->width;
  474.     gcp->popup_height = brush->mask->height;
  475.  
  476.     if (GIMP_IS_BRUSH_PIPE (brush))
  477.       {
  478.         GimpBrushPipe *pipe = GIMP_BRUSH_PIPE (brush);
  479.         gint i;
  480.  
  481.         for (i = 1; i < pipe->nbrushes; i++)
  482.           {
  483.         brush = GIMP_BRUSH (pipe->brushes[i]);
  484.         gcp->popup_width  = MAX (gcp->popup_width, brush->mask->width);
  485.         gcp->popup_height = MAX (gcp->popup_height, brush->mask->height);
  486.           }
  487.       }
  488.     else if (gcp->popup_width <= gcp->width && gcp->popup_height <= gcp->height)
  489.       return FALSE;
  490.       }
  491.       break;
  492.     case GCP_PATTERN:
  493.       {
  494.     GPattern *pattern = (GPattern*)gcp->data;
  495.     gcp->popup_width  = pattern->mask->width;
  496.     gcp->popup_height = pattern->mask->height;
  497.     if (gcp->popup_width <= gcp->width && gcp->popup_height <= gcp->height)
  498.       return FALSE;
  499.       }
  500.       break;
  501.     case GCP_GRADIENT:
  502.       gcp->popup_width  = GRADIENT_POPUP_WIDTH;
  503.       gcp->popup_height = GRADIENT_POPUP_HEIGHT;
  504.       if (gcp->popup_width <= gcp->width && gcp->popup_height <= gcp->height)
  505.     return FALSE;
  506.      break;
  507.      default:
  508.       return FALSE;
  509.     }
  510.  
  511.   /* make sure the popup exists and is not visible */
  512.   if (gcp_popup == NULL)
  513.     {
  514.       GtkWidget *frame;
  515.  
  516.       gcp_popup = gtk_window_new (GTK_WINDOW_POPUP);
  517.       gtk_window_set_policy (GTK_WINDOW (gcp_popup), FALSE, FALSE, TRUE);
  518.       gtk_signal_connect (GTK_OBJECT (gcp_popup), "destroy", 
  519.               gtk_widget_destroyed, &gcp_popup);
  520.       frame = gtk_frame_new (NULL);
  521.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  522.       gtk_container_add (GTK_CONTAINER (gcp_popup), frame);
  523.       gtk_widget_show (frame);
  524.       gcp_popup_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  525.       gtk_signal_connect (GTK_OBJECT (gcp_popup_preview), "destroy", 
  526.               gtk_widget_destroyed, &gcp_popup_preview);
  527.       gtk_container_add (GTK_CONTAINER (frame), gcp_popup_preview);
  528.       gtk_widget_show (gcp_popup_preview);
  529.     }
  530.   else
  531.     {
  532.       gtk_widget_hide (gcp_popup);
  533.     }
  534.  
  535.   /* decide where to put the popup */
  536.   gdk_window_get_origin (GTK_WIDGET (gcp)->window, &x_org, &y_org);
  537.   scr_w = gdk_screen_width ();
  538.   scr_h = gdk_screen_height ();
  539.   x = x_org + x - (gcp->popup_width >> 1);
  540.   y = y_org + y - (gcp->popup_height >> 1);
  541.   x = (x < 0) ? 0 : x;
  542.   y = (y < 0) ? 0 : y;
  543.   x = (x + gcp->popup_width > scr_w) ? scr_w - gcp->popup_width : x;
  544.   y = (y + gcp->popup_height > scr_h) ? scr_h - gcp->popup_height : y;
  545.   gtk_preview_size (GTK_PREVIEW (gcp_popup_preview), gcp->popup_width, gcp->popup_height);
  546.   gtk_widget_popup (gcp_popup, x, y);
  547.  
  548.   switch (gcp->type)
  549.     {
  550.     case GCP_BRUSH:      
  551.       gimp_context_preview_draw_brush_popup (gcp);
  552.       if (GIMP_IS_BRUSH_PIPE (gcp->data) && gcp_pipe_timer == 0)
  553.     {
  554.       gcp_pipe_index = 0;
  555.       gcp_pipe_timer = 
  556.         gtk_timeout_add (300, 
  557.                  (GtkFunction) gimp_context_preview_animate_pipe, 
  558.                  gcp);
  559.     }
  560.       break;
  561.  
  562.     case GCP_PATTERN:
  563.       gimp_context_preview_draw_pattern_popup (gcp);
  564.       break;
  565.  
  566.     case GCP_GRADIENT:
  567.       gimp_context_preview_draw_gradient_popup (gcp);
  568.       break;
  569.  
  570.     default:
  571.       break;
  572.     }  
  573.   gtk_widget_queue_draw (gcp_popup_preview);
  574.  
  575.   return FALSE;
  576. }
  577.  
  578.  
  579. static void
  580. gimp_context_preview_popup_open (GimpContextPreview *gcp,
  581.                  gint                x,
  582.                  gint                y)
  583. {
  584.   static popup_timeout_args_t popup_timeout_args;
  585.  
  586.   if (gcp_popup_timer != 0)
  587.     return;
  588.  
  589.   popup_timeout_args.gcp = gcp;
  590.   popup_timeout_args.x   = x;
  591.   popup_timeout_args.y   = y;
  592.   gcp_popup_timer = gtk_timeout_add (POPUP_DELAY_MS,
  593.                      gimp_context_preview_popup_timeout,
  594.                      &popup_timeout_args);
  595. }
  596.  
  597.   
  598. static void
  599. gimp_context_preview_popup_close (void)
  600. {
  601.   if (gcp_pipe_timer > 0)
  602.     gtk_timeout_remove (gcp_pipe_timer);
  603.   gcp_pipe_timer = 0;
  604.  
  605.   if (gcp_popup_timer)
  606.     gtk_timeout_remove (gcp_popup_timer);
  607.   gcp_popup_timer = 0;
  608.  
  609.   if (gcp_popup != NULL)
  610.     gtk_widget_hide (gcp_popup);
  611. }
  612.  
  613. static gboolean
  614. gimp_context_preview_data_matches_type (GimpContextPreview *gcp,
  615.                     gpointer            data)
  616. {
  617.   gboolean match = FALSE;
  618.  
  619.   g_return_val_if_fail (GIMP_IS_CONTEXT_PREVIEW (gcp), FALSE);
  620.  
  621.   switch (gcp->type)
  622.     {
  623.     case GCP_BRUSH:
  624.       match = GIMP_IS_BRUSH (data);
  625.       break;
  626.     case GCP_PATTERN:
  627.     case GCP_GRADIENT:
  628.       match = data != NULL;  /*  would be nicer if these were real gtk_objects  */
  629.       break;
  630.     default:
  631.       break;
  632.     }
  633.   return (match);
  634. }
  635.  
  636. /*  brush draw functions */
  637.  
  638. void
  639. draw_brush (GtkPreview *preview,
  640.         GimpBrush  *brush,
  641.         gint        width,
  642.         gint        height,
  643.         gboolean    is_popup)
  644. {
  645.   gboolean scale = FALSE;
  646.   gint brush_width, brush_height;
  647.   gint offset_x, offset_y;
  648.   TempBuf *mask_buf, *pixmap_buf = NULL;
  649.   guchar *mask, *buf, *b;
  650.   guchar bg;
  651.   gint x, y;
  652.  
  653.   mask_buf     = gimp_brush_get_mask (brush);
  654.   pixmap_buf   = gimp_brush_get_pixmap (brush);
  655.   brush_width  = mask_buf->width;
  656.   brush_height = mask_buf->height;
  657.  
  658.   if (brush_width > width || brush_height > height)
  659.     {
  660.       gdouble ratio_x = (gdouble)brush_width / width;
  661.       gdouble ratio_y = (gdouble)brush_height / height;
  662.       
  663.       brush_width =  (gdouble)brush_width / MAX (ratio_x, ratio_y) + 0.5; 
  664.       brush_height = (gdouble)brush_height / MAX (ratio_x, ratio_y) + 0.5;
  665.       
  666.       mask_buf = brush_scale_mask (mask_buf, brush_width, brush_height);
  667.       if (pixmap_buf)
  668.     {
  669.       /*  TODO: the scale function should scale the pixmap 
  670.           and the mask in one run                            */
  671.       pixmap_buf = brush_scale_pixmap (pixmap_buf, brush_width, brush_height);
  672.     }
  673.       scale = TRUE;
  674.     }
  675.  
  676.   offset_x = (width - brush_width) / 2;
  677.   offset_y = (height - brush_height) / 2;
  678.   
  679.   mask = temp_buf_data (mask_buf);
  680.   buf = g_new (guchar, 3 * width);
  681.   memset (buf, 255, 3 * width);
  682.  
  683.   if (pixmap_buf) 
  684.     {
  685.       guchar *pixmap = temp_buf_data (pixmap_buf);
  686.  
  687.       for (y = 0; y < offset_y; y++)
  688.     gtk_preview_draw_row (preview, buf, 0, y, width); 
  689.       for (y = offset_y; y < brush_height + offset_y; y++)
  690.     {
  691.       b = buf + 3 * offset_x;
  692.       for (x = 0; x < brush_width ; x++)
  693.         {
  694.           bg = (255 - *mask);
  695.           *b++ = bg + (*mask * *pixmap++) / 255;
  696.           *b++ = bg + (*mask * *pixmap++) / 255; 
  697.           *b++ = bg + (*mask * *pixmap++) / 255;
  698.           mask++;
  699.         }
  700.       gtk_preview_draw_row (preview, buf, 0, y, width); 
  701.     }
  702.       memset (buf, 255, 3 * width);
  703.       for (y = brush_height + offset_y; y < height; y++)
  704.     gtk_preview_draw_row (preview, buf, 0, y, width); 
  705.     }
  706.   else
  707.     {
  708.       for (y = 0; y < offset_y; y++)
  709.     gtk_preview_draw_row (preview, buf, 0, y, width); 
  710.       for (y = offset_y; y < brush_height + offset_y; y++)
  711.     {
  712.       b = buf + 3 * offset_x;
  713.       for (x = 0; x < brush_width ; x++)
  714.         {
  715.           bg = 255 - *mask++;
  716.           memset (b, bg, 3);
  717.           b += 3;
  718.         }   
  719.       gtk_preview_draw_row (preview, buf, 0, y, width); 
  720.     }
  721.       memset (buf, 255, 3 * width);
  722.       for (y = brush_height + offset_y; y < height; y++)
  723.     gtk_preview_draw_row (preview, buf, 0, y, width);    
  724.     }
  725.  
  726.   if (scale)
  727.     {
  728.       offset_x = width - indicator_width;
  729.       offset_y = height - indicator_height;
  730.       for (y = 0; y < indicator_height; y++)
  731.     (GIMP_IS_BRUSH_PIPE (brush)) ?
  732.       gtk_preview_draw_row (preview, scale_pipe_indicator_bits[y][0],
  733.                 offset_x, offset_y + y, indicator_width) :
  734.       gtk_preview_draw_row (preview, scale_indicator_bits[y][0],
  735.                 offset_x, offset_y + y, indicator_width);
  736.       temp_buf_free (mask_buf);
  737.       if (pixmap_buf)
  738.     temp_buf_free (pixmap_buf);
  739.     }
  740.   else if (!is_popup && GIMP_IS_BRUSH_PIPE (brush))
  741.     {
  742.       offset_x = width - indicator_width;
  743.       offset_y = height - indicator_height;
  744.       for (y = 0; y < indicator_height; y++)
  745.     gtk_preview_draw_row (preview, pipe_indicator_bits[y][0],
  746.                   offset_x, offset_y + y, indicator_width);
  747.     }
  748.  
  749.   g_free (buf);
  750. }
  751.  
  752. static void
  753. gimp_context_preview_draw_brush_popup (GimpContextPreview *gcp)
  754. {
  755.   GimpBrush *brush;
  756.  
  757.   g_return_if_fail (gcp != NULL && GIMP_IS_BRUSH (gcp->data));
  758.  
  759.   brush = GIMP_BRUSH (gcp->data);
  760.   draw_brush (GTK_PREVIEW (gcp_popup_preview), brush, 
  761.           gcp->popup_width, gcp->popup_height, TRUE);
  762. }
  763.  
  764. static void
  765. gimp_context_preview_draw_brush (GimpContextPreview *gcp)
  766. {
  767.   GimpBrush *brush;
  768.  
  769.   g_return_if_fail (gcp != NULL && GIMP_IS_BRUSH (gcp->data));
  770.  
  771.   brush = GIMP_BRUSH (gcp->data);
  772.   draw_brush (GTK_PREVIEW (gcp), brush, gcp->width, gcp->height, FALSE);
  773. }
  774.  
  775.  
  776. static gint
  777. gimp_context_preview_animate_pipe (GimpContextPreview *gcp)
  778. {
  779.   GimpBrushPipe *pipe;
  780.   GimpBrush *brush;
  781.  
  782.   g_return_val_if_fail (gcp != NULL && 
  783.             GIMP_IS_BRUSH_PIPE (gcp->data), FALSE);
  784.   if (gcp_popup != NULL && !GTK_WIDGET_VISIBLE (gcp_popup))
  785.     {
  786.       gcp_pipe_timer = 0;
  787.       return (FALSE);
  788.     }
  789.   
  790.   pipe = GIMP_BRUSH_PIPE (gcp->data);
  791.   if (++gcp_pipe_index >= pipe->nbrushes)
  792.     gcp_pipe_index = 0;
  793.   brush = GIMP_BRUSH (pipe->brushes[gcp_pipe_index]);
  794.   draw_brush (GTK_PREVIEW (gcp_popup_preview), brush,
  795.           gcp->popup_width, gcp->popup_height, TRUE);
  796.   gtk_widget_queue_draw (gcp_popup_preview);
  797.   
  798.   return (TRUE);
  799. }
  800.  
  801. /*  brush callbacks  */
  802. static gint 
  803. brush_dirty_callback (GimpBrush          *brush, 
  804.               GimpContextPreview *gcp)
  805. {
  806.   gimp_context_preview_draw_brush (gcp);
  807.   gtk_widget_queue_draw (GTK_WIDGET (gcp));
  808.  
  809.   return TRUE;
  810. }
  811.  
  812. static gint 
  813. brush_rename_callback (GimpBrush          *brush, 
  814.                GimpContextPreview *gcp)
  815. {
  816.   if (gcp->show_tooltips)
  817.     gimp_help_set_help_data (GTK_WIDGET (gcp), brush->name, NULL);
  818.  
  819.   return TRUE;
  820. }
  821.  
  822.  
  823. /*  pattern draw functions */
  824.  
  825. void
  826. draw_pattern (GtkPreview *preview,
  827.           GPattern   *pattern,
  828.           gint        width,
  829.           gint        height)
  830. {
  831.   gint pattern_width, pattern_height;
  832.   guchar *mask, *src, *buf, *b;
  833.   gint x, y;
  834.  
  835.   pattern_width = pattern->mask->width;
  836.   pattern_height = pattern->mask->height;
  837.  
  838.   mask = temp_buf_data (pattern->mask);
  839.   buf = g_new (guchar, 3 * width);
  840.   if (pattern->mask->bytes == 1) 
  841.     {
  842.       for (y = 0; y < height; y++)
  843.     {
  844.       b = buf;
  845.       src = mask + (pattern_width * (y % pattern_height));
  846.       for (x = 0; x < width ; x++)
  847.         {
  848.           memset (b, src[x % pattern_width], 3);
  849.           b += 3;
  850.         }
  851.       gtk_preview_draw_row (preview, buf, 0, y, width);
  852.     }
  853.     }
  854.   else
  855.     {
  856.       for (y = 0; y < height; y++)
  857.     {
  858.       b = buf;
  859.       src = mask + 3 * (pattern_width * (y % pattern_height));
  860.       for (x = 0; x < width ; x++)
  861.         {
  862.           memcpy (b, src + 3 * (x % pattern_width), 3);
  863.           b += 3;
  864.         }
  865.       gtk_preview_draw_row (preview, buf, 0, y, width); 
  866.     }
  867.     }
  868.   g_free(buf);
  869. }
  870.  
  871. static void
  872. gimp_context_preview_draw_pattern_popup (GimpContextPreview *gcp)
  873. {
  874.   GPattern *pattern;
  875.  
  876.   g_return_if_fail (gcp != NULL && gcp->data != NULL);
  877.  
  878.   pattern = (GPattern*)(gcp->data);
  879.   draw_pattern (GTK_PREVIEW (gcp_popup_preview), pattern, 
  880.         gcp->popup_width, gcp->popup_height);
  881. }
  882.  
  883. static void
  884. gimp_context_preview_draw_pattern (GimpContextPreview *gcp)
  885. {
  886.   GPattern *pattern;
  887.  
  888.   g_return_if_fail (gcp != NULL && gcp->data != NULL);
  889.  
  890.   pattern = (GPattern*)(gcp->data);
  891.   draw_pattern (GTK_PREVIEW (gcp), pattern, gcp->width, gcp->height);
  892. }
  893.  
  894.  
  895. /*  gradient draw functions  */
  896.  
  897. void
  898. draw_gradient (GtkPreview *preview, 
  899.            gradient_t *gradient,
  900.            gint        width,
  901.            gint        height)
  902. {
  903.   guchar *p0, *p1, *even, *odd;
  904.   gint x, y;
  905.   gdouble dx, cur_x;
  906.   gdouble r, g, b, a;
  907.   gdouble c0, c1;
  908.  
  909.   dx    = 1.0 / (width - 1);
  910.   cur_x = 0.0;
  911.   p0    = even = g_new (guchar, 3 * width);
  912.   p1    = odd  = g_new (guchar, 3 * width);
  913.  
  914.   for (x = 0; x < width; x++) 
  915.     {
  916.       gradient_get_color_at (gradient, cur_x, &r, &g, &b, &a);
  917.     
  918.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  919.     {
  920.       c0 = GIMP_CHECK_LIGHT;
  921.       c1 = GIMP_CHECK_DARK;
  922.     } 
  923.       else 
  924.     {
  925.       c0 = GIMP_CHECK_DARK;
  926.       c1 = GIMP_CHECK_LIGHT;
  927.     }
  928.  
  929.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  930.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  931.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  932.       
  933.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  934.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  935.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  936.       
  937.       cur_x += dx;
  938.     }
  939.  
  940.   for (y = 0; y < height; y++)
  941.     {
  942.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  943.     gtk_preview_draw_row (preview, odd, 0, y, width);
  944.       else
  945.     gtk_preview_draw_row (preview, even, 0, y, width);
  946.     }
  947.  
  948.   g_free (odd);
  949.   g_free (even);
  950. }
  951.  
  952. static void
  953. gimp_context_preview_draw_gradient_popup (GimpContextPreview *gcp)
  954. {
  955.   gradient_t *gradient;
  956.  
  957.   g_return_if_fail (gcp != NULL && gcp->data != NULL);
  958.   
  959.   gradient = (gradient_t*)(gcp->data);
  960.   draw_gradient (GTK_PREVIEW (gcp_popup_preview), gradient, 
  961.          gcp->popup_width, gcp->popup_height);
  962. }
  963.  
  964. static void
  965. gimp_context_preview_draw_gradient (GimpContextPreview *gcp)
  966. {
  967.   gradient_t *gradient;
  968.  
  969.   g_return_if_fail (gcp != NULL && gcp->data != NULL);
  970.  
  971.   gradient = (gradient_t*)(gcp->data);
  972.   draw_gradient (GTK_PREVIEW (gcp), gradient, gcp->width, gcp->height);
  973. }
  974.