gtkcolorbutton.c 29.2 KB
Newer Older
1
/*
Cody Russell's avatar
Cody Russell committed
2
 * GTK - The GIMP Toolkit
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 * Copyright (C) 1998, 1999 Red Hat, Inc.
 * All rights reserved.
 *
 * This Library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public 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.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25
 */
/* Color picker button for GNOME
 *
 * Author: Federico Mena <federico@nuclecu.unam.mx>
 *
 * Modified by the GTK+ Team and others 2003.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
26
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 28
 */

Matthias Clasen's avatar
Matthias Clasen committed
29
#define GDK_DISABLE_DEPRECATION_WARNINGS
30
#include "config.h"
31 32

#include "gtkcolorbutton.h"
33

34 35
#include "gtkbutton.h"
#include "gtkmain.h"
36
#include "gtkcolorchooser.h"
37
#include "gtkcolorchooserprivate.h"
38
#include "gtkcolorchooserdialog.h"
39 40 41
#include "gtkdnd.h"
#include "gtkdrawingarea.h"
#include "gtkmarshalers.h"
42
#include "gtkprivate.h"
43 44
#include "gtkintl.h"

45 46 47 48 49 50 51

/**
 * SECTION:gtkcolorbutton
 * @Short_description: A button to launch a color selection dialog
 * @Title: GtkColorButton
 * @See_also: #GtkColorSelectionDialog, #GtkFontButton
 *
52 53 54
 * The #GtkColorButton is a button which displays the currently selected
 * color an allows to open a color selection dialog to change the color.
 * It is suitable widget for selecting a color in a preference dialog.
55 56 57
 */


58 59
/* Size of checks and gray levels for alpha compositing checkerboard */
#define CHECK_SIZE  4
60 61
#define CHECK_DARK  (1.0 / 3.0)
#define CHECK_LIGHT (2.0 / 3.0)
62

63
struct _GtkColorButtonPrivate
64
{
65
  GtkWidget *draw_area; /* Widget where we draw the color sample */
66
  GtkWidget *cs_dialog; /* Color selection dialog */
67

68
  gchar *title;         /* Title for the color selection window */
69 70
  GdkRGBA rgba;

71 72 73 74
  guint use_alpha : 1;  /* Use alpha or not */
};

/* Properties */
75
enum
76 77 78 79 80
{
  PROP_0,
  PROP_USE_ALPHA,
  PROP_TITLE,
  PROP_COLOR,
81 82
  PROP_ALPHA,
  PROP_RGBA
83 84 85
};

/* Signals */
86
enum
87 88 89 90 91 92 93 94
{
  COLOR_SET,
  LAST_SIGNAL
};

/* gobject signals */
static void gtk_color_button_finalize      (GObject             *object);
static void gtk_color_button_set_property  (GObject        *object,
95 96 97
                                            guint           param_id,
                                            const GValue   *value,
                                            GParamSpec     *pspec);
98
static void gtk_color_button_get_property  (GObject        *object,
99 100 101
                                            guint           param_id,
                                            GValue         *value,
                                            GParamSpec     *pspec);
102 103

/* gtkwidget signals */
104 105
static void gtk_color_button_state_changed (GtkWidget           *widget,
                                            GtkStateType         previous_state);
106 107 108 109 110 111

/* gtkbutton signals */
static void gtk_color_button_clicked       (GtkButton           *button);

/* source side drag signals */
static void gtk_color_button_drag_begin (GtkWidget        *widget,
112 113
                                         GdkDragContext   *context,
                                         gpointer          data);
114 115 116 117 118
static void gtk_color_button_drag_data_get (GtkWidget        *widget,
                                            GdkDragContext   *context,
                                            GtkSelectionData *selection_data,
                                            guint             info,
                                            guint             time,
Matthias Clasen's avatar
Matthias Clasen committed
119
                                            GtkColorButton   *button);
120 121 122

/* target side drag signals */
static void gtk_color_button_drag_data_received (GtkWidget        *widget,
123 124 125 126 127 128
                                                 GdkDragContext   *context,
                                                 gint              x,
                                                 gint              y,
                                                 GtkSelectionData *selection_data,
                                                 guint             info,
                                                 guint32           time,
Matthias Clasen's avatar
Matthias Clasen committed
129
                                                 GtkColorButton   *button);
130 131 132 133


static guint color_button_signals[LAST_SIGNAL] = { 0 };

134
static const GtkTargetEntry drop_types[] = { { "application/x-color", 0, 0 } };
135

Matthias Clasen's avatar
Matthias Clasen committed
136 137 138
static void gtk_color_button_iface_init (GtkColorChooserInterface *iface);

G_DEFINE_TYPE_WITH_CODE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON,
139
                         G_ADD_PRIVATE (GtkColorButton)
Matthias Clasen's avatar
Matthias Clasen committed
140 141
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
                                                gtk_color_button_iface_init))
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

