gtkcolorchooserwidget.c 24.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/* GTK - The GIMP Toolkit
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserwidget.h"
25 26
#include "gtkcoloreditorprivate.h"
#include "gtkcolorswatchprivate.h"
27 28 29 30
#include "gtkbox.h"
#include "gtkgrid.h"
#include "gtklabel.h"
#include "gtkorientable.h"
31
#include "gtkprivate.h"
32
#include "gtkintl.h"
Matthias Clasen's avatar
Matthias Clasen committed
33
#include "gtksizegroup.h"
34

Matthias Clasen's avatar
Matthias Clasen committed
35 36
#include <math.h>

Matthias Clasen's avatar
Matthias Clasen committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/**
 * SECTION:gtkcolorchooserwidget
 * @Short_description: A widget for choosing colors
 * @Title: GtkColorChooserWidget
 * @See_also: #GtkColorChooserDialog
 *
 * The #GtkColorChooserWidget widget lets the user select a
 * color. By default, the chooser presents a prefined palette
 * of colors, plus a small number of settable custom colors.
 * It is also possible to select a different color with the
 * single-color editor. To enter the single-color editing mode,
 * use the context menu of any color of the palette, or use the
 * '+' button to add a new custom color.
 *
 * The chooser automatically remembers the last selection, as well
 * as custom colors.
 *
 * To change the initially selected color, use gtk_color_chooser_set_rgba().
 * To get the selected font use gtk_color_chooser_get_rgba().
 *
 * The #GtkColorChooserWidget is used in the #GtkColorChooserDialog
 * to provide a dialog for selecting colors.
 *
 * Since: 3.4
 */

63 64 65 66
struct _GtkColorChooserWidgetPrivate
{
  GtkWidget *palette;
  GtkWidget *editor;
Matthias Clasen's avatar
Matthias Clasen committed
67
  GtkSizeGroup *size_group;
68

69
  GtkWidget *custom_label;
70 71
  GtkWidget *custom;

72
  GtkWidget *button;
73 74
  GtkColorSwatch *current;

Matthias Clasen's avatar
Matthias Clasen committed
75
  gboolean use_alpha;
76
  gboolean has_default_palette;
Matthias Clasen's avatar
Matthias Clasen committed
77

78 79 80 81 82 83
  GSettings *settings;
};

enum
{
  PROP_ZERO,
Matthias Clasen's avatar
Matthias Clasen committed
84 85
  PROP_RGBA,
  PROP_USE_ALPHA,
86
  PROP_SHOW_EDITOR
87 88 89 90 91 92 93 94 95 96 97 98
};

static void gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface);

G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWidget, gtk_color_chooser_widget, GTK_TYPE_BOX,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
                                                gtk_color_chooser_widget_iface_init))

static void
select_swatch (GtkColorChooserWidget *cc,
               GtkColorSwatch        *swatch)
{
99 100
  GdkRGBA color;

101 102
  if (cc->priv->current == swatch)
    return;
Matthias Clasen's avatar
Matthias Clasen committed
103

104
  if (cc->priv->current != NULL)
105 106
    gtk_widget_unset_state_flags (GTK_WIDGET (cc->priv->current), GTK_STATE_FLAG_SELECTED);
  gtk_widget_set_state_flags (GTK_WIDGET (swatch), GTK_STATE_FLAG_SELECTED, FALSE);
107
  cc->priv->current = swatch;
Matthias Clasen's avatar
Matthias Clasen committed
108

Matthias Clasen's avatar
Matthias Clasen committed
109
  gtk_color_swatch_get_rgba (swatch, &color);
110 111 112
  g_settings_set (cc->priv->settings, "selected-color", "(bdddd)",
                  TRUE, color.red, color.green, color.blue, color.alpha);

Matthias Clasen's avatar
Matthias Clasen committed
113
  g_object_notify (G_OBJECT (cc), "rgba");
114 115 116 117 118 119 120 121
}

static void
swatch_activate (GtkColorSwatch        *swatch,
                 GtkColorChooserWidget *cc)
{
  GdkRGBA color;

Matthias Clasen's avatar
Matthias Clasen committed
122
  gtk_color_swatch_get_rgba (swatch, &color);
123 124 125 126 127 128 129 130 131
  _gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
}

