~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to libgimp/gimpbrushselectbutton.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* LIBGIMP - The GIMP Library
 
2
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 
3
 *
 
4
 * gimpbrushselectbutton.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 "config.h"
 
24
 
 
25
#include <gtk/gtk.h>
 
26
 
 
27
#include "libgimpwidgets/gimpwidgets.h"
 
28
 
 
29
#include "gimp.h"
 
30
 
 
31
#include "gimpuitypes.h"
 
32
#include "gimpbrushselectbutton.h"
 
33
#include "gimpuimarshal.h"
 
34
 
 
35
#include "libgimp-intl.h"
 
36
 
 
37
 
 
38
#define CELL_SIZE 20
 
39
 
 
40
 
 
41
#define GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GIMP_TYPE_BRUSH_SELECT_BUTTON, GimpBrushSelectButtonPrivate))
 
42
 
 
43
typedef struct _GimpBrushSelectButtonPrivate GimpBrushSelectButtonPrivate;
 
44
 
 
45
struct _GimpBrushSelectButtonPrivate
 
46
{
 
47
  gchar                *title;
 
48
 
 
49
  gchar                *brush_name;      /* Local copy */
 
50
  gdouble               opacity;
 
51
  gint                  spacing;
 
52
  GimpLayerModeEffects  paint_mode;
 
53
  gint                  width;
 
54
  gint                  height;
 
55
  guchar               *mask_data;       /* local copy */
 
56
 
 
57
  GtkWidget            *inside;
 
58
  GtkWidget            *preview;
 
59
  GtkWidget            *popup;
 
60
};
 
61
 
 
62
enum
 
63
{
 
64
  BRUSH_SET,
 
65
  LAST_SIGNAL
 
66
};
 
67
 
 
68
enum
 
69
{
 
70
  PROP_0,
 
71
  PROP_TITLE,
 
72
  PROP_BRUSH_NAME,
 
73
  PROP_BRUSH_OPACITY,
 
74
  PROP_BRUSH_SPACING,
 
75
  PROP_BRUSH_PAINT_MODE
 
76
};
 
77
 
 
78
 
 
79
/*  local function prototypes  */
 
80
 
 
81
static void   gimp_brush_select_button_finalize     (GObject      *object);
 
82
 
 
83
static void   gimp_brush_select_button_set_property (GObject      *object,
 
84
                                                     guint         property_id,
 
85
                                                     const GValue *value,
 
86
                                                     GParamSpec   *pspec);
 
87
static void   gimp_brush_select_button_get_property (GObject      *object,
 
88
                                                     guint         property_id,
 
89
                                                     GValue       *value,
 
90
                                                     GParamSpec   *pspec);
 
91
 
 
92
static void   gimp_brush_select_button_clicked  (GimpBrushSelectButton *button);
 
93
 
 
94
static void   gimp_brush_select_button_callback (const gchar          *brush_name,
 
95
                                                 gdouble               opacity,
 
96
                                                 gint                  spacing,
 
97
                                                 GimpLayerModeEffects  paint_mode,
 
98
                                                 gint                  width,
 
99
                                                 gint                  height,
 
100
                                                 const guchar         *mask_data,
 
101
                                                 gboolean              dialog_closing,
 
102
                                                 gpointer              user_data);
 
103
 
 
104
static void     gimp_brush_select_preview_resize  (GimpBrushSelectButton *button);
 
105
static gboolean gimp_brush_select_preview_events  (GtkWidget             *widget,
 
106
                                                   GdkEvent              *event,
 
107
                                                   GimpBrushSelectButton *button);
 
108
static void     gimp_brush_select_preview_draw    (GimpPreviewArea       *area,
 
109
                                                   gint                   x,
 
110
                                                   gint                   y,
 
111
                                                   gint                   width,
 
112
                                                   gint                   height,
 
113
                                                   const guchar          *mask_data,
 
114
                                                   gint                   rowstride);
 
115
static void     gimp_brush_select_preview_update  (GtkWidget             *preview,
 
116
                                                   gint                   brush_width,
 
117
                                                   gint                   brush_height,
 
118
                                                   const guchar          *mask_data);
 
119
 
 
120
static void     gimp_brush_select_button_open_popup  (GimpBrushSelectButton *button,
 
121
                                                      gint                   x,
 
122
                                                      gint                   y);
 
123
static void     gimp_brush_select_button_close_popup (GimpBrushSelectButton *button);
 
