gimpcolorbutton.c 15.2 KB
Newer Older
1
/* LIBGIMP - The GIMP Library 
2
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3
 *
4
 * gimpcolorbutton.c
5
 * Copyright (C) 1999-2001 Sven Neumann
6 7
 *
 * This library is free software; you can redistribute it and/or
Marc Lehmann's avatar
Marc Lehmann committed
8
 * modify it under the terms of the GNU Lesser General Public
9 10 11 12 13 14 15 16
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
 * Library General Public License for more details.
 *
Marc Lehmann's avatar
Marc Lehmann committed
17
 * You should have received a copy of the GNU Lesser General Public
18 19 20 21 22
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

23 24
#include "config.h"

25 26
#include <gtk/gtk.h>

27
#include "libgimpcolor/gimpcolor.h"
28

29
#include "gimpwidgetstypes.h"
30

31
#include "gimpcolorarea.h"
32
#include "gimpcolorbutton.h"
33
#include "gimpwidgets-private.h"
34 35

#include "libgimp/libgimp-intl.h"
36

37

38 39 40 41
#define TODOUBLE(i) (i / 65535.0)
#define TOUINT16(d) ((guint16) (d * 65535 + 0.5))


42 43 44 45 46 47 48 49
typedef enum
{
  GIMP_COLOR_BUTTON_COLOR_FG,
  GIMP_COLOR_BUTTON_COLOR_BG,
  GIMP_COLOR_BUTTON_COLOR_BLACK,
  GIMP_COLOR_BUTTON_COLOR_WHITE,
} GimpColorButtonColor;

50 51 52 53 54 55 56
enum
{
  COLOR_CHANGED,
  LAST_SIGNAL
};


57
static void     gimp_color_button_class_init     (GimpColorButtonClass *klass);
58 59
static void     gimp_color_button_init           (GimpColorButton      *button);
static void     gimp_color_button_destroy        (GtkObject      *object);
60

61 62 63 64 65
static gboolean gimp_color_button_button_press   (GtkWidget      *widget,
                                                  GdkEventButton *bevent);
static void     gimp_color_button_state_changed  (GtkWidget      *widget,
                                                  GtkStateType    prev_state);
static void     gimp_color_button_clicked        (GtkButton      *button);
66

67 68 69 70
static void     gimp_color_button_dialog_ok      (GtkWidget      *widget,
                                                  gpointer        data);
static void     gimp_color_button_dialog_cancel  (GtkWidget      *widget,
                                                  gpointer        data);
71

72 73 74 75 76
static void     gimp_color_button_use_color      (gpointer        callback_data,
                                                  guint           callback_action, 
                                                  GtkWidget      *widget);
static gchar  * gimp_color_button_menu_translate (const gchar    *path,
                                                  gpointer        func_data);
77

78 79
static void     gimp_color_button_color_changed  (GtkObject      *object,
                                                  gpointer        data);
80 81


82 83
static GtkItemFactoryEntry menu_items[] =
{
84 85 86 87
  { N_("/Foreground Color"), NULL, 
    gimp_color_button_use_color, GIMP_COLOR_BUTTON_COLOR_FG, NULL },
  { N_("/Background Color"), NULL, 
    gimp_color_button_use_color, GIMP_COLOR_BUTTON_COLOR_BG, NULL },
88
  { "/fg-bg-separator", NULL, NULL, 0, "<Separator>"},
89 90 91 92
  { N_("/Black"), NULL, 
    gimp_color_button_use_color, GIMP_COLOR_BUTTON_COLOR_BLACK, NULL },
  { N_("/White"), NULL, 
    gimp_color_button_use_color, GIMP_COLOR_BUTTON_COLOR_WHITE, NULL },
93
};
94

95
static guint   gimp_color_button_signals[LAST_SIGNAL] = { 0 };
96

97
static GimpButtonClass * parent_class = NULL;
98

99

100 101
GType
gimp_color_button_get_type (void)
102
{
103
  static GType button_type = 0;
104

105
  if (!button_type)
106
    {
107
      static const GTypeInfo button_info =
108 109 110 111 112 113 114 115 116 117 118
      {
        sizeof (GimpColorButtonClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gimp_color_button_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data     */
        sizeof (GimpColorButton),
        0,              /* n_preallocs    */
        (GInstanceInitFunc) gimp_color_button_init,
      };
119

120
      button_type = g_type_register_static (GIMP_TYPE_BUTTON,
121
                                         "GimpColorButton", 
122
                                         &button_info, 0);
123
    }
124
  
125
  return button_type;
126 127 128
}