static void
swatch_customize (GtkColorSwatch        *swatch,
                  GtkColorChooserWidget *cc)
{
  GdkRGBA color;

Matthias Clasen's avatar
Matthias Clasen committed
132 133
  gtk_color_swatch_get_rgba (swatch, &color);
  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
134 135 136

  gtk_widget_hide (cc->priv->palette);
  gtk_widget_show (cc->priv->editor);
137
  g_object_notify (G_OBJECT (cc), "show-editor");
138 139 140 141
}

static void
swatch_selected (GtkColorSwatch        *swatch,
142
                 GtkStateFlags          previous,
143 144
                 GtkColorChooserWidget *cc)
{
145 146 147 148 149 150
  GtkStateFlags flags;

  flags = gtk_widget_get_state_flags (GTK_WIDGET (swatch));
  if ((flags & GTK_STATE_FLAG_SELECTED) != (previous & GTK_STATE_FLAG_SELECTED) &&
      (flags & GTK_STATE_FLAG_SELECTED) != 0)
    select_swatch (cc, swatch);
151 152 153
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
154 155
connect_swatch_signals (GtkWidget *p,
                        gpointer   data)
156 157 158
{
  g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
  g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
159
  g_signal_connect (p, "state-flags-changed", G_CALLBACK (swatch_selected), data);
160 161 162
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
163 164
button_activate (GtkColorSwatch        *swatch,
                 GtkColorChooserWidget *cc)
165
{
Matthias Clasen's avatar
Matthias Clasen committed
166 167 168 169 170 171 172
  /* somewhat random, makes the hairline nicely visible */
  GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };

  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);

  gtk_widget_hide (cc->priv->palette);
  gtk_widget_show (cc->priv->editor);
173
  g_object_notify (G_OBJECT (cc), "show-editor");
174 175 176
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
177 178
connect_button_signals (GtkWidget *p,
                        gpointer   data)
179
{
Matthias Clasen's avatar
Matthias Clasen committed
180
  g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
181 182 183
}

static void
184
save_custom_colors (GtkColorChooserWidget *cc)
185 186 187 188
{
  GVariantBuilder builder;
  GVariant *variant;
  GdkRGBA color;
189
  GList *children, *l;
190
  GtkWidget *child;
191 192 193

  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dddd)"));

194 195
  children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
  for (l = g_list_nth (children, 1); l != NULL; l = l->next)
196
    {
197
      child = l->data;
Matthias Clasen's avatar
Matthias Clasen committed
198
      if (gtk_color_swatch_get_rgba (GTK_COLOR_SWATCH (child), &color))
Matthias Clasen's avatar
Matthias Clasen committed
199 200
        g_variant_builder_add (&builder, "(dddd)",
                               color.red, color.green, color.blue, color.alpha);
201 202 203 204
    }

  variant = g_variant_builder_end (&builder);
  g_settings_set_value (cc->priv->settings, "custom-colors", variant);
205 206

  g_list_free (children);
207 208
}

Matthias Clasen's avatar
Matthias Clasen committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222
static void
connect_custom_signals (GtkWidget *p,
                        gpointer   data)
{
  connect_swatch_signals (p, data);
  g_signal_connect_swapped (p, "notify::rgba",
                            G_CALLBACK (save_custom_colors), data);
}

static void
gtk_color_chooser_widget_set_use_alpha (GtkColorChooserWidget *cc,
                                        gboolean               use_alpha)
{
  GList *children, *l;
223
  GList *palettes, *p;
Matthias Clasen's avatar
Matthias Clasen committed
224
  GtkWidget *swatch;
225
  GtkWidget *grid;
Matthias Clasen's avatar
Matthias Clasen committed
226 227 228 229

  cc->priv->use_alpha = use_alpha;
  gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cc->priv->editor), use_alpha);

230 231
  palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
  for (p = palettes; p; p = p->next)
Matthias Clasen's avatar
Matthias Clasen committed
232
    {
233 234
      grid = p->data;

235
      if (!GTK_IS_CONTAINER (grid))
236 237 238
        continue;

      children = gtk_container_get_children (GTK_CONTAINER (grid));
Matthias Clasen's avatar
Matthias Clasen committed
239 240 241 242 243 244 245
      for (l = children; l; l = l->next)
        {
          swatch = l->data;
          gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (swatch), use_alpha);
        }
      g_list_free (children);
    }
