gtkcoloreditor.c 20 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include "gtkcoloreditorprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
21 22

#include "gtkcolorchooserprivate.h"
23 24 25
#include "gtkcolorplaneprivate.h"
#include "gtkcolorscaleprivate.h"
#include "gtkcolorswatchprivate.h"
26
#include "gtkcolorutils.h"
27
#include "gtkcolorpickerprivate.h"
28
#include "gtkgrid.h"
29
#include "gtkbutton.h"
30
#include "gtkintl.h"
31
#include "gtkorientable.h"
32
#include "gtkentry.h"
Matthias Clasen's avatar
Matthias Clasen committed
33
#include "gtkoverlay.h"
34
#include "gtkadjustment.h"
Matthias Clasen's avatar
Matthias Clasen committed
35
#include "gtklabel.h"
36
#include "gtkrender.h"
Matthias Clasen's avatar
Matthias Clasen committed
37
#include "gtkspinbutton.h"
38
#include "gtkstylecontext.h"
39

40
#include <math.h>
41 42 43

struct _GtkColorEditorPrivate
{
Matthias Clasen's avatar
Matthias Clasen committed
44
  GtkWidget *overlay;
45 46 47 48
  GtkWidget *grid;
  GtkWidget *swatch;
  GtkWidget *entry;
  GtkWidget *h_slider;
Matthias Clasen's avatar
Matthias Clasen committed
49 50
  GtkWidget *h_popup;
  GtkWidget *h_entry;
51
  GtkWidget *a_slider;
Matthias Clasen's avatar
Matthias Clasen committed
52 53 54 55 56 57 58 59
  GtkWidget *a_popup;
  GtkWidget *a_entry;
  GtkWidget *sv_plane;
  GtkWidget *sv_popup;
  GtkWidget *s_entry;
  GtkWidget *v_entry;
  GtkWidget *current_popup;
  GtkWidget *popdown_focus;
60 61

  GtkAdjustment *h_adj;
Matthias Clasen's avatar
Matthias Clasen committed
62 63
  GtkAdjustment *s_adj;
  GtkAdjustment *v_adj;
64
  GtkAdjustment *a_adj;
65

66 67 68
  GtkWidget *picker_button;
  GtkColorPicker *picker;

69 70
  gint popup_position;

Matthias Clasen's avatar
Matthias Clasen committed
71
  guint text_changed : 1;
Matthias Clasen's avatar
Matthias Clasen committed
72
  guint use_alpha    : 1;
73 74 75 76 77
};

enum
{
  PROP_ZERO,
Matthias Clasen's avatar
Matthias Clasen committed
78 79
  PROP_RGBA,
  PROP_USE_ALPHA
80 81 82 83 84
};

static void gtk_color_editor_iface_init (GtkColorChooserInterface *iface);

G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX,
85
                         G_ADD_PRIVATE (GtkColorEditor)
86 87 88
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
                                                gtk_color_editor_iface_init))

89 90 91 92 93 94 95 96 97 98
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;
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
99 100
entry_set_rgba (GtkColorEditor *editor,
                const GdkRGBA  *color)
101 102 103 104
{
  gchar *text;

  text = g_strdup_printf ("#%02X%02X%02X",
Matthias Clasen's avatar
Matthias Clasen committed
105 106 107
                          scale_round (color->red, 255),
                          scale_round (color->green, 255),
                          scale_round (color->blue, 255));
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), text);
  editor->priv->text_changed = FALSE;
  g_free (text);
}

static void
entry_apply (GtkWidget      *entry,
             GtkColorEditor *editor)
{
  GdkRGBA color;
  gchar *text;

  if (!editor->priv->text_changed)
    return;

  text = gtk_editable_get_chars (GTK_EDITABLE (editor->priv->entry), 0, -1);
  if (gdk_rgba_parse (&color, text))
    {
Matthias Clasen's avatar
Matthias Clasen committed
126
      color.alpha = gtk_adjustment_get_value (editor->priv->a_adj);
Matthias Clasen's avatar
Matthias Clasen committed
127
      gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), &color);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    }

  editor->priv->text_changed = FALSE;

  g_free (text);
}