static void
129
gimp_color_button_class_init (GimpColorButtonClass *klass)
130 131
{
  GtkObjectClass *object_class;
132
  GtkWidgetClass *widget_class;
133
  GtkButtonClass *button_class;
134

135 136 137
  object_class = GTK_OBJECT_CLASS (klass);
  widget_class = GTK_WIDGET_CLASS (klass);
  button_class = GTK_BUTTON_CLASS (klass);
138
 
139
  parent_class = g_type_class_peek_parent (klass);
140 141

  gimp_color_button_signals[COLOR_CHANGED] = 
142 143 144 145 146 147 148
    g_signal_new ("color_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpColorButtonClass, color_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
149

150
  object_class->destroy            = gimp_color_button_destroy;
151

152 153
  widget_class->button_press_event = gimp_color_button_button_press;
  widget_class->state_changed      = gimp_color_button_state_changed;
154

155
  button_class->clicked            = gimp_color_button_clicked;
156

157
  klass->color_changed             = NULL;
158 159 160
}

static void
161
gimp_color_button_init (GimpColorButton *button)
162
{
163 164
  GimpRGB color;

165 166
  button->title  = NULL;
  button->dialog = NULL;
167 168

  gimp_rgba_set (&color, 0.0, 0.0, 0.0, 1.0);
169
  button->color_area = gimp_color_area_new (&color, FALSE, GDK_BUTTON2_MASK);
170
  g_signal_connect (button->color_area, "color_changed",
171
		    G_CALLBACK (gimp_color_button_color_changed),
172
		    button);
173

174 175
  gtk_container_add (GTK_CONTAINER (button), button->color_area);
  gtk_widget_show (button->color_area);
176 177
  
  /* right-click opens a popup */
178 179
  button->item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<popup>", NULL);  
  gtk_item_factory_set_translate_func (button->item_factory,
180 181
				       gimp_color_button_menu_translate,
	  			       NULL, NULL);
182 183
  gtk_item_factory_create_items (button->item_factory, 
				 G_N_ELEMENTS (menu_items), menu_items, button);
184 185
}

186 187
static void
gimp_color_button_destroy (GtkObject *object)
188
{
189
  GimpColorButton *button;
190

191
  button = GIMP_COLOR_BUTTON (object);
192

193
  if (button->title)
194
    {
195 196
      g_free (button->title);
      button->title = NULL;
197
    }
198

199
  if (button->dialog)
200
    {
201 202
      gtk_widget_destroy (button->dialog);
      button->dialog = NULL;
203 204
    }

205
  if (button->color_area)
206
    {
207 208
      gtk_widget_destroy (button->color_area);
      button->color_area = NULL;
209
    }
210 211

  GTK_OBJECT_CLASS (parent_class)->destroy (object);
212 213
}

214 215 216 217
static gboolean
gimp_color_button_button_press (GtkWidget      *widget,
                                GdkEventButton *bevent)
{
218
  GimpColorButton *button;
219 220 221
  gint             x;
  gint             y;

222
  button = GIMP_COLOR_BUTTON (widget);
223 224 225 226 227 228 229
  
  if (bevent->button == 3)
    {
      gdk_window_get_origin (GTK_WIDGET (widget)->window, &x, &y);
      x += widget->allocation.x;
      y += widget->allocation.y;

230
      gtk_item_factory_popup (button->item_factory,
231 232 233 234 235 236 237 238 239 240
                              x + bevent->x, y + bevent->y,
                              bevent->button, bevent->time);
    }

  if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
    return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, bevent);

  return FALSE;
}

241 242
static void
gimp_color_button_state_changed (GtkWidget    *widget,
243
				 GtkStateType  prev_state)
244 245 246
{  
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (widget));

247
  if (! GTK_WIDGET_IS_SENSITIVE (widget) && GIMP_COLOR_BUTTON (widget)->dialog)
248 249 250
    gtk_widget_hide (GIMP_COLOR_BUTTON (widget)->dialog);

  if (GTK_WIDGET_CLASS (parent_class)->state_changed)
251
    GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
252
}
253

254 255 256 257 258 259
/**
 * gimp_color_button_new:
 * @title: String that will be used as title for the color_selector.
 * @width: Width of the colorpreview in pixels.
 * @height: Height of the colorpreview in pixels.
 * @color: A pointer to a #GimpRGB color.
260
 * @type: 
261 262 263 264 265 266 267 268 269 270 271 272
 * 
 * Creates a new #GimpColorButton widget.
 *
 * This returns a button with a preview showing the color.
 * When the button is clicked a GtkColorSelectionDialog is opened.
 * If the user changes the color the new color is written into the
 * array that was used to pass the initial color and the "color_changed"
 * signal is emitted.
 * 
 * Returns: Pointer to the new #GimpColorButton widget.
 **/