246
  g_list_free (palettes);
Matthias Clasen's avatar
Matthias Clasen committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

  gtk_widget_queue_draw (GTK_WIDGET (cc));
}

static void
gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
                                          gboolean               show_editor)
{
  if (show_editor)
    {
      GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };

      if (cc->priv->current)
        gtk_color_swatch_get_rgba (cc->priv->current, &color);
      gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
    }

  gtk_widget_set_visible (cc->priv->editor, show_editor);
  gtk_widget_set_visible (cc->priv->palette, !show_editor);
}

/* UI construction {{{1 */

270 271 272 273 274 275 276 277 278
static guint
scale_round (gdouble value, gdouble scale)
{
  value = floor (value * scale + 0.5);
  value = MAX (value, 0);
  value = MIN (value, scale);
  return (guint)value;
}

Matthias Clasen's avatar
Matthias Clasen committed
279
static gchar *
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
accessible_color_name (GdkRGBA *color)
{
  if (color->alpha < 1.0)
    return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"),
                            scale_round (color->red, 100),
                            scale_round (color->green, 100),
                            scale_round (color->blue, 100),
                            scale_round (color->alpha, 100));
  else
    return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%"),
                            scale_round (color->red, 100),
                            scale_round (color->green, 100),
                            scale_round (color->blue, 100));
}


296
static void
Matthias Clasen's avatar
Matthias Clasen committed
297 298 299 300 301 302
add_palette (GtkColorChooserWidget  *cc,
             gboolean                horizontal,
             gint                    colors_per_line,
             gint                    n_colors,
             GdkRGBA                *colors,
             const gchar           **names)
303 304 305
{
  GtkWidget *grid;
  GtkWidget *p;
Matthias Clasen's avatar
Matthias Clasen committed
306
  AtkObject *atk_obj;
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
  gint line, pos;
  gint i;
  gint left, right;

  grid = gtk_grid_new ();
  gtk_widget_set_margin_bottom (grid, 12);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
  gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);

  left = 0;
  right = colors_per_line - 1;
  if (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_RTL)
    {
      i = left;
      left = right;
      right = i;
    }

  for (i = 0; i < n_colors; i++)
    {
      p = gtk_color_swatch_new ();
329
      atk_obj = gtk_widget_get_accessible (p);
Matthias Clasen's avatar
Matthias Clasen committed
330 331
      if (names)
        {
332 333 334 335 336 337 338 339 340 341 342 343
          atk_object_set_description (atk_obj,
                                      g_dpgettext2 (GETTEXT_PACKAGE, "Color name", names[i]));
        }
      else
        {
          gchar *text, *name;

          name = accessible_color_name (&colors[i]);
          text = g_strdup_printf (_("Color: %s"), name);
          atk_object_set_description (atk_obj, text);
          g_free (text);
          g_free (name);
Matthias Clasen's avatar
Matthias Clasen committed
344
        }
345 346 347 348 349 350 351 352 353
      gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &colors[i]);
      connect_swatch_signals (p, cc);

      line = i / colors_per_line;
      pos = i % colors_per_line;

      if (horizontal)
        {
            if (pos == left)
354
              gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_LEFT);
355
            else if (pos == right)
356 357 358
              gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_RIGHT);

            gtk_grid_attach (GTK_GRID (grid), p, pos, line, 1, 1);
359 360 361 362
        }
      else
        {
          if (pos == 0)
363
            gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_TOP);
364
          else if (pos == colors_per_line - 1)
365 366 367
            gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_BOTTOM);

          gtk_grid_attach (GTK_GRID (grid), p, line, pos, 1, 1);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
       }
    }

  gtk_widget_show_all (grid);
}

static void
remove_default_palette (GtkColorChooserWidget *cc)
{
  GList *children, *l;
  GtkWidget *widget;

  if (!cc->priv->has_default_palette)
    return;

  children = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
  for (l = children; l; l = l->next)
    {
      widget = l->data;
      if (widget == cc->priv->custom_label || widget == cc->priv->custom)
        continue;
      gtk_container_remove (GTK_CONTAINER (cc->priv->palette), widget);
    }
  g_list_free (children);

  cc->priv->has_default_palette = FALSE;
}