static gboolean
entry_focus_out (GtkWidget      *entry,
                 GdkEventFocus  *event,
                 GtkColorEditor *editor)
{
  entry_apply (entry, editor);
  return FALSE;
}

static void
entry_text_changed (GtkWidget      *entry,
                    GParamSpec     *pspec,
                    GtkColorEditor *editor)
{
  editor->priv->text_changed = TRUE;
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
153
hsv_changed (GtkColorEditor *editor)
154
{
Matthias Clasen's avatar
Matthias Clasen committed
155
  GdkRGBA color;
Matthias Clasen's avatar
Matthias Clasen committed
156
  gdouble h, s, v, a;
Matthias Clasen's avatar
Matthias Clasen committed
157 158 159 160

  h = gtk_adjustment_get_value (editor->priv->h_adj);
  s = gtk_adjustment_get_value (editor->priv->s_adj);
  v = gtk_adjustment_get_value (editor->priv->v_adj);
Matthias Clasen's avatar
Matthias Clasen committed
161 162
  a = gtk_adjustment_get_value (editor->priv->a_adj);

Matthias Clasen's avatar
Matthias Clasen committed
163
  gtk_hsv_to_rgb (h, s, v, &color.red, &color.green, &color.blue);
Matthias Clasen's avatar
Matthias Clasen committed
164 165
  color.alpha = a;

Matthias Clasen's avatar
Matthias Clasen committed
166 167
  gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), &color);
  gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), &color);
Matthias Clasen's avatar
Matthias Clasen committed
168 169
  entry_set_rgba (editor, &color);

Matthias Clasen's avatar
Matthias Clasen committed
170
  g_object_notify (G_OBJECT (editor), "rgba");
171 172
}

173
static void
Matthias Clasen's avatar
Matthias Clasen committed
174 175 176 177 178 179
dismiss_current_popup (GtkColorEditor *editor)
{
  if (editor->priv->current_popup)
    {
      gtk_widget_hide (editor->priv->current_popup);
      editor->priv->current_popup = NULL;
180
      editor->priv->popup_position = 0;
Matthias Clasen's avatar
Matthias Clasen committed
181 182
      if (editor->priv->popdown_focus)
        {
183 184 185
          if (gtk_widget_is_visible (editor->priv->popdown_focus))
            gtk_widget_grab_focus (editor->priv->popdown_focus);
          g_clear_object (&editor->priv->popdown_focus);
Matthias Clasen's avatar
Matthias Clasen committed
186 187 188 189 190 191
        }
    }
}

static void
popup_edit (GtkWidget      *widget,
192 193
            GtkColorEditor *editor)
{
Matthias Clasen's avatar
Matthias Clasen committed
194 195 196
  GtkWidget *popup = NULL;
  GtkWidget *toplevel;
  GtkWidget *focus;
197 198
  gint position;
  gint s, e;
Matthias Clasen's avatar
Matthias Clasen committed
199 200 201 202 203

  if (widget == editor->priv->sv_plane)
    {
      popup = editor->priv->sv_popup;
      focus = editor->priv->s_entry;
204
      position = 0;
Matthias Clasen's avatar
Matthias Clasen committed
205 206 207 208 209
    }
  else if (widget == editor->priv->h_slider)
    {
      popup = editor->priv->h_popup;
      focus = editor->priv->h_entry;
210 211
      gtk_range_get_slider_range (GTK_RANGE (editor->priv->h_slider), &s, &e);
      position = (s + e) / 2;
Matthias Clasen's avatar
Matthias Clasen committed
212 213 214 215 216
    }
  else if (widget == editor->priv->a_slider)
    {
      popup = editor->priv->a_popup;
      focus = editor->priv->a_entry;
217 218
      gtk_range_get_slider_range (GTK_RANGE (editor->priv->a_slider), &s, &e);
      position = (s + e) / 2;
Matthias Clasen's avatar
Matthias Clasen committed
219 220
    }

221 222 223
  if (popup == editor->priv->current_popup)
    dismiss_current_popup (editor);
  else if (popup)
Matthias Clasen's avatar
Matthias Clasen committed
224 225 226
    {
      dismiss_current_popup (editor);
      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
227
      g_set_object (&editor->priv->popdown_focus, gtk_window_get_focus (GTK_WINDOW (toplevel)));
Matthias Clasen's avatar
Matthias Clasen committed
228
      editor->priv->current_popup = popup;
229
      editor->priv->popup_position = position;
Matthias Clasen's avatar
Matthias Clasen committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
      gtk_widget_show (popup);
      gtk_widget_grab_focus (focus);
    }
}