static void
gtk_color_button_class_init (GtkColorButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;
  GtkButtonClass *button_class;

  gobject_class = G_OBJECT_CLASS (klass);
  widget_class = GTK_WIDGET_CLASS (klass);
  button_class = GTK_BUTTON_CLASS (klass);

  gobject_class->get_property = gtk_color_button_get_property;
  gobject_class->set_property = gtk_color_button_set_property;
  gobject_class->finalize = gtk_color_button_finalize;
  widget_class->state_changed = gtk_color_button_state_changed;
  button_class->clicked = gtk_color_button_clicked;
  klass->color_set = NULL;

  /**
   * GtkColorButton:use-alpha:
   *
Matthias Clasen's avatar
Matthias Clasen committed
164 165 166
   * If this property is set to %TRUE, the color swatch on the button is
   * rendered against a checkerboard background to show its opacity and
   * the opacity slider is displayed in the color selection dialog.
167 168 169 170 171
   *
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
                                   PROP_USE_ALPHA,
172
                                   g_param_spec_boolean ("use-alpha", P_("Use alpha"),
173
                                                         P_("Whether to give the color an alpha value"),
174
                                                         FALSE,
175
                                                         GTK_PARAM_READWRITE));
176 177 178 179 180 181 182 183 184 185

  /**
   * GtkColorButton:title:
   *
   * The title of the color selection dialog
   *
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
                                   PROP_TITLE,
186 187
                                   g_param_spec_string ("title",
                                                        P_("Title"),
188
                                                        P_("The title of the color selection dialog"),
189
                                                        _("Pick a Color"),
190
                                                        GTK_PARAM_READWRITE));
191 192 193 194 195 196 197

  /**
   * GtkColorButton:color:
   *
   * The selected color.
   *
   * Since: 2.4
198 199
   *
   * Deprecated: 3.4: Use #GtkColorButton:rgba instead.
200 201 202 203
   */
  g_object_class_install_property (gobject_class,
                                   PROP_COLOR,
                                   g_param_spec_boxed ("color",
204 205
                                                       P_("Current Color"),
                                                       P_("The selected color"),
206
                                                       GDK_TYPE_COLOR,
207
                                                       GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
208 209 210 211

  /**
   * GtkColorButton:alpha:
   *
212
   * The selected opacity value (0 fully transparent, 65535 fully opaque).
213 214 215 216 217 218
   *
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
                                   PROP_ALPHA,
                                   g_param_spec_uint ("alpha",
219 220
                                                      P_("Current Alpha"),
                                                      P_("The selected opacity value (0 fully transparent, 65535 fully opaque)"),
221
                                                      0, 65535, 65535,
222
                                                      GTK_PARAM_READWRITE));
223 224

  /**
225
   * GtkColorButton:rgba:
226 227 228 229 230 231 232 233 234 235 236 237 238 239
   *
   * The RGBA color.
   *
   * Since: 3.0
   */
  g_object_class_install_property (gobject_class,
                                   PROP_RGBA,
                                   g_param_spec_boxed ("rgba",
                                                       P_("Current RGBA Color"),
                                                       P_("The selected RGBA color"),
                                                       GDK_TYPE_RGBA,
                                                       GTK_PARAM_READWRITE));


240 241 242
  /**
   * GtkColorButton::color-set:
   * @widget: the object which received the signal.
243 244
   *
   * The ::color-set signal is emitted when the user selects a color.
245
   * When handling this signal, use gtk_color_button_get_rgba() to
246
   * find out which color was just selected.
247 248 249 250
   *
   * Note that this signal is only emitted when the <emphasis>user</emphasis>
   * changes the color. If you need to react to programmatic color changes
   * as well, use the notify::color signal.
251 252 253
   *
   * Since: 2.4
   */
254
  color_button_signals[COLOR_SET] = g_signal_new (I_("color-set"),
255 256 257 258 259 260
                                                  G_TYPE_FROM_CLASS (gobject_class),
                                                  G_SIGNAL_RUN_FIRST,
                                                  G_STRUCT_OFFSET (GtkColorButtonClass, color_set),
                                                  NULL, NULL,
                                                  _gtk_marshal_VOID__VOID,
                                                  G_TYPE_NONE, 0);
261 262
}

263
static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
264
gtk_color_button_has_alpha (GtkColorButton *button)
265
{
Matthias Clasen's avatar
Matthias Clasen committed
266
  return button->priv->use_alpha && button->priv->rgba.alpha < 1;
267
}
268 269 270

/* Handle exposure events for the color picker's drawing area */
static gint
271
gtk_color_button_draw_cb (GtkWidget *widget,
272 273
                          cairo_t   *cr,
                          gpointer   data)
274
{
Matthias Clasen's avatar
Matthias Clasen committed
275
  GtkColorButton *button = GTK_COLOR_BUTTON (data);
276
  cairo_pattern_t *checkered;
277

Matthias Clasen's avatar
Matthias Clasen committed
278
  if (gtk_color_button_has_alpha (button))
279 280 281
    {
      cairo_set_source_rgb (cr, CHECK_DARK, CHECK_DARK, CHECK_DARK);
      cairo_paint (cr);
282

283 284
      cairo_set_source_rgb (cr, CHECK_LIGHT, CHECK_LIGHT, CHECK_LIGHT);
      cairo_scale (cr, CHECK_SIZE, CHECK_SIZE);
285

286
      checkered = _gtk_color_chooser_get_checkered_pattern ();
287 288
      cairo_mask (cr, checkered);
      cairo_pattern_destroy (checkered);
289

Matthias Clasen's avatar
Matthias Clasen committed
290
      gdk_cairo_set_source_rgba (cr, &button->priv->rgba);
291 292 293
    }
  else
    {
294
      cairo_set_source_rgb (cr,
Matthias Clasen's avatar
Matthias Clasen committed
295 296 297
                            button->priv->rgba.red,
                            button->priv->rgba.green,
                            button->priv->rgba.blue);
298
    }
299

300
  cairo_paint (cr);
301

Matthias Clasen's avatar
Matthias Clasen committed
302
  if (!gtk_widget_is_sensitive (GTK_WIDGET (button)))
303
    {
304 305 306 307 308 309 310
      GtkStyleContext *context;
      GdkRGBA color;

      context = gtk_widget_get_style_context (widget);
      gtk_style_context_get_background_color (context, GTK_STATE_FLAG_INSENSITIVE, &color);

      gdk_cairo_set_source_rgba (cr, &color);
311
      checkered = _gtk_color_chooser_get_checkered_pattern ();
312 313
      cairo_mask (cr, checkered);
      cairo_pattern_destroy (checkered);
314
    }
315 316

  return FALSE;
317 318 319
}

static void
320
gtk_color_button_state_changed (GtkWidget   *widget,
321
                                GtkStateType previous_state)
322
{
323
  gtk_widget_queue_draw (widget);
324 325 326 327
}

static void
gtk_color_button_drag_data_received (GtkWidget        *widget,
328 329 330 331 332 333
                                     GdkDragContext   *context,
                                     gint              x,
                                     gint              y,
                                     GtkSelectionData *selection_data,
                                     guint             info,
                                     guint32           time,
Matthias Clasen's avatar
Matthias Clasen committed
334
                                     GtkColorButton   *button)
335
{
336
  gint length;
337 338
  guint16 *dropped;

339 340 341
  length = gtk_selection_data_get_length (selection_data);

  if (length < 0)
342 343
    return;

344 345 346
  /* We accept drops with the wrong format, since the KDE color
   * chooser incorrectly drops application/x-color with format 8.
   */
347
  if (length != 8)
348
    {
Matthias Clasen's avatar
Matthias Clasen committed
349
      g_warning ("%s: Received invalid color data", G_STRFUNC);
350 351 352 353
      return;
    }


354
  dropped = (guint16 *) gtk_selection_data_get_data (selection_data);
355

Matthias Clasen's avatar
Matthias Clasen committed
356 357 358 359
  button->priv->rgba.red = dropped[0] / 65535.;
  button->priv->rgba.green = dropped[1] / 65535.;
  button->priv->rgba.blue = dropped[2] / 65535.;
  button->priv->rgba.alpha = dropped[3] / 65535.;
360

Matthias Clasen's avatar
Matthias Clasen committed
361
  gtk_widget_queue_draw (button->priv->draw_area);
362

Matthias Clasen's avatar
Matthias Clasen committed
363
  g_signal_emit (button, color_button_signals[COLOR_SET], 0);
364

Matthias Clasen's avatar
Matthias Clasen committed
365 366 367 368 369
  g_object_freeze_notify (G_OBJECT (button));
  g_object_notify (G_OBJECT (button), "color");
  g_object_notify (G_OBJECT (button), "alpha");
  g_object_notify (G_OBJECT (button), "rgba");
  g_object_thaw_notify (G_OBJECT (button));
370 371 372 373
}

static void
set_color_icon (GdkDragContext *context,
374
                GdkRGBA        *rgba)
375
{
376 377
  cairo_surface_t *surface;
  cairo_t *cr;
378

379 380 381
  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
                                        48, 32);
  cr = cairo_create (surface);
382

383 384
  gdk_cairo_set_source_rgba (cr, rgba);
  cairo_paint (cr);
385

386 387 388 389
  gtk_drag_set_icon_surface (context, surface);

  cairo_destroy (cr);
  cairo_surface_destroy (surface);
390 391 392 393
}

static void
gtk_color_button_drag_begin (GtkWidget      *widget,
394 395
                             GdkDragContext *context,
                             gpointer        data)
396
{
Matthias Clasen's avatar
Matthias Clasen committed
397
  GtkColorButton *button = data;
398

Matthias Clasen's avatar
Matthias Clasen committed
399
  set_color_icon (context, &button->priv->rgba);
400 401 402 403
}

static void
gtk_color_button_drag_data_get (GtkWidget        *widget,
404 405 406 407
                                GdkDragContext   *context,
                                GtkSelectionData *selection_data,
                                guint             info,
                                guint             time,
Matthias Clasen's avatar
Matthias Clasen committed
408
                                GtkColorButton   *button)
409 410 411
{
  guint16 dropped[4];

Matthias Clasen's avatar
Matthias Clasen committed
412 413 414 415
  dropped[0] = (guint16) (button->priv->rgba.red * 65535);
  dropped[1] = (guint16) (button->priv->rgba.green * 65535);
  dropped[2] = (guint16) (button->priv->rgba.blue * 65535);
  dropped[3] = (guint16) (button->priv->rgba.alpha * 65535);
416

417 418
  gtk_selection_data_set (selection_data,
                          gtk_selection_data_get_target (selection_data),
419
                          16, (guchar *)dropped, 8);
420 421 422
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
423
gtk_color_button_init (GtkColorButton *button)
424 425 426 427 428
{
  PangoLayout *layout;
  PangoRectangle rect;

  /* Create the widgets */
429
  button->priv = gtk_color_button_get_instance_private (button);
430

431
  button->priv->draw_area = gtk_drawing_area_new ();
Matthias Clasen's avatar
Matthias Clasen committed
432
  layout = gtk_widget_create_pango_layout (GTK_WIDGET (button), "Black");
433
  pango_layout_get_pixel_extents (layout, NULL, &rect);
434 435
  g_object_unref (layout);

436
  gtk_widget_set_size_request (button->priv->draw_area, 
437
                               rect.width, rect.height);
438

Matthias Clasen's avatar
Matthias Clasen committed
439 440
  g_signal_connect (button->priv->draw_area, "draw",
                    G_CALLBACK (gtk_color_button_draw_cb), button);
441
  gtk_container_add (GTK_CONTAINER (button), button->priv->draw_area);
Matthias Clasen's avatar
Matthias Clasen committed
442
  gtk_widget_show (button->priv->draw_area);
443

Matthias Clasen's avatar
Matthias Clasen committed
444
  button->priv->title = g_strdup (_("Pick a Color")); /* default title */
445 446

  /* Start with opaque black, alpha disabled */
Matthias Clasen's avatar
Matthias Clasen committed
447 448 449 450 451
  button->priv->rgba.red = 0;
  button->priv->rgba.green = 0;
  button->priv->rgba.blue = 0;
  button->priv->rgba.alpha = 1;
  button->priv->use_alpha = FALSE;
452

Matthias Clasen's avatar
Matthias Clasen committed
453
  gtk_drag_dest_set (GTK_WIDGET (button),
454 455 456 457
                     GTK_DEST_DEFAULT_MOTION |
                     GTK_DEST_DEFAULT_HIGHLIGHT |
                     GTK_DEST_DEFAULT_DROP,
                     drop_types, 1, GDK_ACTION_COPY);
Matthias Clasen's avatar
Matthias Clasen committed
458
  gtk_drag_source_set (GTK_WIDGET (button),
459 460 461
                       GDK_BUTTON1_MASK|GDK_BUTTON3_MASK,
                       drop_types, 1,
                       GDK_ACTION_COPY);
Matthias Clasen's avatar
Matthias Clasen committed
462 463 464 465 466 467
  g_signal_connect (button, "drag-begin",
                    G_CALLBACK (gtk_color_button_drag_begin), button);
  g_signal_connect (button, "drag-data-received",
                    G_CALLBACK (gtk_color_button_drag_data_received), button);
  g_signal_connect (button, "drag-data-get",
                    G_CALLBACK (gtk_color_button_drag_data_get), button);
468 469 470 471 472
}

static void
gtk_color_button_finalize (GObject *object)
{
Matthias Clasen's avatar
Matthias Clasen committed
473
  GtkColorButton *button = GTK_COLOR_BUTTON (object);
474

Matthias Clasen's avatar
Matthias Clasen committed
475 476 477
  if (button->priv->cs_dialog != NULL)
    gtk_widget_destroy (button->priv->cs_dialog);
  button->priv->cs_dialog = NULL;
478

Matthias Clasen's avatar
Matthias Clasen committed
479 480
  g_free (button->priv->title);
  button->priv->title = NULL;
481

Matthias Clasen's avatar
Matthias Clasen committed
482
  G_OBJECT_CLASS (gtk_color_button_parent_class)->finalize (object);
483 484 485 486 487 488
}


/**
 * gtk_color_button_new:
 *
489 490 491 492 493 494 495
 * Creates a new color button.
 *
 * This returns a widget in the form of a small button containing
 * a swatch representing the current selected color. When the button
 * is clicked, a color-selection dialog will open, allowing the user
 * to select a color. The swatch will be updated to reflect the new
 * color when the user finishes.
496
 *
497
 * Returns: a new color button
498 499 500 501 502 503 504 505 506 507 508
 *
 * Since: 2.4
 */
GtkWidget *
gtk_color_button_new (void)
{
  return g_object_new (GTK_TYPE_COLOR_BUTTON, NULL);
}

/**
 * gtk_color_button_new_with_color:
509
 * @color: A #GdkColor to set the current color with
510
 *
511
 * Creates a new color button.
512
 *
513
 * Returns: a new color button
514 515
 *
 * Since: 2.4
516 517
 *
 * Deprecated: 3.4: Use gtk_color_button_new_with_rgba() instead.
518 519
 */
GtkWidget *
520
gtk_color_button_new_with_color (const GdkColor *color)
521 522 523 524
{
  return g_object_new (GTK_TYPE_COLOR_BUTTON, "color", color, NULL);
}

Matthias Clasen's avatar
Matthias Clasen committed
525 526
/**
 * gtk_color_button_new_with_rgba:
527
 * @rgba: A #GdkRGBA to set the current color with
Matthias Clasen's avatar
Matthias Clasen committed
528 529 530 531 532 533 534
 *
 * Creates a new color button.
 *
 * Returns: a new color button
 *
 * Since: 3.0
 */
535 536 537 538 539 540
GtkWidget *
gtk_color_button_new_with_rgba (const GdkRGBA *rgba)
{
  return g_object_new (GTK_TYPE_COLOR_BUTTON, "rgba", rgba, NULL);
}

541
static gboolean
542 543
dialog_destroy (GtkWidget *widget,
                gpointer   data)
544
{
Matthias Clasen's avatar
Matthias Clasen committed
545
  GtkColorButton *button = GTK_COLOR_BUTTON (data);
546

Matthias Clasen's avatar
Matthias Clasen committed
547
  button->priv->cs_dialog = NULL;
548 549 550 551 552

  return FALSE;
}

static void
553 554 555
dialog_response (GtkDialog *dialog,
                 gint       response,
                 gpointer   data)
556
{
557 558 559 560
  if (response == GTK_RESPONSE_CANCEL)
    gtk_widget_hide (GTK_WIDGET (dialog));
  else if (response == GTK_RESPONSE_OK)
    {
Matthias Clasen's avatar
Matthias Clasen committed
561
      GtkColorButton *button = GTK_COLOR_BUTTON (data);
562

Matthias Clasen's avatar
Matthias Clasen committed
563 564
      gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog),
                                  &button->priv->rgba);
565 566 567

      gtk_widget_hide (GTK_WIDGET (dialog));

Matthias Clasen's avatar
Matthias Clasen committed
568
      gtk_widget_queue_draw (button->priv->draw_area);
569

570
      g_object_ref (button);
Matthias Clasen's avatar
Matthias Clasen committed
571
      g_signal_emit (button, color_button_signals[COLOR_SET], 0);
572

Matthias Clasen's avatar
Matthias Clasen committed
573 574 575 576 577
      g_object_freeze_notify (G_OBJECT (button));
      g_object_notify (G_OBJECT (button), "color");
      g_object_notify (G_OBJECT (button), "alpha");
      g_object_notify (G_OBJECT (button), "rgba");
      g_object_thaw_notify (G_OBJECT (button));
578
      g_object_unref (button);
579
    }
580 581
}