static void
add_default_palette (GtkColorChooserWidget *cc)
{
  const gchar *default_colors[9][3] = {
400 401 402 403 404 405 406 407 408
    { "#ef2929", "#cc0000", "#a40000" }, /* Scarlet Red */
    { "#fcaf3e", "#f57900", "#ce5c00" }, /* Orange */
    { "#fce94f", "#edd400", "#c4a000" }, /* Butter */
    { "#8ae234", "#73d216", "#4e9a06" }, /* Chameleon */
    { "#729fcf", "#3465a4", "#204a87" }, /* Sky Blue */
    { "#ad7fa8", "#75507b", "#5c3566" }, /* Plum */
    { "#e9b96e", "#c17d11", "#8f5902" }, /* Chocolate */
    { "#888a85", "#555753", "#2e3436" }, /* Aluminum 1 */
    { "#eeeeec", "#d3d7cf", "#babdb6" }  /* Aluminum 2 */
409
  };
Matthias Clasen's avatar
Matthias Clasen committed
410
  const gchar *color_names[] = {
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
    NC_("Color name", "Light Scarlet Red"),
    NC_("Color name", "Scarlet Red"),
    NC_("Color name", "Dark Scarlet Red"),
    NC_("Color name", "Light Orange"),
    NC_("Color name", "Orange"),
    NC_("Color name", "Dark Orange"),
    NC_("Color name", "Light Butter"),
    NC_("Color name", "Butter"),
    NC_("Color name", "Dark Butter"),
    NC_("Color name", "Light Chameleon"),
    NC_("Color name", "Chameleon"),
    NC_("Color name", "Dark Chameleon"),
    NC_("Color name", "Light Sky Blue"),
    NC_("Color name", "Sky Blue"),
    NC_("Color name", "Dark Sky Blue"),
    NC_("Color name", "Light Plum"),
    NC_("Color name", "Plum"),
    NC_("Color name", "Dark Plum"),
    NC_("Color name", "Light Chocolate"),
    NC_("Color name", "Chocolate"),
    NC_("Color name", "Dark Chocolate"),
    NC_("Color name", "Light Aluminum 1"),
    NC_("Color name", "Aluminum 1"),
    NC_("Color name", "Dark Aluminum 1"),
    NC_("Color name", "Light Aluminum 2"),
    NC_("Color name", "Aluminum 2"),
    NC_("Color name", "Dark Aluminum 2")
Matthias Clasen's avatar
Matthias Clasen committed
438
  };
439
  const gchar *default_grays[9] = {
Matthias Clasen's avatar
Matthias Clasen committed
440 441 442 443 444 445 446 447 448 449 450
    "#000000", /* black */
    "#2e3436", /* very dark gray */
    "#555753", /* darker gray */
    "#888a85", /* dark gray */
    "#babdb6", /* medium gray */
    "#d3d7cf", /* light gray */
    "#eeeeec", /* lighter gray */
    "#f3f3f3", /* very light gray */
    "#ffffff"  /* white */
  };
  const gchar *gray_names[] = {
451 452 453 454 455 456 457 458 459
    NC_("Color name", "Black"),
    NC_("Color name", "Very Dark Gray"),
    NC_("Color name", "Darker Gray"),
    NC_("Color name", "Dark Gray"),
    NC_("Color name", "Medium Gray"),
    NC_("Color name", "Light Gray"),
    NC_("Color name", "Lighter Gray"),
    NC_("Color name", "Very Light Gray"),
    NC_("Color name", "White")
Jon McCann's avatar
Jon McCann committed
460
  };
461 462
  GdkRGBA colors[9*3];
  gint i, j;
463

464 465 466
  for (i = 0; i < 9; i++)
    for (j = 0; j < 3; j++)
      gdk_rgba_parse (&colors[i*3 + j], default_colors[i][j]);
467

Matthias Clasen's avatar
Matthias Clasen committed
468
  add_palette (cc, FALSE, 3, 9*3, colors, color_names);
469 470

  for (i = 0; i < 9; i++)
471
    gdk_rgba_parse (&colors[i], default_grays[i]);
472

Matthias Clasen's avatar
Matthias Clasen committed
473
  add_palette (cc, TRUE, 9, 9, colors, gray_names);
474

475 476
  cc->priv->has_default_palette = TRUE;
}
477