124
 
 
125
static void   gimp_brush_select_drag_data_received (GimpBrushSelectButton *button,
 
126
                                                    GdkDragContext        *context,
 
127
                                                    gint                   x,
 
128
                                                    gint                   y,
 
129
                                                    GtkSelectionData      *selection,
 
130
                                                    guint                  info,
 
131
                                                    guint                  time);
 
132
 
 
133
static GtkWidget * gimp_brush_select_button_create_inside (GimpBrushSelectButton *button);
 
134
 
 
135
 
 
136
static const GtkTargetEntry target = { "application/x-gimp-brush-name", 0 };
 
137
 
 
138
static guint brush_button_signals[LAST_SIGNAL] = { 0 };
 
139
 
 
140
 
 
141
G_DEFINE_TYPE (GimpBrushSelectButton, gimp_brush_select_button,
 
142
               GIMP_TYPE_SELECT_BUTTON)
 
143
 
 
144
 
 
145
static void
 
146
gimp_brush_select_button_class_init (GimpBrushSelectButtonClass *klass)
 
147
{
 
148
  GObjectClass          *object_class        = G_OBJECT_CLASS (klass);
 
149
  GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass);
 
150
 
 
151
  object_class->finalize     = gimp_brush_select_button_finalize;
 
152
  object_class->set_property = gimp_brush_select_button_set_property;
 
153
  object_class->get_property = gimp_brush_select_button_get_property;
 
154
 
 
155
  select_button_class->select_destroy = gimp_brush_select_destroy;
 
156
 
 
157
  klass->brush_set = NULL;
 
158
 
 
159
  /**
 
160
   * GimpBrushSelectButton:title:
 
161
   *
 
162
   * The title to be used for the brush selection popup dialog.
 
163
   *
 
164
   * Since: GIMP 2.4
 
165
   */
 
166
  g_object_class_install_property (object_class, PROP_TITLE,
 
167
                                   g_param_spec_string ("title",
 
168
                                                        "Title",
 
169
                                                        "The title to be used for the brush selection popup dialog",
 
170
                                                        _("Brush Selection"),
 
171
                                                        GIMP_PARAM_READWRITE |
 
172
                                                        G_PARAM_CONSTRUCT_ONLY));
 
173
 
 
174
  /**
 
175
   * GimpBrushSelectButton:brush-name:
 
176
   *
 
177
   * The name of the currently selected brush.
 
178
   *
 
179
   * Since: GIMP 2.4
 
180
   */
 
181
  g_object_class_install_property (object_class, PROP_BRUSH_NAME,
 
182
                                   g_param_spec_string ("brush-name",
 
183
                                                        "Brush name",
 
184
                                                        "The name of the currently selected brush",
 
185
                                                        NULL,
 
186
                                                        GIMP_PARAM_READWRITE));
 
187
 
 
188
  /**
 
189
   * GimpBrushSelectButton:opacity:
 
190
   *
 
191
   * The opacity of the currently selected brush.
 
192
   *
 
193
   * Since: GIMP 2.4
 
194
   */
 
195
  g_object_class_install_property (object_class, PROP_BRUSH_OPACITY,
 
196
                                   g_param_spec_double ("brush-opacity",
 
197
                                                        "Brush opacity",
 
198
                                                        "The opacity of the currently selected brush",
 
199
                                                        -1.0, 100.0, -1.0,
 
200
                                                        GIMP_PARAM_READWRITE));
 
201
 
 
202
  /**
 
203
   * GimpBrushSelectButton:spacing:
 
204
   *
 
205
   * The spacing of the currently selected brush.
 
206
   *
 
207
   * Since: GIMP 2.4
 
208
   */
 
209
  g_object_class_install_property (object_class, PROP_BRUSH_SPACING,
 
210
                                   g_param_spec_int ("brush-spacing",
 
211
                                                     "Brush spacing",
 
212
                                                     "The spacing of the currently selected brush",
 
213
                                                     -G_MAXINT, 1000, -1,
 
214
                                                     GIMP_PARAM_READWRITE));
 
215
 
 
216
  /**
 
217
   * GimpBrushSelectButton:paint-mode:
 
218
   *
 
219
   * The name of the currently selected brush.
 
220
   *
 
221
   * Since: GIMP 2.4
 
222
   */
 
223
  g_object_class_install_property (object_class, PROP_BRUSH_PAINT_MODE,
 
224
                                   g_param_spec_int ("brush-paint-mode",
 
225
                                                     "Brush paint mode",
 
226
                                                     "The paint mode of the currently selected brush",
 
227
                                                     -1, GIMP_COLOR_ERASE_MODE,
 
228
                                                     -1,
 
229
                                                     GIMP_PARAM_READWRITE));
 