static gboolean
popup_key_press (GtkWidget      *popup,
                 GdkEventKey    *event,
                 GtkColorEditor *editor)
{
  if (event->keyval == GDK_KEY_Escape)
    {
      dismiss_current_popup (editor);
      return TRUE;
    }

  return FALSE;
}

static gboolean
get_child_position (GtkOverlay     *overlay,
                    GtkWidget      *widget,
                    GtkAllocation  *allocation,
                    GtkColorEditor *editor)
{
  GtkRequisition req;
  GtkAllocation alloc;
  gint s, e;

  gtk_widget_get_preferred_size (widget, &req, NULL);

261 262
  allocation->x = 0;
  allocation->y = 0;
Matthias Clasen's avatar
Matthias Clasen committed
263 264 265 266 267
  allocation->width = req.width;
  allocation->height = req.height;

  if (widget == editor->priv->sv_popup)
    {
268 269 270 271
      gtk_widget_translate_coordinates (editor->priv->sv_plane,
                                        gtk_widget_get_parent (editor->priv->grid),
                                        0, -6,
                                        &allocation->x, &allocation->y);
272
      if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
Matthias Clasen's avatar
Matthias Clasen committed
273 274 275 276 277 278 279 280 281
        allocation->x = 0;
      else
        allocation->x = gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width;
    }
  else if (widget == editor->priv->h_popup)
    {
      gtk_widget_get_allocation (editor->priv->h_slider, &alloc);
      gtk_range_get_slider_range (GTK_RANGE (editor->priv->h_slider), &s, &e);

282
      if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
Matthias Clasen's avatar
Matthias Clasen committed
283 284
        gtk_widget_translate_coordinates (editor->priv->h_slider,
                                          gtk_widget_get_parent (editor->priv->grid),
285
                                          - req.width - 6, editor->priv->popup_position - req.height / 2,
Matthias Clasen's avatar
Matthias Clasen committed
286 287 288 289
                                          &allocation->x, &allocation->y);
      else
        gtk_widget_translate_coordinates (editor->priv->h_slider,
                                          gtk_widget_get_parent (editor->priv->grid),
290
                                          alloc.width + 6, editor->priv->popup_position - req.height / 2,
Matthias Clasen's avatar
Matthias Clasen committed
291 292 293 294 295 296 297 298 299
                                          &allocation->x, &allocation->y);
    }
  else if (widget == editor->priv->a_popup)
    {
      gtk_widget_get_allocation (editor->priv->a_slider, &alloc);
      gtk_range_get_slider_range (GTK_RANGE (editor->priv->a_slider), &s, &e);

      gtk_widget_translate_coordinates (editor->priv->a_slider,
                                        gtk_widget_get_parent (editor->priv->grid),
300
                                        editor->priv->popup_position - req.width / 2, - req.height - 6,
Matthias Clasen's avatar
Matthias Clasen committed
301 302 303 304 305 306 307 308 309
                                        &allocation->x, &allocation->y);
    }
  else
    return FALSE;

  allocation->x = CLAMP (allocation->x, 0, gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width);
  allocation->y = CLAMP (allocation->y, 0, gtk_widget_get_allocated_height (GTK_WIDGET (overlay)) - req.height);

  return TRUE;
310 311
}

312
static void
Matthias Clasen's avatar
Matthias Clasen committed
313 314
value_changed (GtkAdjustment *a,
               GtkAdjustment *as)