582
/* Create the dialog and connects its buttons */
583
static void
584
ensure_dialog (GtkColorButton *button)
585
{
586
  GtkWidget *parent, *dialog;
587

588 589
  if (button->priv->cs_dialog != NULL)
    return;
590

591
  parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
592

593
  button->priv->cs_dialog = dialog = gtk_color_chooser_dialog_new (button->priv->title, NULL);
594

595 596 597 598
  if (gtk_widget_is_toplevel (parent) && GTK_IS_WINDOW (parent))
  {
    if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
      gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
599

600 601 602 603 604 605 606 607 608
    gtk_window_set_modal (GTK_WINDOW (dialog),
                            gtk_window_get_modal (GTK_WINDOW (parent)));
  }

  g_signal_connect (dialog, "response",
                    G_CALLBACK (dialog_response), button);
  g_signal_connect (dialog, "destroy",
                    G_CALLBACK (dialog_destroy), button);
}
609

610 611 612 613 614 615 616 617

static void
gtk_color_button_clicked (GtkButton *b)
{
  GtkColorButton *button = GTK_COLOR_BUTTON (b);

  /* if dialog already exists, make sure it's shown and raised */
  ensure_dialog (button);
618

Matthias Clasen's avatar
Matthias Clasen committed
619 620
  gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
                                   button->priv->use_alpha);