230
 
 
231
  /**
 
232
   * GimpBrushSelectButton::brush-set:
 
233
   * @widget: the object which received the signal.
 
234
   * @brush_name: the name of the currently selected brush.
 
235
   * @opacity: opacity of the brush
 
236
   * @spacing: spacing of the brush
 
237
   * @paint_mode: paint mode of the brush
 
238
   * @width: width of the brush
 
239
   * @height: height of the brush
 
240
   * @mask_data: brush mask data
 
241
   * @dialog_closing: whether the dialog was closed or not.
 
242
   *
 
243
   * The ::brush-set signal is emitted when the user selects a brush.
 
244
   *
 
245
   * Since: GIMP 2.4
 
246
   */
 
247
  brush_button_signals[BRUSH_SET] =
 
248
    g_signal_new ("brush-set",
 
249
                  G_TYPE_FROM_CLASS (klass),
 
250
                  G_SIGNAL_RUN_FIRST,
 
251
                  G_STRUCT_OFFSET (GimpBrushSelectButtonClass, brush_set),
 
252
                  NULL, NULL,
 
253
                  _gimpui_marshal_VOID__STRING_DOUBLE_INT_INT_INT_INT_POINTER_BOOLEAN,
 
254
                  G_TYPE_NONE, 8,
 
255
                  G_TYPE_STRING,
 
256
                  G_TYPE_DOUBLE,
 
257
                  G_TYPE_INT,
 
258
                  G_TYPE_INT,
 
259
                  G_TYPE_INT,
 
260
                  G_TYPE_INT,
 
261
                  G_TYPE_POINTER,
 
262
                  G_TYPE_BOOLEAN);
 
263
 
 
264
  g_type_class_add_private (object_class,
 
265
                            sizeof (GimpBrushSelectButtonPrivate));
 
266
}
 
267
 
 
268
static void
 
269
gimp_brush_select_button_init (GimpBrushSelectButton *button)
 
270
{
 
271
  GimpBrushSelectButtonPrivate *priv;
 
272
  gint                          mask_bpp;
 
273
  gint                          mask_data_size;
 
274
  gint                          color_bpp;
 
275
  gint                          color_data_size;
 
276
  guint8                       *color_data;
 
277
 
 
278
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
279
 
 
280
  priv->brush_name = gimp_context_get_brush ();
 
281
  gimp_brush_get_pixels (priv->brush_name,
 
282
                         &priv->width,
 
283
                         &priv->height,
 
284
                         &mask_bpp,
 
285
                         &mask_data_size,
 
286
                         &priv->mask_data,
 
287
                         &color_bpp,
 
288
                         &color_data_size,
 
289
                         &color_data);
 
290
 
 
291
  if (color_data)
 
292
    g_free (color_data);
 
293
 
 
294
  priv->inside = gimp_brush_select_button_create_inside (button);
 
295
  gtk_container_add (GTK_CONTAINER (button), priv->inside);
 
296
 
 
297
  priv->popup = NULL;
 
298
}
 
299
 
 
300
/**
 
301
 * gimp_brush_select_button_new:
 
302
 * @title:      Title of the dialog to use or %NULL means to use the default
 
303
 *              title.
 
304
 * @brush_name: Initial brush name or %NULL to use current selection.
 
305
 * @opacity:    Initial opacity. -1 means to use current opacity.
 
306
 * @spacing:    Initial spacing. -1 means to use current spacing.
 
307
 * @paint_mode: Initial paint mode.  -1 means to use current paint mode.
 
308
 *
 
309
 * Creates a new #GtkWidget that completely controls the selection of
 
310
 * a #GimpBrush.  This widget is suitable for placement in a table in
 
311
 * a plug-in dialog.
 
312
 *
 
313
 * Returns: A #GtkWidget that you can use in your UI.
 
314
 *
 
315
 * Since: GIMP 2.4
 
316
 */
 
317
GtkWidget *
 
318
gimp_brush_select_button_new (const gchar          *title,
 
319
                              const gchar          *brush_name,
 
320
                              gdouble               opacity,
 
321
                              gint                  spacing,
 
322
                              GimpLayerModeEffects  paint_mode)
 
323
{
 
324
  GtkWidget *button;
 
325
 
 
326
  if (title)
 
327
    button = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON,
 
328
                           "title",            title,
 
329
                           "brush-name",       brush_name,
 
330
                           "brush-opacity",    opacity,
 
331
                           "brush-spacing",    spacing,
 
332
                           "brush-paint-mode", paint_mode,
 
333
                           NULL);
 