478 479 480
static void
gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
{
481
  GtkWidget *box;
482 483 484 485 486 487 488 489
  GtkWidget *p;
  GtkWidget *button;
  GtkWidget *label;
  gint i;
  GdkRGBA color;
  GVariant *variant;
  GVariantIter iter;
  gboolean selected;
Matthias Clasen's avatar
Matthias Clasen committed
490
  AtkObject *atk_obj;
491
  gchar *text, *name;
492

493
  cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc, GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetPrivate);
Matthias Clasen's avatar
Matthias Clasen committed
494

495 496
  cc->priv->use_alpha = TRUE;

497 498 499
  gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
  cc->priv->palette = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add (GTK_CONTAINER (cc), cc->priv->palette);
500

501
  add_default_palette (cc);
502

503 504 505
  cc->priv->custom = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
  g_object_set (box, "margin-top", 12, NULL);
  gtk_box_pack_end (GTK_BOX (cc->priv->palette), box, FALSE, TRUE, 0);
506 507 508 509 510

  /* translators: label for the custom section in the color chooser */
  cc->priv->custom_label = label = gtk_label_new (_("Custom"));
  gtk_widget_set_halign (label, GTK_ALIGN_START);
  gtk_box_pack_end (GTK_BOX (cc->priv->palette), label, FALSE, TRUE, 0);
511

512
  cc->priv->button = button = gtk_color_swatch_new ();
513
  gtk_widget_set_name (button, "add-color-button");
Matthias Clasen's avatar
Matthias Clasen committed
514 515 516
  atk_obj = gtk_widget_get_accessible (button);
  atk_object_set_role (atk_obj, ATK_ROLE_PUSH_BUTTON);
  atk_object_set_description (atk_obj, _("Create custom color"));
517 518
  connect_button_signals (button, cc);
  gtk_color_swatch_set_icon (GTK_COLOR_SWATCH (button), "list-add-symbolic");
519
  gtk_container_add (GTK_CONTAINER (box), button);
520 521 522 523 524 525

  cc->priv->settings = g_settings_new_with_path ("org.gtk.Settings.ColorChooser",
                                                 "/org/gtk/settings/color-chooser/");
  variant = g_settings_get_value (cc->priv->settings, "custom-colors");
  g_variant_iter_init (&iter, variant);
  i = 0;
526
  p = NULL;
527 528 529 530
  while (g_variant_iter_loop (&iter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha))
    {
      i++;
      p = gtk_color_swatch_new ();
Matthias Clasen's avatar
Matthias Clasen committed
531
      gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &color);
532
      gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
Matthias Clasen's avatar
Matthias Clasen committed
533
      atk_obj = gtk_widget_get_accessible (p);
534 535
      name = accessible_color_name (&color);
      text = g_strdup_printf (_("Custom color %d: %s"), i, name);
Matthias Clasen's avatar
Matthias Clasen committed
536 537
      atk_object_set_description (atk_obj, text);
      g_free (text);
538
      g_free (name);
539
      connect_custom_signals (p, cc);
540
      gtk_container_add (GTK_CONTAINER (box), p);
541 542 543 544 545 546 547

      if (i == 8)
        break;
    }
  g_variant_unref (variant);

  cc->priv->editor = gtk_color_editor_new ();
548 549 550 551 552 553
  gtk_widget_set_halign (cc->priv->editor, GTK_ALIGN_CENTER);
  gtk_widget_set_hexpand (cc->priv->editor, TRUE);

  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_container_add (GTK_CONTAINER (cc), box);
  gtk_container_add (GTK_CONTAINER (box), cc->priv->editor);
554 555 556 557 558

  g_settings_get (cc->priv->settings, "selected-color", "(bdddd)",
                  &selected,
                  &color.red, &color.green, &color.blue, &color.alpha);
  if (selected)
Matthias Clasen's avatar
Matthias Clasen committed
559
    gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), &color);
560 561 562 563 564 565 566

  gtk_widget_show_all (GTK_WIDGET (cc));
  gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
  gtk_widget_hide (GTK_WIDGET (cc));

  gtk_widget_set_no_show_all (cc->priv->palette, TRUE);
  gtk_widget_set_no_show_all (cc->priv->editor, TRUE);
Matthias Clasen's avatar
Matthias Clasen committed
567 568 569

  cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
  gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
570
  gtk_size_group_add_widget (cc->priv->size_group, box);
571 572
}

Matthias Clasen's avatar
Matthias Clasen committed
573 574
/* GObject implementation {{{1 */