621

622 623 624
  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
                              &button->priv->rgba);

Matthias Clasen's avatar
Matthias Clasen committed
625
  gtk_window_present (GTK_WINDOW (button->priv->cs_dialog));
626 627 628 629
}

/**
 * gtk_color_button_set_color:
Matthias Clasen's avatar
Matthias Clasen committed
630
 * @button: a #GtkColorButton
631
 * @color: A #GdkColor to set the current color with
632 633 634 635
 *
 * Sets the current color to be @color.
 *
 * Since: 2.4
636
 *
Matthias Clasen's avatar
Matthias Clasen committed
637
 * Deprecated: Use gtk_color_chooser_set_rgba() instead.
638
 */
639
void
Matthias Clasen's avatar
Matthias Clasen committed
640
gtk_color_button_set_color (GtkColorButton *button,
641
                            const GdkColor *color)
642
{
Matthias Clasen's avatar
Matthias Clasen committed
643
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
644
  g_return_if_fail (color != NULL);
645

Matthias Clasen's avatar
Matthias Clasen committed
646 647 648
  button->priv->rgba.red = color->red / 65535.;
  button->priv->rgba.green = color->green / 65535.;
  button->priv->rgba.blue = color->blue / 65535.;
649

Matthias Clasen's avatar
Matthias Clasen committed
650
  gtk_widget_queue_draw (button->priv->draw_area);
651

Matthias Clasen's avatar
Matthias Clasen committed
652 653
  g_object_notify (G_OBJECT (button), "color");
  g_object_notify (G_OBJECT (button), "rgba");
654 655 656 657 658
}