334
  else
 
335
    button = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON,
 
336
                           "brush-name",       brush_name,
 
337
                           "brush-opacity",    opacity,
 
338
                           "brush-spacing",    spacing,
 
339
                           "brush-paint-mode", paint_mode,
 
340
                           NULL);
 
341
 
 
342
  return button;
 
343
}
 
344
 
 
345
/**
 
346
 * gimp_brush_select_button_get_brush:
 
347
 * @button: A #GimpBrushSelectButton
 
348
 * @opacity: Opacity of the selected brush.
 
349
 * @spacing: Spacing of the selected brush.
 
350
 * @paint_mode: Paint mode of the selected brush.
 
351
 *
 
352
 * Retrieves the properties of currently selected brush.
 
353
 *
 
354
 * Returns: an internal copy of the brush name which must not be freed.
 
355
 *
 
356
 * Since: GIMP 2.4
 
357
 */
 
358
const gchar *
 
359
gimp_brush_select_button_get_brush (GimpBrushSelectButton *button,
 
360
                                    gdouble               *opacity,
 
361
                                    gint                  *spacing,
 
362
                                    GimpLayerModeEffects  *paint_mode)
 
363
{
 
364
  GimpBrushSelectButtonPrivate *priv;
 
365
 
 
366
  g_return_val_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (button), NULL);
 
367
 
 
368
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
369
 
 
370
  if (opacity)
 
371
    *opacity = priv->opacity;
 
372
 
 
373
  if (spacing)
 
374
    *spacing = priv->spacing;
 
375
 
 
376
  if (paint_mode)
 
377
    *paint_mode = priv->paint_mode;
 
378
 
 
379
  return priv->brush_name;
 
380
}
 
381
 
 
382
/**
 
383
 * gimp_brush_select_button_set_brush:
 
384
 * @button: A #GimpBrushSelectButton
 
385
 * @brush_name: Brush name to set; %NULL means no change.
 
386
 * @opacity:    Opacity to set. -1.0 means no change.
 
387
 * @spacing:    Spacing to set. -1 means no change.
 
388
 * @paint_mode: Paint mode to set.  -1 means no change.
 
389
 *
 
390
 * Sets the current brush and other values for the brush select
 
391
 * button.
 
392
 *
 
393
 * Since: GIMP 2.4
 
394
 */
 
395
void
 
396
gimp_brush_select_button_set_brush (GimpBrushSelectButton *button,
 
397
                                    const gchar           *brush_name,
 
398
                                    gdouble                opacity,
 
399
                                    gint                   spacing,
 
400
                                    GimpLayerModeEffects   paint_mode)
 
401
{
 
402
  GimpSelectButton *select_button;
 
403
 
 
404
  g_return_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (button));
 
405
 
 
406
  select_button = GIMP_SELECT_BUTTON (button);
 
407
 
 
408
  if (select_button->temp_callback)
 
409
    {
 
410
      gimp_brushes_set_popup (select_button->temp_callback, brush_name,
 
411
                              opacity, spacing, paint_mode);
 
412
    }
 
413
  else
 
414
    {
 
415
      gchar  *name;
 
416
      gint    width;
 
417
      gint    height;
 
418
      gint    bytes;
 
419
      gint    mask_data_size;
 
420
      guint8 *mask_data;
 
421
      gint    color_bpp;
 
422
      gint    color_data_size;
 
423
      guint8 *color_data;
 
424
 
 
425
      if (brush_name && *brush_name)
 
426
        name = g_strdup (brush_name);
 
427
      else
 
428
        name = gimp_context_get_brush ();
 
429
 
 
430
      if (gimp_brush_get_pixels (name,
 
431
                                 &width,
 
432
                                 &height,
 
433
                                 &bytes,
 
434
                                 &mask_data_size,
 
435
                                 &mask_data,
 
436
                                 &color_bpp,
 
437
                                 &color_data_size,
 
438
                                 &color_data))
 
439
        {
 
440
          if (color_data)
 
441
            g_free (color_data);
 
442
 
 
443
          if (opacity < 0.0)
 
444
            opacity = gimp_context_get_opacity ();
 
445
 
 
446
          if (spacing == -1)
 
447
            gimp_brush_get_spacing (name, &spacing);
 
448
 
 
449
          if (paint_mode == -1)
 
450
            paint_mode = gimp_context_get_paint_mode ();
 
451
 
 
452
          gimp_brush_select_button_callback (name,
 
453
                                             opacity, spacing, paint_mode,
 
454
                                             width, height, mask_data,
 
455
                                             FALSE, button);
 
456
 
 
457
          g_free (mask_data);
 
458
        }
 
459
 
 
460
      g_free (name);
 
461
    }
 