315
{
Matthias Clasen's avatar
Matthias Clasen committed
316 317 318 319 320 321 322 323 324
  gdouble scale;

  scale = gtk_adjustment_get_upper (as) / gtk_adjustment_get_upper (a);
  g_signal_handlers_block_by_func (as, value_changed, a);
  gtk_adjustment_set_value (as, gtk_adjustment_get_value (a) * scale);
  g_signal_handlers_unblock_by_func (as, value_changed, a);
}

static GtkAdjustment *
Matthias Clasen's avatar
Matthias Clasen committed
325 326
scaled_adjustment (GtkAdjustment *a,
                   gdouble        scale)
Matthias Clasen's avatar
Matthias Clasen committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
{
  GtkAdjustment *as;

  as = gtk_adjustment_new (gtk_adjustment_get_value (a) * scale,
                           gtk_adjustment_get_lower (a) * scale,
                           gtk_adjustment_get_upper (a) * scale,
                           gtk_adjustment_get_step_increment (a) * scale,
                           gtk_adjustment_get_page_increment (a) * scale,
                           gtk_adjustment_get_page_size (a) * scale);

  g_signal_connect (a, "value-changed", G_CALLBACK (value_changed), as);
  g_signal_connect (as, "value-changed", G_CALLBACK (value_changed), a);

  return as;
}

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
344 345 346
popup_draw (GtkWidget      *popup,
            cairo_t        *cr,
            GtkColorEditor *editor)
Matthias Clasen's avatar
Matthias Clasen committed
347 348 349 350 351 352 353 354 355 356 357 358
{
  GtkStyleContext *context;
  gint width, height;

  context = gtk_widget_get_style_context (popup);
  width = gtk_widget_get_allocated_width (popup);
  height = gtk_widget_get_allocated_height (popup);

  gtk_render_background (context, cr, 0, 0, width, height);
  gtk_render_frame (context, cr, 0, 0, width, height);

  return FALSE;
359 360
}

361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
static void
color_picked (GObject      *source,
              GAsyncResult *res,
              gpointer      data)
{
  GtkColorPicker *picker = GTK_COLOR_PICKER (source);
  GtkColorEditor *editor = data;
  GError *error = NULL;
  GdkRGBA *color;

  color = gtk_color_picker_pick_finish (picker, res, &error);
  if (color == NULL)
    {
      g_warning ("Picking color failed: %s", error->message);
      g_error_free (error);
    }
  else
    {
      gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), color);
      gdk_rgba_free (color);
    }
}

static void
pick_color (GtkButton      *button,
            GtkColorEditor *editor)
{
  gtk_color_picker_pick (editor->priv->picker, color_picked, editor);
}

391 392 393
static void
gtk_color_editor_init (GtkColorEditor *editor)
{
394
  editor->priv = gtk_color_editor_get_instance_private (editor);
Matthias Clasen's avatar
Matthias Clasen committed
395
  editor->priv->use_alpha = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
396

397 398 399 400 401 402 403 404
  g_type_ensure (GTK_TYPE_COLOR_SCALE);
  g_type_ensure (GTK_TYPE_COLOR_PLANE);
  g_type_ensure (GTK_TYPE_COLOR_SWATCH);
  gtk_widget_init_template (GTK_WIDGET (editor));

  /* Some post processing is needed in code to set this up */
  gtk_widget_set_events (editor->priv->swatch,
			 gtk_widget_get_events (editor->priv->swatch)
405 406 407 408
                                 & ~(GDK_BUTTON_PRESS_MASK
                                     | GDK_BUTTON_RELEASE_MASK
                                     | GDK_KEY_PRESS_MASK
                                     | GDK_KEY_RELEASE_MASK));
409 410 411

  if (gtk_widget_get_direction (editor->priv->h_slider) == GTK_TEXT_DIR_RTL)
    gtk_style_context_add_class (gtk_widget_get_style_context (editor->priv->h_slider),
412
                                 "marks-before");
Matthias Clasen's avatar
Matthias Clasen committed
413
  else
414
    gtk_style_context_add_class (gtk_widget_get_style_context (editor->priv->h_slider),
415
                                 "marks-after");
Matthias Clasen's avatar
Matthias Clasen committed
416

417 418 419 420 421 422 423 424 425 426 427 428 429
  /* Create the scaled popup adjustments manually here because connecting user data is not
   * supported by template GtkBuilder xml (it would be possible to set this up in the xml
   * but require 4 separate callbacks and would be rather ugly).
   */
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->priv->h_entry), scaled_adjustment (editor->priv->h_adj, 100));
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->priv->s_entry), scaled_adjustment (editor->priv->s_adj, 100));
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->priv->v_entry), scaled_adjustment (editor->priv->v_adj, 100));
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->priv->a_entry), scaled_adjustment (editor->priv->a_adj, 100));

  /* This can be setup in the .ui file, but requires work in Glade otherwise it cannot be edited there */
  gtk_overlay_add_overlay (GTK_OVERLAY (editor->priv->overlay), editor->priv->sv_popup);
  gtk_overlay_add_overlay (GTK_OVERLAY (editor->priv->overlay), editor->priv->h_popup);
  gtk_overlay_add_overlay (GTK_OVERLAY (editor->priv->overlay), editor->priv->a_popup);