/**
 * gtk_color_button_set_alpha:
Matthias Clasen's avatar
Matthias Clasen committed
659
 * @button: a #GtkColorButton
660
 * @alpha: an integer between 0 and 65535
661
 *
662
 * Sets the current opacity to be @alpha.
663 664
 *
 * Since: 2.4
Matthias Clasen's avatar
Matthias Clasen committed
665 666
 *
 * Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
667
 */
668
void
Matthias Clasen's avatar
Matthias Clasen committed
669
gtk_color_button_set_alpha (GtkColorButton *button,
670
                            guint16         alpha)
671
{
Matthias Clasen's avatar
Matthias Clasen committed
672
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
673

Matthias Clasen's avatar
Matthias Clasen committed
674
  button->priv->rgba.alpha = alpha / 65535.;
675

Matthias Clasen's avatar
Matthias Clasen committed
676
  gtk_widget_queue_draw (button->priv->draw_area);
677

Matthias Clasen's avatar
Matthias Clasen committed
678 679
  g_object_notify (G_OBJECT (button), "alpha");
  g_object_notify (G_OBJECT (button), "rgba");
680 681 682 683
}

/**
 * gtk_color_button_get_color:
Matthias Clasen's avatar
Matthias Clasen committed
684
 * @button: a #GtkColorButton
685
 * @color: (out): a #GdkColor to fill in with the current color
686 687 688 689
 *
 * Sets @color to be the current color in the #GtkColorButton widget.
 *
 * Since: 2.4
690
 *
Matthias Clasen's avatar
Matthias Clasen committed
691
 * Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
692
 */