462
}
 
463
 
 
464
 
 
465
/*  private functions  */
 
466
 
 
467
static void
 
468
gimp_brush_select_button_finalize (GObject *object)
 
469
{
 
470
  GimpBrushSelectButtonPrivate *priv;
 
471
 
 
472
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (object);
 
473
 
 
474
  g_free (priv->brush_name);
 
475
  priv->brush_name = NULL;
 
476
 
 
477
  g_free (priv->mask_data);
 
478
  priv->mask_data = NULL;
 
479
 
 
480
  g_free (priv->title);
 
481
  priv->title = NULL;
 
482
 
 
483
  G_OBJECT_CLASS (gimp_brush_select_button_parent_class)->finalize (object);
 
484
}
 
485
 
 
486
static void
 
487
gimp_brush_select_button_set_property (GObject      *object,
 
488
                                       guint         property_id,
 
489
                                       const GValue *value,
 
490
                                       GParamSpec   *pspec)
 
491
{
 
492
  GimpBrushSelectButton        *button = GIMP_BRUSH_SELECT_BUTTON (object);
 
493
  GimpBrushSelectButtonPrivate *priv;
 
494
  gdouble opacity;
 
495
  gint32 spacing;
 
496
  gint32 paint_mode;
 
497
 
 
498
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
499
 
 
500
  switch (property_id)
 
501
    {
 
502
    case PROP_TITLE:
 
503
      priv->title = g_value_dup_string (value);
 
504
      break;
 
505
    case PROP_BRUSH_NAME:
 
506
      gimp_brush_select_button_set_brush (button,
 
507
                                          g_value_get_string (value),
 
508
                                          -1.0, -1, -1);
 
509
      break;
 
510
    case PROP_BRUSH_OPACITY:
 
511
      opacity = g_value_get_double (value);
 
512
      if (opacity >= 0.0)
 
513
        priv->opacity = opacity;
 
514
      break;
 
515
    case PROP_BRUSH_SPACING:
 
516
      spacing = g_value_get_int (value);
 
517
      if (spacing != -1)
 
518
        priv->spacing = spacing;
 
519
      break;
 
520
    case PROP_BRUSH_PAINT_MODE:
 
521
      paint_mode = g_value_get_int (value);
 
522
      if (paint_mode != -1)
 
523
        priv->paint_mode = paint_mode;
 
524
      break;
 
525
    default:
 
526
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
527
      break;
 
528
    }
 
529
}
 
530
 
 
531
static void
 
532
gimp_brush_select_button_get_property (GObject    *object,
 
533
                                       guint       property_id,
 
534
                                       GValue     *value,
 
535
                                       GParamSpec *pspec)
 
536
{
 
537
  GimpBrushSelectButton        *button = GIMP_BRUSH_SELECT_BUTTON (object);
 
538
  GimpBrushSelectButtonPrivate *priv;
 
539
 
 
540
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
541
 
 
542
  switch (property_id)
 
543
    {
 
544
    case PROP_TITLE:
 
545
      g_value_set_string (value, priv->title);
 
546
      break;
 
547
    case PROP_BRUSH_NAME:
 
548
      g_value_set_string (value, priv->brush_name);
 
549
      break;
 
550
    case PROP_BRUSH_OPACITY:
 
551
      g_value_set_double (value, priv->opacity);
 
552
      break;
 
553
    case PROP_BRUSH_SPACING:
 
554
      g_value_set_int (value, priv->spacing);
 
555
      break;
 
556
    case PROP_BRUSH_PAINT_MODE:
 
557
      g_value_set_int (value, priv->paint_mode);
 
558
      break;
 
559
    default:
 
560
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
561
      break;
 
562
    }
 
563
}
 
564
 
 
565
static void
 
566
gimp_brush_select_button_callback (const gchar          *name,
 
567
                                   gdouble               opacity,
 
568
                                   gint                  spacing,
 
569
                                   GimpLayerModeEffects  paint_mode,
 
570
                                   gint                  width,
 
571
                                   gint                  height,
 
572
                                   const guchar         *mask_data,
 
573
                                   gboolean              dialog_closing,
 
574
                                   gpointer              data)
 