575 576 577 578 579 580
static void
gtk_color_chooser_widget_get_property (GObject    *object,
                                       guint       prop_id,
                                       GValue     *value,
                                       GParamSpec *pspec)
{
Matthias Clasen's avatar
Matthias Clasen committed
581
  GtkColorChooserWidget *cw = GTK_COLOR_CHOOSER_WIDGET (object);
582 583 584 585
  GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);

  switch (prop_id)
    {
Matthias Clasen's avatar
Matthias Clasen committed
586
    case PROP_RGBA:
587 588 589
      {
        GdkRGBA color;

Matthias Clasen's avatar
Matthias Clasen committed
590
        gtk_color_chooser_get_rgba (cc, &color);
591 592
        g_value_set_boxed (value, &color);
      }
Matthias Clasen's avatar
Matthias Clasen committed
593
      break;
Matthias Clasen's avatar
Matthias Clasen committed
594 595
    case PROP_USE_ALPHA:
      g_value_set_boolean (value, cw->priv->use_alpha);
Matthias Clasen's avatar
Matthias Clasen committed
596
      break;
597 598 599
    case PROP_SHOW_EDITOR:
      g_value_set_boolean (value, gtk_widget_get_visible (cw->priv->editor));
      break;
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_color_chooser_widget_set_property (GObject      *object,
                                       guint         prop_id,
                                       const GValue *value,
                                       GParamSpec   *pspec)
{
  GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);

  switch (prop_id)
    {
Matthias Clasen's avatar
Matthias Clasen committed
616 617 618
    case PROP_RGBA:
      gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc),
                                  g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
619
      break;
Matthias Clasen's avatar
Matthias Clasen committed
620 621 622
    case PROP_USE_ALPHA:
      gtk_color_chooser_widget_set_use_alpha (cc,
                                              g_value_get_boolean (value));
Matthias Clasen's avatar
Matthias Clasen committed
623
      break;
624 625 626 627
    case PROP_SHOW_EDITOR:
      gtk_color_chooser_widget_set_show_editor (cc,
                                                g_value_get_boolean (value));
      break;
628 629 630 631 632 633 634 635 636 637 638
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_color_chooser_widget_finalize (GObject *object)
{
  GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);

Matthias Clasen's avatar
Matthias Clasen committed
639
  g_object_unref (cc->priv->size_group);
640 641 642 643 644 645 646 647 648 649 650 651 652 653
  g_object_unref (cc->priv->settings);

  G_OBJECT_CLASS (gtk_color_chooser_widget_parent_class)->finalize (object);
}

static void
gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->get_property = gtk_color_chooser_widget_get_property;
  object_class->set_property = gtk_color_chooser_widget_set_property;
  object_class->finalize = gtk_color_chooser_widget_finalize;

Matthias Clasen's avatar
Matthias Clasen committed
654 655
  g_object_class_override_property (object_class, PROP_RGBA, "rgba");
  g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
656

Matthias Clasen's avatar
Matthias Clasen committed
657 658 659 660 661 662 663 664 665
  /**
   * GtkColorChooserWidget:show-editor:
   *
   * The ::show-editor property is %TRUE when the color chooser
   * is showing the single-color editor. It can be set to switch
   * the color chooser into single-color editing mode.
   *
   * Since: 3.4
   */
666 667 668 669
  g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
      g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
                            FALSE, GTK_PARAM_READWRITE));

670 671 672
  g_type_class_add_private (object_class, sizeof (GtkColorChooserWidgetPrivate));
}

Matthias Clasen's avatar
Matthias Clasen committed
673 674
/* GtkColorChooser implementation {{{1 */

675
static void
Matthias Clasen's avatar
Matthias Clasen committed
676 677
gtk_color_chooser_widget_get_rgba (GtkColorChooser *chooser,
                                   GdkRGBA         *color)
678 679 680 681
{
  GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);

  if (gtk_widget_get_visible (cc->priv->editor))
Matthias Clasen's avatar
Matthias Clasen committed
682
    gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), color);
683
  else if (cc->priv->current)
Matthias Clasen's avatar
Matthias Clasen committed
684
    gtk_color_swatch_get_rgba (cc->priv->current, color);
685 686 687 688 689 690 691
  else
    {
      color->red = 1.0;
      color->green = 1.0;
      color->blue = 1.0;
      color->alpha = 1.0;
    }