693
void
Matthias Clasen's avatar
Matthias Clasen committed
694
gtk_color_button_get_color (GtkColorButton *button,
695
                            GdkColor       *color)
696
{
Matthias Clasen's avatar
Matthias Clasen committed
697
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
698

Matthias Clasen's avatar
Matthias Clasen committed
699 700 701
  color->red = (guint16) (button->priv->rgba.red * 65535);
  color->green = (guint16) (button->priv->rgba.green * 65535);
  color->blue = (guint16) (button->priv->rgba.blue * 65535);
702 703 704 705
}

/**
 * gtk_color_button_get_alpha:
Matthias Clasen's avatar
Matthias Clasen committed
706
 * @button: a #GtkColorButton
707
 *
708
 * Returns the current alpha value.
709
 *
710
 * Return value: an integer between 0 and 65535
711 712
 *
 * Since: 2.4
Matthias Clasen's avatar
Matthias Clasen committed
713 714
 *
 * Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
715
 */
716
guint16
Matthias Clasen's avatar
Matthias Clasen committed
717
gtk_color_button_get_alpha (GtkColorButton *button)
718
{
Matthias Clasen's avatar
Matthias Clasen committed
719
  g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), 0);
720

Matthias Clasen's avatar
Matthias Clasen committed
721
  return (guint16) (button->priv->rgba.alpha * 65535);
722 723 724
}

/**
725
 * gtk_color_button_set_rgba: (skip)
Matthias Clasen's avatar
Matthias Clasen committed
726
 * @button: a #GtkColorButton
727 728 729 730 731
 * @rgba: a #GdkRGBA to set the current color with
 *
 * Sets the current color to be @rgba.
 *
 * Since: 3.0
Matthias Clasen's avatar
Matthias Clasen committed
732 733
 *
 * Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
734
 */
735
void
Matthias Clasen's avatar
Matthias Clasen committed
736
gtk_color_button_set_rgba (GtkColorButton *button,
737 738
                           const GdkRGBA  *rgba)
{
Matthias Clasen's avatar
Matthias Clasen committed
739
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
740 741
  g_return_if_fail (rgba != NULL);

Matthias Clasen's avatar
Matthias Clasen committed
742 743
  button->priv->rgba = *rgba;
  gtk_widget_queue_draw (button->priv->draw_area);
744

Matthias Clasen's avatar
Matthias Clasen committed
745 746 747
  g_object_notify (G_OBJECT (button), "color");
  g_object_notify (G_OBJECT (button), "alpha");
  g_object_notify (G_OBJECT (button), "rgba");
748 749 750
}