575
{
 
576
  GimpBrushSelectButton        *button;
 
577
  GimpBrushSelectButtonPrivate *priv;
 
578
  GimpSelectButton             *select_button;
 
579
 
 
580
  button = GIMP_BRUSH_SELECT_BUTTON (data);
 
581
 
 
582
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
583
  select_button = GIMP_SELECT_BUTTON (button);
 
584
 
 
585
  g_free (priv->brush_name);
 
586
  g_free (priv->mask_data);
 
587
 
 
588
  priv->brush_name = g_strdup (name);
 
589
  priv->width      = width;
 
590
  priv->height     = height;
 
591
  priv->mask_data  = g_memdup (mask_data, width * height);
 
592
  priv->opacity    = opacity;
 
593
  priv->spacing    = spacing;
 
594
  priv->paint_mode = paint_mode;
 
595
 
 
596
  gimp_brush_select_preview_update (priv->preview,
 
597
                                    width, height, mask_data);
 
598
 
 
599
  if (dialog_closing)
 
600
    select_button->temp_callback = NULL;
 
601
 
 
602
  g_signal_emit (button, brush_button_signals[BRUSH_SET], 0,
 
603
                 name, opacity, spacing, paint_mode, width, height, mask_data,
 
604
                 dialog_closing);
 
605
  g_object_notify (G_OBJECT (button), "brush-name");
 
606
}
 
607
 
 
608
static void
 
609
gimp_brush_select_button_clicked (GimpBrushSelectButton *button)
 
610
{
 
611
  GimpBrushSelectButtonPrivate *priv;
 
612
  GimpSelectButton             *select_button;
 
613
 
 
614
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
615
  select_button = GIMP_SELECT_BUTTON (button);
 
616
 
 
617
  if (select_button->temp_callback)
 
618
    {
 
619
      /*  calling gimp_brushes_set_popup() raises the dialog  */
 
620
      gimp_brushes_set_popup (select_button->temp_callback,
 
621
                              priv->brush_name,
 
622
                              priv->opacity,
 
623
                              priv->spacing,
 
624
                              priv->paint_mode);
 
625
    }
 
626
  else
 
627
    {
 
628
      select_button->temp_callback =
 
629
        gimp_brush_select_new (priv->title, priv->brush_name,
 
630
                               priv->opacity, priv->spacing, priv->paint_mode,
 
631
                               gimp_brush_select_button_callback,
 
632
                               button);
 
633
    }
 
634
}
 
635
 
 
636
static void
 
637
gimp_brush_select_preview_resize (GimpBrushSelectButton *button)
 
638
{
 
639
  GimpBrushSelectButtonPrivate *priv;
 
640
 
 
641
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
642
 
 
643
  if (priv->width > 0 && priv->height > 0)
 
644
    gimp_brush_select_preview_update (priv->preview,
 
645
                                      priv->width,
 
646
                                      priv->height,
 
647
                                      priv->mask_data);
 
648
}
 
649
 
 
650
static gboolean
 
651
gimp_brush_select_preview_events (GtkWidget             *widget,
 
652
                                  GdkEvent              *event,
 
653
                                  GimpBrushSelectButton *button)
 
654
{
 
655
  GimpBrushSelectButtonPrivate *priv;
 
656
  GdkEventButton               *bevent;
 
657
 
 
658
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
659
 
 
660
  if (priv->mask_data)
 
661
    {
 
662
      switch (event->type)
 
663
        {
 
664
        case GDK_BUTTON_PRESS:
 
665
          bevent = (GdkEventButton *) event;
 
666
 
 
667
          if (bevent->button == 1)
 
668
            {
 
669
              gtk_grab_add (widget);
 
670
              gimp_brush_select_button_open_popup (button,
 
671
                                                   bevent->x, bevent->y);
 
672
            }
 
673
          break;
 
674
 
 
675
        case GDK_BUTTON_RELEASE:
 
676
          bevent = (GdkEventButton *) event;
 
677
 
 
678
          if (bevent->button == 1)
 
679
            {
 
680
              gtk_grab_remove (widget);
 
681
              gimp_brush_select_button_close_popup (button);
 
682
            }
 
683
          break;
 
684
 
 
685
        default:
 
686
          break;
 
687
        }
 
688
    }
 
689
 
 
690
  return FALSE;
 
691
}
 
692
 
 
693
static void
 
694
gimp_brush_select_preview_draw (GimpPreviewArea *area,
 
695
                                gint             x,
 
696
                                gint             y,
 
697
                                gint             width,
 
698
                                gint             height,
 
699
                                const guchar    *mask_data,
 
700
                                gint             rowstride)
 