430 431

  gtk_style_context_remove_class (gtk_widget_get_style_context (editor->priv->swatch), "activatable");
432 433 434 435

  editor->priv->picker = gtk_color_picker_new ();
  if (editor->priv->picker == NULL)
    gtk_widget_hide (editor->priv->picker_button);
436 437
}

438 439 440 441 442 443
static void
gtk_color_editor_dispose (GObject *object)
{
  GtkColorEditor *editor = GTK_COLOR_EDITOR (object);

  dismiss_current_popup (editor);
444
  g_clear_object (&editor->priv->picker);
445 446 447 448

  G_OBJECT_CLASS (gtk_color_editor_parent_class)->dispose (object);
}

449 450 451 452 453 454
static void
gtk_color_editor_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
{
Matthias Clasen's avatar
Matthias Clasen committed
455
  GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
456 457 458 459
  GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);

  switch (prop_id)
    {
Matthias Clasen's avatar
Matthias Clasen committed
460
    case PROP_RGBA:
461 462
      {
        GdkRGBA color;
Matthias Clasen's avatar
Matthias Clasen committed
463
        gtk_color_chooser_get_rgba (cc, &color);
464 465
        g_value_set_boxed (value, &color);
      }
Matthias Clasen's avatar
Matthias Clasen committed
466
      break;
Matthias Clasen's avatar
Matthias Clasen committed
467
    case PROP_USE_ALPHA:
Matthias Clasen's avatar
Matthias Clasen committed
468 469
      g_value_set_boolean (value, gtk_widget_get_visible (ce->priv->a_slider));
      break;
470 471 472 473 474 475
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
476
static void
Matthias Clasen's avatar
Matthias Clasen committed
477 478
gtk_color_editor_set_use_alpha (GtkColorEditor *editor,
                                gboolean        use_alpha)
Matthias Clasen's avatar
Matthias Clasen committed
479
{
Matthias Clasen's avatar
Matthias Clasen committed
480
  if (editor->priv->use_alpha != use_alpha)
Matthias Clasen's avatar
Matthias Clasen committed
481
    {
Matthias Clasen's avatar
Matthias Clasen committed
482 483 484
      editor->priv->use_alpha = use_alpha;
      gtk_widget_set_visible (editor->priv->a_slider, use_alpha);
      gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (editor->priv->swatch), use_alpha);
Matthias Clasen's avatar
Matthias Clasen committed
485 486 487
    }
}

488 489 490 491 492 493
static void
gtk_color_editor_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
Matthias Clasen's avatar
Matthias Clasen committed
494
  GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