Matthias Clasen's avatar
Matthias Clasen committed
692

Matthias Clasen's avatar
Matthias Clasen committed
693
  if (!cc->priv->use_alpha)
Matthias Clasen's avatar
Matthias Clasen committed
694
    color->alpha = 1.0;
695 696
}

697 698 699 700 701 702
static void
add_custom_color (GtkColorChooserWidget *cc,
                  const GdkRGBA         *color)
{
  GtkWidget *last;
  GtkWidget *p;
703
  GList *children;
704

705
  children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
706
  if (g_list_length (children) >= 8)
707
    {
708 709
      last = g_list_last (children)->data;
      gtk_widget_destroy (last);
710
    }
711

712
  g_list_free (children);
713 714

  p = gtk_color_swatch_new ();
Matthias Clasen's avatar
Matthias Clasen committed
715
  gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), color);
716 717 718
  gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
  connect_custom_signals (p, cc);

719 720
  gtk_container_add (GTK_CONTAINER (cc->priv->custom), p);
  gtk_box_reorder_child (GTK_BOX (cc->priv->custom), p, 1);
721 722 723 724 725 726
  gtk_widget_show (p);

  select_swatch (cc, GTK_COLOR_SWATCH (p));
  save_custom_colors (cc);
}

727
static void
Matthias Clasen's avatar
Matthias Clasen committed
728 729
gtk_color_chooser_widget_set_rgba (GtkColorChooser *chooser,
                                   const GdkRGBA   *color)
730 731 732
{
  GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
  GList *children, *l;
733
  GList *palettes, *p;
734
  GtkColorSwatch *swatch;
735
  GtkWidget *w;
736 737
  GdkRGBA c;

738 739
  palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
  for (p = palettes; p; p = p->next)
740
    {
741 742
      w = p->data;
      if (!GTK_IS_GRID (w) && !GTK_IS_BOX (w))
743 744
        continue;

745
      children = gtk_container_get_children (GTK_CONTAINER (w));
746 747 748
      for (l = children; l; l = l->next)
        {
          swatch = l->data;
Matthias Clasen's avatar
Matthias Clasen committed
749 750
          gtk_color_swatch_get_rgba (swatch, &c);
          if (!cc->priv->use_alpha)
Matthias Clasen's avatar
Matthias Clasen committed
751
            c.alpha = color->alpha;
752 753 754 755 756 757 758 759 760
          if (gdk_rgba_equal (color, &c))
            {
              select_swatch (cc, swatch);
              g_list_free (children);
              return;
            }
        }
      g_list_free (children);
    }
761
  g_list_free (palettes);
762

763
  add_custom_color (cc, color);
764 765
}

766 767 768 769 770 771 772 773 774 775
static void
gtk_color_chooser_widget_add_palette (GtkColorChooser *chooser,
                                      gboolean         horizontal,
                                      gint             colors_per_line,
                                      gint             n_colors,
                                      GdkRGBA         *colors)
{
  GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);

  remove_default_palette (cc);
Matthias Clasen's avatar
Matthias Clasen committed
776
  add_palette (cc, horizontal, colors_per_line, n_colors, colors, NULL);
777 778
}

779 780 781
static void
gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface)
{
Matthias Clasen's avatar
Matthias Clasen committed
782 783
  iface->get_rgba = gtk_color_chooser_widget_get_rgba;
  iface->set_rgba = gtk_color_chooser_widget_set_rgba;
784
  iface->add_palette = gtk_color_chooser_widget_add_palette;
785 786
}

Matthias Clasen's avatar
Matthias Clasen committed
787 788
/* Public API {{{1 */

Matthias Clasen's avatar
Matthias Clasen committed
789 790 791 792 793 794 795 796 797
/**
 * gtk_color_chooser_widget_new:
 *
 * Creates a new #GtkColorChooserWidget.
 *
 * Returns: a new #GtkColorChooserWidget
 *
 * Since: 3.4
 */
798 799 800 801 802
GtkWidget *
gtk_color_chooser_widget_new (void)
{
  return g_object_new (GTK_TYPE_COLOR_CHOOSER_WIDGET, NULL);
}
Matthias Clasen's avatar
Matthias Clasen committed
803 804

/* vim:set foldmethod=marker: */