701
{
 
702
  const guchar *src;
 
703
  guchar       *dest;
 
704
  guchar       *buf;
 
705
  gint          i, j;
 
706
 
 
707
  buf = g_new (guchar, width * height);
 
708
 
 
709
  src  = mask_data;
 
710
  dest = buf;
 
711
 
 
712
  for (j = 0; j < height; j++)
 
713
    {
 
714
      const guchar *s = src;
 
715
 
 
716
      for (i = 0; i < width; i++, s++, dest++)
 
717
        *dest = 255 - *s;
 
718
 
 
719
      src += rowstride;
 
720
    }
 
721
 
 
722
  gimp_preview_area_draw (area,
 
723
                          x, y, width, height,
 
724
                          GIMP_GRAY_IMAGE,
 
725
                          buf,
 
726
                          width);
 
727
 
 
728
  g_free (buf);
 
729
}
 
730
 
 
731
static void
 
732
gimp_brush_select_preview_update (GtkWidget    *preview,
 
733
                                  gint          brush_width,
 
734
                                  gint          brush_height,
 
735
                                  const guchar *mask_data)
 
736
{
 
737
  GimpPreviewArea *area = GIMP_PREVIEW_AREA (preview);
 
738
  gint             x, y;
 
739
  gint             width, height;
 
740
 
 
741
  width  = MIN (brush_width,  preview->allocation.width);
 
742
  height = MIN (brush_height, preview->allocation.height);
 
743
 
 
744
  x = ((preview->allocation.width  - width)  / 2);
 
745
  y = ((preview->allocation.height - height) / 2);
 
746
 
 
747
  if (x || y)
 
748
    gimp_preview_area_fill (area,
 
749
                            0, 0,
 
750
                            preview->allocation.width,
 
751
                            preview->allocation.height,
 
752
                            0xFF, 0xFF, 0xFF);
 
753
 
 
754
  gimp_brush_select_preview_draw (area,
 
755
                                  x, y, width, height,
 
756
                                  mask_data, brush_width);
 
757
}
 
758
 
 
759
static void
 
760
gimp_brush_select_button_open_popup (GimpBrushSelectButton *button,
 
761
                                     gint                   x,
 
762
                                     gint                   y)
 
763
{
 
764
  GimpBrushSelectButtonPrivate *priv;
 
765
  GtkWidget                    *frame;
 
766
  GtkWidget                    *preview;
 
767
  GdkScreen                    *screen;
 
768
  gint                          x_org;
 
769
  gint                          y_org;
 
770
  gint                          scr_w;
 
771
  gint                          scr_h;
 
772
 
 
773
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
774
 
 
775
  if (priv->popup)
 
776
    gimp_brush_select_button_close_popup (button);
 
777
 
 
778
  if (priv->width <= CELL_SIZE && priv->height <= CELL_SIZE)
 
779
    return;
 
780
 
 
781
  priv->popup = gtk_window_new (GTK_WINDOW_POPUP);
 
782
 
 
783
  frame = gtk_frame_new (NULL);
 
784
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
 
785
  gtk_container_add (GTK_CONTAINER (priv->popup), frame);
 
786
  gtk_widget_show (frame);
 
787
 
 
788
  preview = gimp_preview_area_new ();
 
789
  gtk_widget_set_size_request (preview, priv->width, priv->height);
 
790
  gtk_container_add (GTK_CONTAINER (frame), preview);
 
791
  gtk_widget_show (preview);
 
792
 
 
793
  /* decide where to put the popup */
 
794
  gdk_window_get_origin (priv->preview->window, &x_org, &y_org);
 
795
 
 
796
  screen = gtk_widget_get_screen (priv->popup);
 
797
 
 
798
  scr_w = gdk_screen_get_width (screen);
 
799
  scr_h = gdk_screen_get_height (screen);
 
800
 
 
801
  x = x_org + x - (priv->width  / 2);
 
802
  y = y_org + y - (priv->height / 2);
 
803
  x = (x < 0) ? 0 : x;
 
804
  y = (y < 0) ? 0 : y;
 
805
  x = (x + priv->width  > scr_w) ? scr_w - priv->width  : x;
 
806
  y = (y + priv->height > scr_h) ? scr_h - priv->height : y;
 
807
 
 
808
  gtk_window_move (GTK_WINDOW (priv->popup), x, y);
 
809
 
 
810
  gtk_widget_show (priv->popup);
 
811
 
 
812
  /*  Draw the brush  */
 
813
  gimp_brush_select_preview_draw (GIMP_PREVIEW_AREA (preview),
 
814
                                  0, 0, priv->width, priv->height,
 
815
                                  priv->mask_data, priv->width);
 
816
}
 