495 496 497 498
  GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);

  switch (prop_id)
    {
Matthias Clasen's avatar
Matthias Clasen committed
499 500
    case PROP_RGBA:
      gtk_color_chooser_set_rgba (cc, g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
501
      break;
Matthias Clasen's avatar
Matthias Clasen committed
502 503
    case PROP_USE_ALPHA:
      gtk_color_editor_set_use_alpha (ce, g_value_get_boolean (value));
Matthias Clasen's avatar
Matthias Clasen committed
504
      break;
505 506 507 508 509 510 511 512 513 514
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_color_editor_class_init (GtkColorEditorClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
515
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
516

517
  object_class->dispose = gtk_color_editor_dispose;
518 519 520
  object_class->get_property = gtk_color_editor_get_property;
  object_class->set_property = gtk_color_editor_set_property;

Matthias Clasen's avatar
Matthias Clasen committed
521 522
  g_object_class_override_property (object_class, PROP_RGBA, "rgba");
  g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
523

524 525 526
  /* Bind class to template
   */
  gtk_widget_class_set_template_from_resource (widget_class,
527
					       "/org/gtk/libgtk/ui/gtkcoloreditor.ui");
528

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, overlay);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, grid);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, swatch);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, entry);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, h_slider);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, h_popup);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, h_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, a_slider);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, a_popup);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, a_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, sv_plane);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, sv_popup);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, s_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, v_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, h_adj);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, s_adj);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, v_adj);
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, a_adj);
547
  gtk_widget_class_bind_template_child_private (widget_class, GtkColorEditor, picker_button);
548 549 550 551 552 553 554 555 556 557

  gtk_widget_class_bind_template_callback (widget_class, hsv_changed);
  gtk_widget_class_bind_template_callback (widget_class, popup_draw);
  gtk_widget_class_bind_template_callback (widget_class, popup_key_press);
  gtk_widget_class_bind_template_callback (widget_class, dismiss_current_popup);
  gtk_widget_class_bind_template_callback (widget_class, get_child_position);
  gtk_widget_class_bind_template_callback (widget_class, entry_text_changed);
  gtk_widget_class_bind_template_callback (widget_class, entry_apply);
  gtk_widget_class_bind_template_callback (widget_class, entry_focus_out);
  gtk_widget_class_bind_template_callback (widget_class, popup_edit);
558
  gtk_widget_class_bind_template_callback (widget_class, pick_color);
559 560 561
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
562 563
gtk_color_editor_get_rgba (GtkColorChooser *chooser,
                           GdkRGBA         *color)
564 565
{
  GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
Matthias Clasen's avatar
Matthias Clasen committed
566
  gdouble h, s, v;
567

Matthias Clasen's avatar
Matthias Clasen committed
568 569 570 571 572
  h = gtk_adjustment_get_value (editor->priv->h_adj);
  s = gtk_adjustment_get_value (editor->priv->s_adj);
  v = gtk_adjustment_get_value (editor->priv->v_adj);
  gtk_hsv_to_rgb (h, s, v, &color->red, &color->green, &color->blue);
  color->alpha = gtk_adjustment_get_value (editor->priv->a_adj);
573 574 575
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
576 577
gtk_color_editor_set_rgba (GtkColorChooser *chooser,
                           const GdkRGBA   *color)
578 579
{
  GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
580
  gdouble h, s, v;
581

582 583 584
  gtk_rgb_to_hsv (color->red, color->green, color->blue, &h, &s, &v);

  gtk_adjustment_set_value (editor->priv->h_adj, h);
Matthias Clasen's avatar
Matthias Clasen committed
585 586
  gtk_adjustment_set_value (editor->priv->s_adj, s);
  gtk_adjustment_set_value (editor->priv->v_adj, v);
587
  gtk_adjustment_set_value (editor->priv->a_adj, color->alpha);
Matthias Clasen's avatar
Matthias Clasen committed
588

Matthias Clasen's avatar
Matthias Clasen committed
589 590
  gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), color);
  gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), color);
Matthias Clasen's avatar
Matthias Clasen committed
591
  entry_set_rgba (editor, color);
592

Matthias Clasen's avatar
Matthias Clasen committed
593
  g_object_notify (G_OBJECT (editor), "rgba");
594 595 596 597 598
}

static void
gtk_color_editor_iface_init (GtkColorChooserInterface *iface)
{
Matthias Clasen's avatar
Matthias Clasen committed
599 600
  iface->get_rgba = gtk_color_editor_get_rgba;
  iface->set_rgba = gtk_color_editor_set_rgba;
601 602 603 604 605 606 607
}

GtkWidget *
gtk_color_editor_new (void)
{
  return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_EDITOR, NULL);
}