/**
751
 * gtk_color_button_get_rgba: (skip)
Matthias Clasen's avatar
Matthias Clasen committed
752
 * @button: a #GtkColorButton
753
 * @rgba: (out): a #GdkRGBA to fill in with the current color
754 755 756 757
 *
 * Sets @rgba to be the current color in the #GtkColorButton widget.
 *
 * Since: 3.0
Matthias Clasen's avatar
Matthias Clasen committed
758 759
 *
 * Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
760
 */
761
void
Matthias Clasen's avatar
Matthias Clasen committed
762
gtk_color_button_get_rgba (GtkColorButton *button,
763 764
                           GdkRGBA        *rgba)
{
Matthias Clasen's avatar
Matthias Clasen committed
765
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
766 767
  g_return_if_fail (rgba != NULL);

Matthias Clasen's avatar
Matthias Clasen committed
768
  *rgba = button->priv->rgba;
769 770 771 772
}

/**
 * gtk_color_button_set_use_alpha:
Matthias Clasen's avatar
Matthias Clasen committed
773
 * @button: a #GtkColorButton
774
 * @use_alpha: %TRUE if color button should use alpha channel, %FALSE if not
775 776 777 778
 *
 * Sets whether or not the color button should use the alpha channel.
 *
 * Since: 2.4
Matthias Clasen's avatar
Matthias Clasen committed
779 780
 *
 * Deprecated: 3.4: Use gtk_color_chooser_set_use_alpha() instead.
781 782
 */
void
Matthias Clasen's avatar
Matthias Clasen committed
783
gtk_color_button_set_use_alpha (GtkColorButton *button,
784
                                gboolean        use_alpha)
785
{
Matthias Clasen's avatar
Matthias Clasen committed
786
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
787 788 789

  use_alpha = (use_alpha != FALSE);

Matthias Clasen's avatar
Matthias Clasen committed
790
  if (button->priv->use_alpha != use_alpha)
791
    {
Matthias Clasen's avatar
Matthias Clasen committed
792
      button->priv->use_alpha = use_alpha;
793

Matthias Clasen's avatar
Matthias Clasen committed
794
      gtk_widget_queue_draw (button->priv->draw_area);
795

Matthias Clasen's avatar
Matthias Clasen committed
796
      g_object_notify (G_OBJECT (button), "use-alpha");
797 798 799 800 801
    }
}

/**
 * gtk_color_button_get_use_alpha:
Matthias Clasen's avatar
Matthias Clasen committed
802
 * @button: a #GtkColorButton
803
 *
804
 * Does the color selection dialog use the alpha channel ?
805
 *
806
 * Returns: %TRUE if the color sample uses alpha channel, %FALSE if not
807 808
 *
 * Since: 2.4
Matthias Clasen's avatar
Matthias Clasen committed
809 810
 *
 * Deprecated: 3.4: Use gtk_color_chooser_get_use_alpha() instead.
811 812
 */
gboolean
Matthias Clasen's avatar
Matthias Clasen committed
813
gtk_color_button_get_use_alpha (GtkColorButton *button)
814
{
Matthias Clasen's avatar
Matthias Clasen committed
815
  g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), FALSE);
816

Matthias Clasen's avatar
Matthias Clasen committed
817
  return button->priv->use_alpha;
818 819 820 821 822
}


/**
 * gtk_color_button_set_title:
Matthias Clasen's avatar
Matthias Clasen committed
823
 * @button: a #GtkColorButton
824
 * @title: String containing new window title
825 826 827 828 829 830
 *
 * Sets the title for the color selection dialog.
 *
 * Since: 2.4
 */
void
Matthias Clasen's avatar
Matthias Clasen committed
831
gtk_color_button_set_title (GtkColorButton *button,
832
                            const gchar    *title)
833 834 835
{
  gchar *old_title;

Matthias Clasen's avatar
Matthias Clasen committed
836
  g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
837

Matthias Clasen's avatar
Matthias Clasen committed
838 839
  old_title = button->priv->title;
  button->priv->title = g_strdup (title);
840 841
  g_free (old_title);

Matthias Clasen's avatar
Matthias Clasen committed
842 843 844
  if (button->priv->cs_dialog)
    gtk_window_set_title (GTK_WINDOW (button->priv->cs_dialog),
                          button->priv->title);
845

Matthias Clasen's avatar
Matthias Clasen committed
846
  g_object_notify (G_OBJECT (button), "title");
847 848 849 850
}

/**
 * gtk_color_button_get_title:
Matthias Clasen's avatar
Matthias Clasen committed
851
 * @button: a #GtkColorButton
852 853 854 855 856 857 858
 *
 * Gets the title of the color selection dialog.
 *
 * Returns: An internal string, do not free the return value
 *
 * Since: 2.4
 */