817
 
 
818
static void
 
819
gimp_brush_select_button_close_popup (GimpBrushSelectButton *button)
 
820
{
 
821
  GimpBrushSelectButtonPrivate *priv;
 
822
 
 
823
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (button);
 
824
 
 
825
  if (priv->popup)
 
826
    {
 
827
      gtk_widget_destroy (priv->popup);
 
828
      priv->popup = NULL;
 
829
    }
 
830
}
 
831
 
 
832
static void
 
833
gimp_brush_select_drag_data_received (GimpBrushSelectButton *button,
 
834
                                      GdkDragContext        *context,
 
835
                                      gint                   x,
 
836
                                      gint                   y,
 
837
                                      GtkSelectionData      *selection,
 
838
                                      guint                  info,
 
839
                                      guint                  time)
 
840
{
 
841
  gchar *str;
 
842
 
 
843
  if ((selection->format != 8) || (selection->length < 1))
 
844
    {
 
845
      g_warning ("Received invalid brush data!");
 
846
      return;
 
847
    }
 
848
 
 
849
  str = g_strndup ((const gchar *) selection->data, selection->length);
 
850
 
 
851
  if (g_utf8_validate (str, -1, NULL))
 
852
    {
 
853
      gint     pid;
 
854
      gpointer unused;
 
855
      gint     name_offset = 0;
 
856
 
 
857
      if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 &&
 
858
          pid == gimp_getpid () && name_offset > 0)
 
859
        {
 
860
          gchar *name = str + name_offset;
 
861
 
 
862
          gimp_brush_select_button_set_brush (button, name, -1.0, -1, -1);
 
863
        }
 
864
    }
 
865
 
 
866
  g_free (str);
 
867
}
 
868
 
 
869
static GtkWidget *
 
870
gimp_brush_select_button_create_inside (GimpBrushSelectButton *brush_button)
 
871
{
 
872
  GtkWidget                    *hbox;
 
873
  GtkWidget                    *frame;
 
874
  GtkWidget                    *button;
 
875
  GimpBrushSelectButtonPrivate *priv;
 
876
 
 
877
  priv = GIMP_BRUSH_SELECT_BUTTON_GET_PRIVATE (brush_button);
 
878
 
 
879
  gtk_widget_push_composite_child ();
 
880
 
 
881
  hbox = gtk_hbox_new (FALSE, 6);
 
882
 
 
883
  frame = gtk_frame_new (NULL);
 
884
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
 
885
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
 
886
 
 
887
  priv->preview = gimp_preview_area_new ();
 
888
  gtk_widget_add_events (priv->preview,
 
889
                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
 
890
  gtk_widget_set_size_request (priv->preview, CELL_SIZE, CELL_SIZE);
 
891
  gtk_container_add (GTK_CONTAINER (frame), priv->preview);
 
892
 
 
893
  g_signal_connect_swapped (priv->preview, "size-allocate",
 
894
                            G_CALLBACK (gimp_brush_select_preview_resize),
 
895
                            brush_button);
 
896
  g_signal_connect (priv->preview, "event",
 
897
                    G_CALLBACK (gimp_brush_select_preview_events),
 
898
                    brush_button);
 
899
 
 
900
  gtk_drag_dest_set (GTK_WIDGET (priv->preview),
 
901
                     GTK_DEST_DEFAULT_HIGHLIGHT |
 
902
                     GTK_DEST_DEFAULT_MOTION |
 
903
                     GTK_DEST_DEFAULT_DROP,
 
904
                     &target, 1,
 
905
                     GDK_ACTION_COPY);
 
906
 
 
907
  g_signal_connect (priv->preview, "drag-data-received",
 
908
                    G_CALLBACK (gimp_brush_select_drag_data_received),
 
909
                    hbox);
 
910
 
 
911
  button = gtk_button_new_with_mnemonic (_("_Browse..."));
 
912
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
 
913
 
 
914
  g_signal_connect_swapped (button, "clicked",
 
915
                            G_CALLBACK (gimp_brush_select_button_clicked),
 
916
                            brush_button);
 
917
 
 
918
  gtk_widget_show_all (hbox);
 
919
 
 
920
  gtk_widget_pop_composite_child ();
 
921
 
 
922
  return hbox;
 
923
}