GtkWidget *
273 274 275 276 277
gimp_color_button_new (const gchar       *title,
		       gint               width,
		       gint               height,
		       const GimpRGB     *color,
		       GimpColorAreaType  type)
278
{
279
  GimpColorButton *button;
280
  
281
  g_return_val_if_fail (color != NULL, NULL);  
282

283
  button = g_object_new (GIMP_TYPE_COLOR_BUTTON, NULL);
284

285
  button->title = g_strdup (title);
286
  
287
  gtk_widget_set_size_request (GTK_WIDGET (button->color_area), width, height);
288

289 290
  gimp_color_area_set_color (GIMP_COLOR_AREA (button->color_area), color);
  gimp_color_area_set_type (GIMP_COLOR_AREA (button->color_area), type);
291

292
  return GTK_WIDGET (button);
293 294
}

295
/**
296
 * gimp_color_button_set_color:
297
 * @button: Pointer to a #GimpColorButton.
298
 * @color: Pointer to the new #GimpRGB color.
299
 * 
300
 * Sets the @button to the given @color.
301
 **/
302
void       
303
gimp_color_button_set_color (GimpColorButton *button,
304
			     const GimpRGB   *color)
305
{
306
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (button));
307 308
  g_return_if_fail (color != NULL);

309
  gimp_color_area_set_color (GIMP_COLOR_AREA (button->color_area), color);
310 311 312
}

/**
313
 * gimp_color_button_get_color:
314 315
 * @button: Pointer to a #GimpColorButton.
 * @color: Pointer to a #GimpRGB struct used to return the color.
316
 * 
317
 * Retrieves the currently set color from the @button.
318
 **/
319
void
320
gimp_color_button_get_color (GimpColorButton *button,
321
			     GimpRGB         *color)
322
{
323
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (button));
324 325
  g_return_if_fail (color != NULL);

326
  gimp_color_area_get_color (GIMP_COLOR_AREA (button->color_area), color);
327 328
}

329
/**
330
 * gimp_color_button_has_alpha:
331
 * @button: Pointer to a #GimpColorButton.
332
 *
333
 * Checks whether the @buttons shows transparency information.
334
 *
335 336
 * Returns: %TRUE if the @button shows transparency information, %FALSE
 * otherwise.
337
 **/
338
gboolean
339
gimp_color_button_has_alpha (GimpColorButton *button)
340
{
341
  g_return_val_if_fail (GIMP_IS_COLOR_BUTTON (button), FALSE);
342

343
  return gimp_color_area_has_alpha (GIMP_COLOR_AREA (button->color_area));
344 345
}

346 347 348 349 350 351 352
/**
 * gimp_color_button_set_type:
 * @button: Pointer to a #GimpColorButton.
 * @type: the new #GimpColorAreaType
 *
 * Sets the @button to the given @type. See also gimp_color_area_set_type().
 **/
353
void
354
gimp_color_button_set_type (GimpColorButton   *button,
355 356
			    GimpColorAreaType  type)
{
357
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (button));
358

359
  gimp_color_area_set_type (GIMP_COLOR_AREA (button->color_area), type);
360 361
}

362 363 364
static void
gimp_color_button_clicked (GtkButton *button)
{
365 366
  GimpColorButton *color_button;
  GtkWidget       *dialog;
367
  GimpRGB          color;
368 369
  GdkColor         gdk_color;
  guint16          alpha;
370 371

  g_return_if_fail (GIMP_IS_COLOR_BUTTON (button));
372

373
  color_button = GIMP_COLOR_BUTTON (button);
374

375
  gimp_color_button_get_color (color_button, &color);
376

377 378 379 380
  gdk_color.red   = TOUINT16 (color.r);
  gdk_color.green = TOUINT16 (color.g);
  gdk_color.blue  = TOUINT16 (color.b);
  alpha           = TOUINT16 (color.a);
381

382 383 384
  dialog = color_button->dialog;
    
  if (!dialog)
385
    {
386
      dialog = gtk_color_selection_dialog_new (color_button->title);
387

388
      gtk_color_selection_set_has_opacity_control (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel), gimp_color_button_has_alpha (color_button));
389

390 391
      gtk_widget_destroy (GTK_COLOR_SELECTION_DIALOG (dialog)->help_button);
      gtk_container_set_border_width (GTK_CONTAINER (dialog), 2);
392

393
      g_signal_connect (dialog, "destroy",
394 395
			G_CALLBACK (gtk_widget_destroyed),
			&color_button->dialog);
396
      g_signal_connect (GTK_COLOR_SELECTION_DIALOG (dialog)->ok_button,
397 398
                        "clicked",
                        G_CALLBACK (gimp_color_button_dialog_ok), 
399
                        color_button);
400
      g_signal_connect (GTK_COLOR_SELECTION_DIALOG (dialog)->cancel_button,
401 402
                        "clicked",
                        G_CALLBACK (gimp_color_button_dialog_cancel), 
403 404 405 406
                        color_button);
      gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);  

      color_button->dialog = dialog;
