1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22 
23 #include "libgimpmath/gimpmath.h"
24 #include "libgimpcolor/gimpcolor.h"
25 #include "libgimpconfig/gimpconfig.h"
26 #include "libgimpwidgets/gimpwidgets.h"
27 
28 #include "widgets-types.h"
29 
30 #include "gegl/gimp-babl.h"
31 
32 #include "core/gimpimage.h"
33 
34 #include "gimpcolorframe.h"
35 
36 #include "gimp-intl.h"
37 
38 
39 #define RGBA_EPSILON 1e-6
40 
41 enum
42 {
43   PROP_0,
44   PROP_MODE,
45   PROP_HAS_NUMBER,
46   PROP_NUMBER,
47   PROP_HAS_COLOR_AREA,
48   PROP_HAS_COORDS,
49   PROP_ELLIPSIZE,
50 };
51 
52 
53 /*  local function prototypes  */
54 
55 static void       gimp_color_frame_dispose           (GObject        *object);
56 static void       gimp_color_frame_finalize          (GObject        *object);
57 static void       gimp_color_frame_get_property      (GObject        *object,
58                                                       guint           property_id,
59                                                       GValue         *value,
60                                                       GParamSpec     *pspec);
61 static void       gimp_color_frame_set_property      (GObject        *object,
62                                                       guint           property_id,
63                                                       const GValue   *value,
64                                                       GParamSpec     *pspec);
65 
66 static void       gimp_color_frame_style_set         (GtkWidget      *widget,
67                                                       GtkStyle       *prev_style);
68 static gboolean   gimp_color_frame_expose            (GtkWidget      *widget,
69                                                       GdkEventExpose *eevent);
70 
71 static void       gimp_color_frame_combo_callback    (GtkWidget      *widget,
72                                                       GimpColorFrame *frame);
73 static void       gimp_color_frame_update            (GimpColorFrame *frame);
74 
75 static void       gimp_color_frame_create_transform  (GimpColorFrame *frame);
76 static void       gimp_color_frame_destroy_transform (GimpColorFrame *frame);
77 
78 
G_DEFINE_TYPE(GimpColorFrame,gimp_color_frame,GIMP_TYPE_FRAME)79 G_DEFINE_TYPE (GimpColorFrame, gimp_color_frame, GIMP_TYPE_FRAME)
80 
81 #define parent_class gimp_color_frame_parent_class
82 
83 
84 static void
85 gimp_color_frame_class_init (GimpColorFrameClass *klass)
86 {
87   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
88   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
89 
90   object_class->dispose      = gimp_color_frame_dispose;
91   object_class->finalize     = gimp_color_frame_finalize;
92   object_class->get_property = gimp_color_frame_get_property;
93   object_class->set_property = gimp_color_frame_set_property;
94 
95   widget_class->style_set    = gimp_color_frame_style_set;
96   widget_class->expose_event = gimp_color_frame_expose;
97 
98   g_object_class_install_property (object_class, PROP_MODE,
99                                    g_param_spec_enum ("mode",
100                                                       NULL, NULL,
101                                                       GIMP_TYPE_COLOR_PICK_MODE,
102                                                       GIMP_COLOR_PICK_MODE_PIXEL,
103                                                       GIMP_PARAM_READWRITE));
104 
105   g_object_class_install_property (object_class, PROP_HAS_NUMBER,
106                                    g_param_spec_boolean ("has-number",
107                                                          NULL, NULL,
108                                                          FALSE,
109                                                          GIMP_PARAM_READWRITE));
110 
111   g_object_class_install_property (object_class, PROP_NUMBER,
112                                    g_param_spec_int ("number",
113                                                      NULL, NULL,
114                                                      0, 256, 0,
115                                                      GIMP_PARAM_READWRITE));
116 
117   g_object_class_install_property (object_class, PROP_HAS_COLOR_AREA,
118                                    g_param_spec_boolean ("has-color-area",
119                                                          NULL, NULL,
120                                                          FALSE,
121                                                          GIMP_PARAM_READWRITE));
122 
123   g_object_class_install_property (object_class, PROP_HAS_COORDS,
124                                    g_param_spec_boolean ("has-coords",
125                                                          NULL, NULL,
126                                                          FALSE,
127                                                          GIMP_PARAM_READWRITE));
128 
129   g_object_class_install_property (object_class, PROP_ELLIPSIZE,
130                                    g_param_spec_enum ("ellipsize",
131                                                       NULL, NULL,
132                                                       PANGO_TYPE_ELLIPSIZE_MODE,
133                                                       PANGO_ELLIPSIZE_NONE,
134                                                       GIMP_PARAM_READWRITE));
135 }
136 
137 static void
gimp_color_frame_init(GimpColorFrame * frame)138 gimp_color_frame_init (GimpColorFrame *frame)
139 {
140   GtkListStore *store;
141   GtkWidget    *vbox;
142   GtkWidget    *vbox2;
143   GtkWidget    *label;
144   gint          i;
145 
146   frame->sample_valid  = FALSE;
147   frame->sample_format = babl_format ("R'G'B' u8");
148 
149   gimp_rgba_set (&frame->color, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
150 
151   /* create the store manually so the values have a nice order */
152   store = gimp_enum_store_new_with_values (GIMP_TYPE_COLOR_PICK_MODE,
153                                            GIMP_COLOR_PICK_MODE_LAST + 1,
154                                            GIMP_COLOR_PICK_MODE_PIXEL,
155                                            GIMP_COLOR_PICK_MODE_RGB_PERCENT,
156                                            GIMP_COLOR_PICK_MODE_RGB_U8,
157                                            GIMP_COLOR_PICK_MODE_HSV,
158                                            GIMP_COLOR_PICK_MODE_LCH,
159                                            GIMP_COLOR_PICK_MODE_LAB,
160                                            GIMP_COLOR_PICK_MODE_XYY,
161                                            GIMP_COLOR_PICK_MODE_YUV,
162                                            GIMP_COLOR_PICK_MODE_CMYK);
163   frame->combo = gimp_enum_combo_box_new_with_model (GIMP_ENUM_STORE (store));
164   g_object_unref (store);
165 
166   gtk_frame_set_label_widget (GTK_FRAME (frame), frame->combo);
167   gtk_widget_show (frame->combo);
168 
169   g_signal_connect (frame->combo, "changed",
170                     G_CALLBACK (gimp_color_frame_combo_callback),
171                     frame);
172 
173   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
174   gtk_container_add (GTK_CONTAINER (frame), vbox);
175   gtk_widget_show (vbox);
176 
177   frame->color_area =
178     g_object_new (GIMP_TYPE_COLOR_AREA,
179                   "color",          &frame->color,
180                   "type",           GIMP_COLOR_AREA_SMALL_CHECKS,
181                   "drag-mask",      GDK_BUTTON1_MASK,
182                   "draw-border",    TRUE,
183                   "height-request", 20,
184                   NULL);
185   gtk_box_pack_start (GTK_BOX (vbox), frame->color_area, FALSE, FALSE, 0);
186 
187   vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
188   gtk_box_set_homogeneous (GTK_BOX (vbox2), TRUE);
189   gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
190   gtk_widget_show (vbox2);
191 
192   for (i = 0; i < GIMP_COLOR_FRAME_ROWS; i++)
193     {
194       GtkWidget *hbox;
195 
196       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
197       gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
198       gtk_widget_show (hbox);
199 
200       frame->name_labels[i] = gtk_label_new (" ");
201       gtk_label_set_xalign (GTK_LABEL (frame->name_labels[i]), 0.0);
202       gtk_box_pack_start (GTK_BOX (hbox), frame->name_labels[i],
203                           FALSE, FALSE, 0);
204       gtk_widget_show (frame->name_labels[i]);
205 
206       frame->value_labels[i] = gtk_label_new (" ");
207       gtk_label_set_selectable (GTK_LABEL (frame->value_labels[i]), TRUE);
208       gtk_label_set_xalign (GTK_LABEL (frame->value_labels[i]), 1.0);
209       gtk_box_pack_end (GTK_BOX (hbox), frame->value_labels[i],
210                         TRUE, TRUE, 0);
211       gtk_widget_show (frame->value_labels[i]);
212     }
213 
214   frame->coords_box_x = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
215   gtk_box_pack_start (GTK_BOX (vbox), frame->coords_box_x, FALSE, FALSE, 0);
216 
217   /* TRANSLATORS: X for the X coordinate. */
218   label = gtk_label_new (C_("Coordinates", "X:"));
219   gtk_box_pack_start (GTK_BOX (frame->coords_box_x), label, FALSE, FALSE, 0);
220   gtk_widget_show (label);
221 
222   frame->coords_label_x = gtk_label_new (" ");
223   gtk_label_set_selectable (GTK_LABEL (frame->coords_label_x), TRUE);
224   gtk_box_pack_end (GTK_BOX (frame->coords_box_x), frame->coords_label_x,
225                     FALSE, FALSE, 0);
226   gtk_widget_show (frame->coords_label_x);
227 
228   frame->coords_box_y = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
229   gtk_box_pack_start (GTK_BOX (vbox), frame->coords_box_y, FALSE, FALSE, 0);
230 
231   /* TRANSLATORS: Y for the Y coordinate. */
232   label = gtk_label_new (C_("Coordinates", "Y:"));
233   gtk_box_pack_start (GTK_BOX (frame->coords_box_y), label, FALSE, FALSE, 0);
234   gtk_widget_show (label);
235 
236   frame->coords_label_y = gtk_label_new (" ");
237   gtk_label_set_selectable (GTK_LABEL (frame->coords_label_y), TRUE);
238   gtk_box_pack_end (GTK_BOX (frame->coords_box_y), frame->coords_label_y,
239                     FALSE, FALSE, 0);
240   gtk_widget_show (frame->coords_label_y);
241 }
242 
243 static void
gimp_color_frame_dispose(GObject * object)244 gimp_color_frame_dispose (GObject *object)
245 {
246   GimpColorFrame *frame = GIMP_COLOR_FRAME (object);
247 
248   gimp_color_frame_set_color_config (frame, NULL);
249 
250   G_OBJECT_CLASS (parent_class)->dispose (object);
251 }
252 
253 static void
gimp_color_frame_finalize(GObject * object)254 gimp_color_frame_finalize (GObject *object)
255 {
256   GimpColorFrame *frame = GIMP_COLOR_FRAME (object);
257 
258   g_clear_object (&frame->number_layout);
259 
260   G_OBJECT_CLASS (parent_class)->finalize (object);
261 }
262 
263 static void
gimp_color_frame_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)264 gimp_color_frame_get_property (GObject    *object,
265                                guint       property_id,
266                                GValue     *value,
267                                GParamSpec *pspec)
268 {
269   GimpColorFrame *frame = GIMP_COLOR_FRAME (object);
270 
271   switch (property_id)
272     {
273     case PROP_MODE:
274       g_value_set_enum (value, frame->pick_mode);
275       break;
276 
277     case PROP_ELLIPSIZE:
278       g_value_set_enum (value, frame->ellipsize);
279       break;
280 
281     case PROP_HAS_NUMBER:
282       g_value_set_boolean (value, frame->has_number);
283       break;
284 
285     case PROP_NUMBER:
286       g_value_set_int (value, frame->number);
287       break;
288 
289     case PROP_HAS_COLOR_AREA:
290       g_value_set_boolean (value, frame->has_color_area);
291       break;
292 
293     case PROP_HAS_COORDS:
294       g_value_set_boolean (value, frame->has_coords);
295       break;
296 
297     default:
298       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
299       break;
300     }
301 }
302 
303 static void
gimp_color_frame_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)304 gimp_color_frame_set_property (GObject      *object,
305                                guint         property_id,
306                                const GValue *value,
307                                GParamSpec   *pspec)
308 {
309   GimpColorFrame *frame = GIMP_COLOR_FRAME (object);
310 
311   switch (property_id)
312     {
313     case PROP_MODE:
314       gimp_color_frame_set_mode (frame, g_value_get_enum (value));
315       break;
316 
317     case PROP_ELLIPSIZE:
318       gimp_color_frame_set_ellipsize (frame, g_value_get_enum (value));
319       break;
320 
321     case PROP_HAS_NUMBER:
322       gimp_color_frame_set_has_number (frame, g_value_get_boolean (value));
323       break;
324 
325     case PROP_NUMBER:
326       gimp_color_frame_set_number (frame, g_value_get_int (value));
327       break;
328 
329     case PROP_HAS_COLOR_AREA:
330       gimp_color_frame_set_has_color_area (frame, g_value_get_boolean (value));
331       break;
332 
333     case PROP_HAS_COORDS:
334       gimp_color_frame_set_has_coords (frame, g_value_get_boolean (value));
335       break;
336 
337     default:
338       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
339       break;
340     }
341 }
342 
343 static void
gimp_color_frame_style_set(GtkWidget * widget,GtkStyle * prev_style)344 gimp_color_frame_style_set (GtkWidget *widget,
345                             GtkStyle  *prev_style)
346 {
347   GimpColorFrame *frame = GIMP_COLOR_FRAME (widget);
348 
349   GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
350 
351   g_clear_object (&frame->number_layout);
352 }
353 
354 static gboolean
gimp_color_frame_expose(GtkWidget * widget,GdkEventExpose * eevent)355 gimp_color_frame_expose (GtkWidget      *widget,
356                          GdkEventExpose *eevent)
357 {
358   GimpColorFrame *frame = GIMP_COLOR_FRAME (widget);
359 
360   if (frame->has_number)
361     {
362       GtkStyle      *style = gtk_widget_get_style (widget);
363       GtkAllocation  allocation;
364       GtkAllocation  combo_allocation;
365       GtkAllocation  color_area_allocation;
366       GtkAllocation  coords_box_x_allocation;
367       GtkAllocation  coords_box_y_allocation;
368       cairo_t       *cr;
369       gchar          buf[8];
370       gint           w, h;
371       gdouble        scale;
372 
373       gtk_widget_get_allocation (widget, &allocation);
374       gtk_widget_get_allocation (frame->combo, &combo_allocation);
375       gtk_widget_get_allocation (frame->color_area, &color_area_allocation);
376       gtk_widget_get_allocation (frame->coords_box_x, &coords_box_x_allocation);
377       gtk_widget_get_allocation (frame->coords_box_y, &coords_box_y_allocation);
378 
379       cr = gdk_cairo_create (gtk_widget_get_window (widget));
380       gdk_cairo_region (cr, eevent->region);
381       cairo_clip (cr);
382 
383       cairo_translate (cr, allocation.x, allocation.y);
384 
385       gdk_cairo_set_source_color (cr, &style->light[GTK_STATE_NORMAL]);
386 
387       g_snprintf (buf, sizeof (buf), "%d", frame->number);
388 
389       if (! frame->number_layout)
390         frame->number_layout = gtk_widget_create_pango_layout (widget, NULL);
391 
392       pango_layout_set_text (frame->number_layout, buf, -1);
393       pango_layout_get_pixel_size (frame->number_layout, &w, &h);
394 
395       scale = ((gdouble) (allocation.height -
396                           combo_allocation.height -
397                           color_area_allocation.height -
398                           (coords_box_x_allocation.height +
399                            coords_box_y_allocation.height)) /
400                (gdouble) h);
401 
402       cairo_scale (cr, scale, scale);
403 
404       cairo_move_to (cr,
405                      (allocation.width / 2.0) / scale - w / 2.0,
406                      (allocation.height / 2.0 +
407                       combo_allocation.height / 2.0 +
408                       color_area_allocation.height / 2.0 +
409                       coords_box_x_allocation.height / 2.0 +
410                       coords_box_y_allocation.height / 2.0) / scale - h / 2.0);
411       pango_cairo_show_layout (cr, frame->number_layout);
412 
413       cairo_destroy (cr);
414     }
415 
416   return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, eevent);
417 }
418 
419 
420 /*  public functions  */
421 
422 /**
423  * gimp_color_frame_new:
424  *
425  * Creates a new #GimpColorFrame widget.
426  *
427  * Return value: The new #GimpColorFrame widget.
428  **/
429 GtkWidget *
gimp_color_frame_new(void)430 gimp_color_frame_new (void)
431 {
432   return g_object_new (GIMP_TYPE_COLOR_FRAME, NULL);
433 }
434 
435 
436 /**
437  * gimp_color_frame_set_mode:
438  * @frame: The #GimpColorFrame.
439  * @mode:  The new @mode.
440  *
441  * Sets the #GimpColorFrame's color pick @mode. Calling this function
442  * does the same as selecting the @mode from the frame's #GtkComboBox.
443  **/
444 void
gimp_color_frame_set_mode(GimpColorFrame * frame,GimpColorPickMode mode)445 gimp_color_frame_set_mode (GimpColorFrame    *frame,
446                            GimpColorPickMode  mode)
447 {
448   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
449 
450   gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (frame->combo), mode);
451 }
452 
453 void
gimp_color_frame_set_ellipsize(GimpColorFrame * frame,PangoEllipsizeMode ellipsize)454 gimp_color_frame_set_ellipsize (GimpColorFrame     *frame,
455                                 PangoEllipsizeMode  ellipsize)
456 {
457   gint i;
458 
459   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
460 
461   if (ellipsize != frame->ellipsize)
462     {
463       frame->ellipsize = ellipsize;
464 
465       for (i = 0; i < GIMP_COLOR_FRAME_ROWS; i++)
466         {
467           if (frame->value_labels[i])
468             gtk_label_set_ellipsize (GTK_LABEL (frame->value_labels[i]),
469                                      ellipsize);
470         }
471     }
472 }
473 
474 void
gimp_color_frame_set_has_number(GimpColorFrame * frame,gboolean has_number)475 gimp_color_frame_set_has_number (GimpColorFrame *frame,
476                                  gboolean        has_number)
477 {
478   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
479 
480   if (has_number != frame->has_number)
481     {
482       frame->has_number = has_number ? TRUE : FALSE;
483 
484       gtk_widget_queue_draw (GTK_WIDGET (frame));
485 
486       g_object_notify (G_OBJECT (frame), "has-number");
487     }
488 }
489 
490 void
gimp_color_frame_set_number(GimpColorFrame * frame,gint number)491 gimp_color_frame_set_number (GimpColorFrame *frame,
492                              gint            number)
493 {
494   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
495 
496   if (number != frame->number)
497     {
498       frame->number = number;
499 
500       gtk_widget_queue_draw (GTK_WIDGET (frame));
501 
502       g_object_notify (G_OBJECT (frame), "number");
503     }
504 }
505 
506 void
gimp_color_frame_set_has_color_area(GimpColorFrame * frame,gboolean has_color_area)507 gimp_color_frame_set_has_color_area (GimpColorFrame *frame,
508                                      gboolean        has_color_area)
509 {
510   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
511 
512   if (has_color_area != frame->has_color_area)
513     {
514       frame->has_color_area = has_color_area ? TRUE : FALSE;
515 
516       g_object_set (frame->color_area, "visible", frame->has_color_area, NULL);
517 
518       g_object_notify (G_OBJECT (frame), "has-color-area");
519     }
520 }
521 
522 void
gimp_color_frame_set_has_coords(GimpColorFrame * frame,gboolean has_coords)523 gimp_color_frame_set_has_coords (GimpColorFrame *frame,
524                                  gboolean        has_coords)
525 {
526   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
527 
528   if (has_coords != frame->has_coords)
529     {
530       frame->has_coords = has_coords ? TRUE : FALSE;
531 
532       g_object_set (frame->coords_box_x, "visible", frame->has_coords, NULL);
533       g_object_set (frame->coords_box_y, "visible", frame->has_coords, NULL);
534 
535       g_object_notify (G_OBJECT (frame), "has-coords");
536     }
537 }
538 
539 /**
540  * gimp_color_frame_set_color:
541  * @frame:          The #GimpColorFrame.
542  * @sample_average: The set @color is the result of averaging
543  * @sample_format:  The format of the #GimpDrawable or #GimpImage the @color
544  *                  was picked from.
545  * @pixel:          The raw pixel in @sample_format.
546  * @color:          The @color to set.
547  * @x:              X position where the color was picked.
548  * @y:              Y position where the color was picked.
549  *
550  * Sets the color sample to display in the #GimpColorFrame. if
551  * @sample_average is %TRUE, @pixel represents the sample at the
552  * center of the average area and will not be displayed.
553  **/
554 void
gimp_color_frame_set_color(GimpColorFrame * frame,gboolean sample_average,const Babl * sample_format,gpointer pixel,const GimpRGB * color,gint x,gint y)555 gimp_color_frame_set_color (GimpColorFrame *frame,
556                             gboolean        sample_average,
557                             const Babl     *sample_format,
558                             gpointer        pixel,
559                             const GimpRGB  *color,
560                             gint            x,
561                             gint            y)
562 {
563   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
564   g_return_if_fail (color != NULL);
565 
566   if (frame->sample_valid                     &&
567       frame->sample_average == sample_average &&
568       frame->sample_format  == sample_format  &&
569       frame->x              == x              &&
570       frame->y              == y              &&
571       gimp_rgba_distance (&frame->color, color) < RGBA_EPSILON)
572     {
573       frame->color = *color;
574       return;
575     }
576 
577   frame->sample_valid   = TRUE;
578   frame->sample_average = sample_average;
579   frame->sample_format  = sample_format;
580   frame->color          = *color;
581   frame->x              = x;
582   frame->y              = y;
583 
584   memcpy (frame->pixel, pixel, babl_format_get_bytes_per_pixel (sample_format));
585 
586   gimp_color_frame_update (frame);
587 }
588 
589 /**
590  * gimp_color_frame_set_invalid:
591  * @frame: The #GimpColorFrame.
592  *
593  * Tells the #GimpColorFrame that the current sample is invalid. All labels
594  * visible for the current color space will show "n/a" (not available).
595  *
596  * There is no special API for setting the frame to "valid" again because
597  * this happens automatically when calling gimp_color_frame_set_color().
598  **/
599 void
gimp_color_frame_set_invalid(GimpColorFrame * frame)600 gimp_color_frame_set_invalid (GimpColorFrame *frame)
601 {
602   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
603 
604   if (! frame->sample_valid)
605     return;
606 
607   frame->sample_valid = FALSE;
608 
609   gimp_color_frame_update (frame);
610 }
611 
612 void
gimp_color_frame_set_color_config(GimpColorFrame * frame,GimpColorConfig * config)613 gimp_color_frame_set_color_config (GimpColorFrame  *frame,
614                                    GimpColorConfig *config)
615 {
616   g_return_if_fail (GIMP_IS_COLOR_FRAME (frame));
617   g_return_if_fail (config == NULL || GIMP_IS_COLOR_CONFIG (config));
618 
619   if (config != frame->config)
620     {
621       if (frame->config)
622         {
623           g_signal_handlers_disconnect_by_func (frame->config,
624                                                 gimp_color_frame_destroy_transform,
625                                                 frame);
626           g_object_unref (frame->config);
627 
628           gimp_color_frame_destroy_transform (frame);
629         }
630 
631       frame->config = config;
632 
633       if (frame->config)
634         {
635           g_object_ref (frame->config);
636 
637           g_signal_connect_swapped (frame->config, "notify",
638                                     G_CALLBACK (gimp_color_frame_destroy_transform),
639                                     frame);
640         }
641 
642       gimp_color_area_set_color_config (GIMP_COLOR_AREA (frame->color_area),
643                                         config);
644     }
645 }
646 
647 
648 /*  private functions  */
649 
650 static void
gimp_color_frame_combo_callback(GtkWidget * widget,GimpColorFrame * frame)651 gimp_color_frame_combo_callback (GtkWidget      *widget,
652                                  GimpColorFrame *frame)
653 {
654   gint value;
655 
656   if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value))
657     {
658       frame->pick_mode = value;
659       gimp_color_frame_update (frame);
660 
661       g_object_notify (G_OBJECT (frame), "mode");
662     }
663 }
664 
665 static void
gimp_color_frame_update(GimpColorFrame * frame)666 gimp_color_frame_update (GimpColorFrame *frame)
667 {
668   const gchar  *names[GIMP_COLOR_FRAME_ROWS]  = { NULL, };
669   gchar       **values = NULL;
670   gboolean      has_alpha;
671   gint          i;
672 
673   has_alpha = babl_format_has_alpha (frame->sample_format);
674 
675   if (frame->sample_valid)
676     {
677       gchar str[16];
678 
679       gimp_color_area_set_color (GIMP_COLOR_AREA (frame->color_area),
680                                  &frame->color);
681 
682       g_snprintf (str, sizeof (str), "%d", frame->x);
683       gtk_label_set_text (GTK_LABEL (frame->coords_label_x), str);
684 
685       g_snprintf (str, sizeof (str), "%d", frame->y);
686       gtk_label_set_text (GTK_LABEL (frame->coords_label_y), str);
687     }
688   else
689     {
690       /* TRANSLATORS: n/a for Not Available. */
691       gtk_label_set_text (GTK_LABEL (frame->coords_label_x), C_("Coordinates", "n/a"));
692       /* TRANSLATORS: n/a for Not Available. */
693       gtk_label_set_text (GTK_LABEL (frame->coords_label_y), C_("Coordinates", "n/a"));
694     }
695 
696   switch (frame->pick_mode)
697     {
698     case GIMP_COLOR_PICK_MODE_PIXEL:
699       {
700         GimpImageBaseType base_type;
701 
702         base_type = gimp_babl_format_get_base_type (frame->sample_format);
703 
704         if (frame->sample_valid)
705           {
706             const Babl *print_format = NULL;
707             guchar      print_pixel[32];
708 
709             switch (gimp_babl_format_get_precision (frame->sample_format))
710               {
711               case GIMP_PRECISION_U8_GAMMA:
712                 if (babl_format_is_palette (frame->sample_format))
713                   {
714                     print_format = gimp_babl_format (GIMP_RGB,
715                                                      GIMP_PRECISION_U8_GAMMA,
716                                                      has_alpha);
717                     break;
718                   }
719                 /* else fall thru */
720 
721               case GIMP_PRECISION_U8_LINEAR:
722               case GIMP_PRECISION_U16_LINEAR:
723               case GIMP_PRECISION_U16_GAMMA:
724               case GIMP_PRECISION_U32_LINEAR:
725               case GIMP_PRECISION_U32_GAMMA:
726               case GIMP_PRECISION_FLOAT_LINEAR:
727               case GIMP_PRECISION_FLOAT_GAMMA:
728               case GIMP_PRECISION_DOUBLE_LINEAR:
729               case GIMP_PRECISION_DOUBLE_GAMMA:
730                 print_format = frame->sample_format;
731                 break;
732 
733               case GIMP_PRECISION_HALF_GAMMA:
734                 print_format = gimp_babl_format (base_type,
735                                                  GIMP_PRECISION_FLOAT_GAMMA,
736                                                  has_alpha);
737                 break;
738 
739               case GIMP_PRECISION_HALF_LINEAR:
740                 print_format = gimp_babl_format (base_type,
741                                                  GIMP_PRECISION_FLOAT_LINEAR,
742                                                  has_alpha);
743                 break;
744               }
745 
746             if (frame->sample_average)
747               {
748                 /* FIXME: this is broken: can't use the averaged sRGB GimpRGB
749                  * value for displaying pixel values when color management
750                  * is enabled
751                  */
752                 gimp_rgba_get_pixel (&frame->color, print_format, print_pixel);
753               }
754             else
755               {
756                 babl_process (babl_fish (frame->sample_format, print_format),
757                               frame->pixel, print_pixel, 1);
758               }
759 
760             values = gimp_babl_print_pixel (print_format, print_pixel);
761           }
762 
763         if (base_type == GIMP_GRAY)
764           {
765             /* TRANSLATORS: V for Value (grayscale) */
766             names[0] = C_("Grayscale", "V:");
767 
768             if (has_alpha)
769               /* TRANSLATORS: A for Alpha (color transparency) */
770               names[1] = C_("Alpha channel", "A:");
771           }
772         else
773           {
774             /* TRANSLATORS: R for Red (RGB) */
775             names[0] = C_("RGB", "R:");
776             /* TRANSLATORS: G for Green (RGB) */
777             names[1] = C_("RGB", "G:");
778             /* TRANSLATORS: B for Blue (RGB) */
779             names[2] = C_("RGB", "B:");
780 
781             if (has_alpha)
782               /* TRANSLATORS: A for Alpha (color transparency) */
783               names[3] = C_("Alpha channel", "A:");
784 
785             if (babl_format_is_palette (frame->sample_format))
786               {
787                 /* TRANSLATORS: Index of the color in the palette. */
788                 names[4] = C_("Indexed color", "Index:");
789 
790                 if (frame->sample_valid)
791                   {
792                     gchar **v   = g_new0 (gchar *, 6);
793                     gchar **tmp = values;
794 
795                     memcpy (v, values, 4 * sizeof (gchar *));
796                     values = v;
797 
798                     g_free (tmp);
799 
800                     if (! frame->sample_average)
801                       {
802                         values[4] = g_strdup_printf (
803                           "%d", ((guint8 *) frame->pixel)[0]);
804                       }
805                   }
806               }
807           }
808       }
809       break;
810 
811     case GIMP_COLOR_PICK_MODE_RGB_PERCENT:
812     case GIMP_COLOR_PICK_MODE_RGB_U8:
813       /* TRANSLATORS: R for Red (RGB) */
814       names[0] = C_("RGB", "R:");
815       /* TRANSLATORS: G for Green (RGB) */
816       names[1] = C_("RGB", "G:");
817       /* TRANSLATORS: B for Blue (RGB) */
818       names[2] = C_("RGB", "B:");
819 
820       if (has_alpha)
821         /* TRANSLATORS: A for Alpha (color transparency) */
822         names[3] = C_("Alpha channel", "A:");
823 
824       /* TRANSLATORS: Hex for Hexadecimal (representation of a color) */
825       names[4] = C_("Color representation", "Hex:");
826 
827       if (frame->sample_valid)
828         {
829           guchar r, g, b, a;
830 
831           values = g_new0 (gchar *, 6);
832 
833           gimp_rgba_get_uchar (&frame->color, &r, &g, &b, &a);
834 
835           if (frame->pick_mode == GIMP_COLOR_PICK_MODE_RGB_PERCENT)
836             {
837               values[0] = g_strdup_printf ("%.01f %%", frame->color.r * 100.0);
838               values[1] = g_strdup_printf ("%.01f %%", frame->color.g * 100.0);
839               values[2] = g_strdup_printf ("%.01f %%", frame->color.b * 100.0);
840               values[3] = g_strdup_printf ("%.01f %%", frame->color.a * 100.0);
841             }
842           else
843             {
844               values[0] = g_strdup_printf ("%d", r);
845               values[1] = g_strdup_printf ("%d", g);
846               values[2] = g_strdup_printf ("%d", b);
847               values[3] = g_strdup_printf ("%d", a);
848             }
849 
850           values[4] = g_strdup_printf ("%.2x%.2x%.2x", r, g, b);
851         }
852       break;
853 
854     case GIMP_COLOR_PICK_MODE_HSV:
855       /* TRANSLATORS: H for Hue (HSV color space) */
856       names[0] = C_("HSV color space", "H:");
857       /* TRANSLATORS: S for Saturation (HSV color space) */
858       names[1] = C_("HSV color space", "S:");
859       /* TRANSLATORS: V for Value (HSV color space) */
860       names[2] = C_("HSV color space", "V:");
861 
862       if (has_alpha)
863         /* TRANSLATORS: A for Alpha (color transparency) */
864         names[3] = C_("Alpha channel", "A:");
865 
866       if (frame->sample_valid)
867         {
868           GimpHSV hsv;
869 
870           gimp_rgb_to_hsv (&frame->color, &hsv);
871           hsv.a = frame->color.a;
872 
873           values = g_new0 (gchar *, 5);
874 
875           values[0] = g_strdup_printf ("%.01f \302\260", hsv.h * 360.0);
876           values[1] = g_strdup_printf ("%.01f %%",       hsv.s * 100.0);
877           values[2] = g_strdup_printf ("%.01f %%",       hsv.v * 100.0);
878           values[3] = g_strdup_printf ("%.01f %%",       hsv.a * 100.0);
879         }
880       break;
881 
882     case GIMP_COLOR_PICK_MODE_LCH:
883       /* TRANSLATORS: L for Lightness (LCH color space) */
884       names[0] = C_("LCH color space", "L*:");
885       /* TRANSLATORS: C for Chroma (LCH color space) */
886       names[1] = C_("LCH color space", "C*:");
887       /* TRANSLATORS: H for Hue angle (LCH color space) */
888       names[2] = C_("LCH color space", "h\302\260:");
889 
890       if (has_alpha)
891         /* TRANSLATORS: A for Alpha (color transparency) */
892         names[3] = C_("Alpha channel", "A:");
893 
894       if (frame->sample_valid)
895         {
896           static const Babl *fish = NULL;
897           gfloat             lch[4];
898 
899           if (G_UNLIKELY (! fish))
900             fish = babl_fish (babl_format ("R'G'B'A double"),
901                               babl_format ("CIE LCH(ab) alpha float"));
902 
903           babl_process (fish, &frame->color, lch, 1);
904 
905           values = g_new0 (gchar *, 5);
906 
907           values[0] = g_strdup_printf ("%.01f  ",        lch[0]);
908           values[1] = g_strdup_printf ("%.01f  ",        lch[1]);
909           values[2] = g_strdup_printf ("%.01f \302\260", lch[2]);
910           values[3] = g_strdup_printf ("%.01f %%",       lch[3] * 100.0);
911         }
912       break;
913 
914     case GIMP_COLOR_PICK_MODE_LAB:
915       /* TRANSLATORS: L* for Lightness (Lab color space) */
916       names[0] = C_("Lab color space", "L*:");
917       /* TRANSLATORS: a* color channel in Lab color space */
918       names[1] = C_("Lab color space", "a*:");
919       /* TRANSLATORS: b* color channel in Lab color space */
920       names[2] = C_("Lab color space", "b*:");
921 
922       if (has_alpha)
923         /* TRANSLATORS: A for Alpha (color transparency) */
924         names[3] = C_("Alpha channel", "A:");
925 
926       if (frame->sample_valid)
927         {
928           static const Babl *fish = NULL;
929           gfloat             lab[4];
930 
931           if (G_UNLIKELY (! fish))
932             fish = babl_fish (babl_format ("R'G'B'A double"),
933                               babl_format ("CIE Lab alpha float"));
934 
935           babl_process (fish, &frame->color, lab, 1);
936 
937           values = g_new0 (gchar *, 5);
938 
939           values[0] = g_strdup_printf ("%.01f  ",  lab[0]);
940           values[1] = g_strdup_printf ("%.01f  ",  lab[1]);
941           values[2] = g_strdup_printf ("%.01f  ",  lab[2]);
942           values[3] = g_strdup_printf ("%.01f %%", lab[3] * 100.0);
943         }
944       break;
945 
946     case GIMP_COLOR_PICK_MODE_XYY:
947       /* TRANSLATORS: x from xyY color space */
948       names[0] = C_("xyY color space", "x:");
949       /* TRANSLATORS: y from xyY color space */
950       names[1] = C_("xyY color space", "y:");
951       /* TRANSLATORS: Y from xyY color space */
952       names[2] = C_("xyY color space", "Y:");
953 
954       if (has_alpha)
955         /* TRANSLATORS: A for Alpha (color transparency) */
956         names[3] = C_("Alpha channel", "A:");
957 
958       if (frame->sample_valid)
959         {
960           static const Babl *fish = NULL;
961           gfloat             xyY[4];
962 
963           if (G_UNLIKELY (! fish))
964             fish = babl_fish (babl_format ("R'G'B'A double"),
965                               babl_format ("CIE xyY alpha float"));
966 
967           babl_process (fish, &frame->color, xyY, 1);
968 
969           values = g_new0 (gchar *, 5);
970 
971           values[0] = g_strdup_printf ("%1.6f  ",  xyY[0]);
972           values[1] = g_strdup_printf ("%1.6f  ",  xyY[1]);
973           values[2] = g_strdup_printf ("%1.6f  ",  xyY[2]);
974           values[3] = g_strdup_printf ("%.01f %%", xyY[3] * 100.0);
975         }
976       break;
977 
978     case GIMP_COLOR_PICK_MODE_YUV:
979       /* TRANSLATORS: Y from Yu'v' color space */
980       names[0] = C_("Yu'v' color space", "Y:");
981       /* TRANSLATORS: u' from Yu'v' color space */
982       names[1] = C_("Yu'v' color space", "u':");
983       /* TRANSLATORS: v' from Yu'v' color space */
984       names[2] = C_("Yu'v' color space", "v':");
985 
986       if (has_alpha)
987         /* TRANSLATORS: A for Alpha (color transparency) */
988         names[3] = C_("Alpha channel", "A:");
989 
990       if (frame->sample_valid)
991         {
992           static const Babl *fish = NULL;
993           gfloat             Yuv[4];
994 
995           if (G_UNLIKELY (! fish))
996             fish = babl_fish (babl_format ("R'G'B'A double"),
997                               babl_format ("CIE Yuv alpha float"));
998 
999           babl_process (fish, &frame->color, Yuv, 1);
1000 
1001           values = g_new0 (gchar *, 5);
1002 
1003           values[0] = g_strdup_printf ("%1.6f  ",  Yuv[0]);
1004           values[1] = g_strdup_printf ("%1.6f  ",  Yuv[1]);
1005           values[2] = g_strdup_printf ("%1.6f  ",  Yuv[2]);
1006           values[3] = g_strdup_printf ("%.01f %%", Yuv[3] * 100.0);
1007         }
1008       break;
1009 
1010     case GIMP_COLOR_PICK_MODE_CMYK:
1011       /* TRANSLATORS: C for Cyan (CMYK) */
1012       names[0] = C_("CMYK", "C:");
1013       /* TRANSLATORS: M for Magenta (CMYK) */
1014       names[1] = C_("CMYK", "M:");
1015       /* TRANSLATORS: Y for Yellow (CMYK) */
1016       names[2] = C_("CMYK", "Y:");
1017       /* TRANSLATORS: K for Key/black (CMYK) */
1018       names[3] = C_("CMYK", "K:");
1019 
1020       if (has_alpha)
1021         /* TRANSLATORS: A for Alpha (color transparency) */
1022         names[4] = C_("Alpha channel", "A:");
1023 
1024       if (frame->sample_valid)
1025         {
1026           GimpCMYK cmyk;
1027 
1028           if (! frame->transform)
1029             gimp_color_frame_create_transform (frame);
1030 
1031           if (frame->transform)
1032             {
1033               gdouble rgb_values[3];
1034               gdouble cmyk_values[4];
1035 
1036               rgb_values[0] = frame->color.r;
1037               rgb_values[1] = frame->color.g;
1038               rgb_values[2] = frame->color.b;
1039 
1040               gimp_color_transform_process_pixels (frame->transform,
1041                                                    babl_format ("R'G'B' double"),
1042                                                    rgb_values,
1043                                                    babl_format ("CMYK double"),
1044                                                    cmyk_values,
1045                                                    1);
1046 
1047               cmyk.c = cmyk_values[0] / 100.0;
1048               cmyk.m = cmyk_values[1] / 100.0;
1049               cmyk.y = cmyk_values[2] / 100.0;
1050               cmyk.k = cmyk_values[3] / 100.0;
1051             }
1052           else
1053             {
1054               gimp_rgb_to_cmyk (&frame->color, 1.0, &cmyk);
1055             }
1056 
1057           cmyk.a = frame->color.a;
1058 
1059           values = g_new0 (gchar *, 6);
1060 
1061           values[0] = g_strdup_printf ("%.01f %%", cmyk.c * 100.0);
1062           values[1] = g_strdup_printf ("%.01f %%", cmyk.m * 100.0);
1063           values[2] = g_strdup_printf ("%.01f %%", cmyk.y * 100.0);
1064           values[3] = g_strdup_printf ("%.01f %%", cmyk.k * 100.0);
1065           values[4] = g_strdup_printf ("%.01f %%", cmyk.a * 100.0);
1066         }
1067       break;
1068     }
1069 
1070   for (i = 0; i < GIMP_COLOR_FRAME_ROWS; i++)
1071     {
1072       if (names[i])
1073         {
1074           gtk_label_set_text (GTK_LABEL (frame->name_labels[i]), names[i]);
1075 
1076           if (frame->sample_valid && values[i])
1077             gtk_label_set_text (GTK_LABEL (frame->value_labels[i]), values[i]);
1078           else
1079             gtk_label_set_text (GTK_LABEL (frame->value_labels[i]),
1080                                 C_("Color value", "n/a"));
1081         }
1082       else
1083         {
1084           gtk_label_set_text (GTK_LABEL (frame->name_labels[i]),  " ");
1085           gtk_label_set_text (GTK_LABEL (frame->value_labels[i]), " ");
1086         }
1087     }
1088 
1089   g_strfreev (values);
1090 }
1091 
1092 static void
gimp_color_frame_create_transform(GimpColorFrame * frame)1093 gimp_color_frame_create_transform (GimpColorFrame *frame)
1094 {
1095   if (frame->config)
1096     {
1097       GimpColorProfile *cmyk_profile;
1098 
1099       cmyk_profile = gimp_color_config_get_cmyk_color_profile (frame->config,
1100                                                                NULL);
1101 
1102       if (cmyk_profile)
1103         {
1104           static GimpColorProfile *rgb_profile = NULL;
1105 
1106           if (G_UNLIKELY (! rgb_profile))
1107             rgb_profile = gimp_color_profile_new_rgb_srgb ();
1108 
1109           frame->transform =
1110             gimp_color_transform_new (rgb_profile,
1111                                       babl_format ("R'G'B' double"),
1112                                       cmyk_profile,
1113                                       babl_format ("CMYK double"),
1114                                       GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
1115                                       GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE |
1116                                       GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION);
1117         }
1118     }
1119 }
1120 
1121 static void
gimp_color_frame_destroy_transform(GimpColorFrame * frame)1122 gimp_color_frame_destroy_transform (GimpColorFrame *frame)
1123 {
1124   g_clear_object (&frame->transform);
1125 
1126   gimp_color_frame_update (frame);
1127 }
1128