859
const gchar *
Matthias Clasen's avatar
Matthias Clasen committed
860
gtk_color_button_get_title (GtkColorButton *button)
861
{
Matthias Clasen's avatar
Matthias Clasen committed
862
  g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), NULL);
863

Matthias Clasen's avatar
Matthias Clasen committed
864
  return button->priv->title;
865 866 867 868
}

static void
gtk_color_button_set_property (GObject      *object,
869 870 871
                               guint         param_id,
                               const GValue *value,
                               GParamSpec   *pspec)
872
{
Matthias Clasen's avatar
Matthias Clasen committed
873
  GtkColorButton *button = GTK_COLOR_BUTTON (object);
874

875
  switch (param_id)
876 877
    {
    case PROP_USE_ALPHA:
Matthias Clasen's avatar
Matthias Clasen committed
878
      gtk_color_button_set_use_alpha (button, g_value_get_boolean (value));
879 880
      break;
    case PROP_TITLE:
Matthias Clasen's avatar
Matthias Clasen committed
881
      gtk_color_button_set_title (button, g_value_get_string (value));
882 883
      break;
    case PROP_COLOR:
884 885 886 887 888 889 890 891 892 893 894
      {
        GdkColor *color;
        GdkRGBA rgba;

        color = g_value_get_boxed (value);

        rgba.red = color->red / 65535.0;
        rgba.green = color->green / 65535.0;
        rgba.blue = color->blue / 65535.0;
        rgba.alpha = 1.0;

Matthias Clasen's avatar
Matthias Clasen committed
895
        gtk_color_button_set_rgba (button, &rgba);
896
      }
897 898
      break;
    case PROP_ALPHA:
Matthias Clasen's avatar
Matthias Clasen committed
899
      gtk_color_button_set_alpha (button, g_value_get_uint (value));
900
      break;
901
    case PROP_RGBA:
Matthias Clasen's avatar
Matthias Clasen committed
902
      gtk_color_button_set_rgba (button, g_value_get_boxed (value));
903
      break;
904 905 906 907 908 909 910 911
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
      break;
    }
}

static void
gtk_color_button_get_property (GObject    *object,
912 913 914
                               guint       param_id,
                               GValue     *value,
                               GParamSpec *pspec)
915
{
Matthias Clasen's avatar
Matthias Clasen committed
916
  GtkColorButton *button = GTK_COLOR_BUTTON (object);
917

918
  switch (param_id)
919 920
    {
    case PROP_USE_ALPHA:
Matthias Clasen's avatar
Matthias Clasen committed
921
      g_value_set_boolean (value, gtk_color_button_get_use_alpha (button));
922 923
      break;
    case PROP_TITLE:
Matthias Clasen's avatar
Matthias Clasen committed
924
      g_value_set_string (value, gtk_color_button_get_title (button));
925 926
      break;
    case PROP_COLOR:
927 928 929 930
      {
        GdkColor color;
        GdkRGBA rgba;

Matthias Clasen's avatar
Matthias Clasen committed
931
        gtk_color_button_get_rgba (button, &rgba);
932 933 934 935 936 937 938

        color.red = (guint16) (rgba.red * 65535 + 0.5);
        color.green = (guint16) (rgba.green * 65535 + 0.5);
        color.blue = (guint16) (rgba.blue * 65535 + 0.5);

        g_value_set_boxed (value, &color);
      }
939 940
      break;
    case PROP_ALPHA:
Matthias Clasen's avatar
Matthias Clasen committed
941
      g_value_set_uint (value, gtk_color_button_get_alpha (button));
942
      break;
943 944 945 946
    case PROP_RGBA:
      {
        GdkRGBA rgba;

Matthias Clasen's avatar
Matthias Clasen committed
947
        gtk_color_button_get_rgba (button, &rgba);
948 949 950
        g_value_set_boxed (value, &rgba);
      }
      break;
951 952 953 954 955
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
      break;
    }
}
Matthias Clasen's avatar
Matthias Clasen committed
956

957 958
static void
gtk_color_button_add_palette (GtkColorChooser *chooser,
959
                              GtkOrientation   orientation,
960 961 962 963 964 965
                              gint             colors_per_line,
                              gint             n_colors,
                              GdkRGBA         *colors)
{
  GtkColorButton *button = GTK_COLOR_BUTTON (chooser);

966 967 968
  ensure_dialog (button);

  gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
969
                                   orientation, colors_per_line, n_colors, colors);
970 971
}

Matthias Clasen's avatar
Matthias Clasen committed
972 973 974 975 976 977 978 979
typedef void (* get_rgba) (GtkColorChooser *, GdkRGBA *);
typedef void (* set_rgba) (GtkColorChooser *, const GdkRGBA *);

static void
gtk_color_button_iface_init (GtkColorChooserInterface *iface)
{
  iface->get_rgba = (get_rgba)gtk_color_button_get_rgba;
  iface->set_rgba = (set_rgba)gtk_color_button_set_rgba;
980
  iface->add_palette = gtk_color_button_add_palette;
Matthias Clasen's avatar
Matthias Clasen committed
981 982
}