407
    }
408

409 410
  gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel), &gdk_color);
  gtk_color_selection_set_current_alpha (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel), alpha);
411

412
  gtk_widget_show (dialog);
413 414 415 416 417 418
}

static void  
gimp_color_button_dialog_ok (GtkWidget *widget, 
			     gpointer   data)
{
419
  GimpColorButton *button;
420
  GimpRGB          color;
421 422
  GdkColor         gdk_color;
  guint16          alpha;
423

424
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (data));
425

426
  button = GIMP_COLOR_BUTTON (data);
427

428 429
  gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (button->dialog)->colorsel), &gdk_color);
  alpha = gtk_color_selection_get_current_alpha (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (button->dialog)->colorsel));
430 431 432 433 434

  color.r = TODOUBLE (gdk_color.red);
  color.g = TODOUBLE (gdk_color.green);
  color.b = TODOUBLE (gdk_color.blue);
  color.a = TODOUBLE (alpha);
435

436
  gimp_color_button_set_color (button, &color);
437

438
  gtk_widget_hide (button->dialog);  
439 440 441 442 443 444 445
}

static void  
gimp_color_button_dialog_cancel (GtkWidget *widget, 
				 gpointer   data)
{
  g_return_if_fail (GIMP_IS_COLOR_BUTTON (data));
446

447
  gtk_widget_hide (GIMP_COLOR_BUTTON (data)->dialog);
448 449 450
}


451
static void  
452 453 454
gimp_color_button_use_color (gpointer   callback_data, 
                             guint      callback_action, 
                             GtkWidget *widget)
455
{
456 457
  GimpRGB              color;
  GimpColorButtonColor type;
458

459
  type = (GimpColorButtonColor) callback_action;
460

461
  gimp_color_button_get_color (GIMP_COLOR_BUTTON (callback_data), &color);
462

463 464 465
  switch (type)
    {
    case GIMP_COLOR_BUTTON_COLOR_FG:
466 467
      if (_gimp_get_foreground_func)
        _gimp_get_foreground_func (&color);
468 469
      break;
    case GIMP_COLOR_BUTTON_COLOR_BG:
470 471
      if (_gimp_get_background_func)
        _gimp_get_background_func (&color);
472 473 474 475 476 477 478 479
      break;
    case GIMP_COLOR_BUTTON_COLOR_BLACK:
      gimp_rgb_set (&color, 0.0, 0.0, 0.0);
      break;
    case GIMP_COLOR_BUTTON_COLOR_WHITE:
      gimp_rgb_set (&color, 1.0, 1.0, 1.0);
      break;
    }
480

481
  gimp_color_button_set_color (GIMP_COLOR_BUTTON (callback_data), &color);
482 483 484
}

static void
485 486
gimp_color_button_color_changed (GtkObject *object,
				 gpointer   data)
487
{
488
  GimpColorButton *button = GIMP_COLOR_BUTTON (data);
489

490
  if (button->dialog)
491
    {
492
      GimpRGB  color;
493 494
      GdkColor gdk_color;
      guint16  alpha;
495 496 497

      gimp_color_button_get_color (GIMP_COLOR_BUTTON (data), &color);
      
498 499 500 501 502
      gdk_color.red   = TOUINT16 (color.r);
      gdk_color.green = TOUINT16 (color.g);
      gdk_color.blue  = TOUINT16 (color.b);
      alpha           = TOUINT16 (color.a);

503 504
      gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (button->dialog)->colorsel), &gdk_color);
      gtk_color_selection_set_current_alpha (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (button->dialog)->colorsel), alpha);
505 506
    }

507
  g_signal_emit (button, gimp_color_button_signals[COLOR_CHANGED], 0);
508 509
}

510 511 512
static gchar *
gimp_color_button_menu_translate (const gchar *path, 
				  gpointer     func_data)
513
{
514
  return (gettext (path));
515
}