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 "libgimpwidgets/gimpwidgets.h"
24 
25 #include "widgets-types.h"
26 
27 #include "core/gimp.h"
28 #include "core/gimpasync.h"
29 #include "core/gimpdrawable.h"
30 #include "core/gimpdrawable-histogram.h"
31 #include "core/gimphistogram.h"
32 #include "core/gimpimage.h"
33 
34 #include "gimpdocked.h"
35 #include "gimphelp-ids.h"
36 #include "gimphistogrambox.h"
37 #include "gimphistogrameditor.h"
38 #include "gimphistogramview.h"
39 #include "gimppropwidgets.h"
40 #include "gimpsessioninfo-aux.h"
41 #include "gimpwidgets-utils.h"
42 
43 #include "gimp-intl.h"
44 
45 
46 enum
47 {
48   PROP_0,
49   PROP_LINEAR
50 };
51 
52 
53 static void     gimp_histogram_editor_docked_iface_init (GimpDockedInterface *iface);
54 
55 static void     gimp_histogram_editor_set_property  (GObject            *object,
56                                                      guint               property_id,
57                                                      const GValue       *value,
58                                                      GParamSpec         *pspec);
59 static void     gimp_histogram_editor_get_property  (GObject            *object,
60                                                      guint               property_id,
61                                                      GValue             *value,
62                                                      GParamSpec         *pspec);
63 
64 static void     gimp_histogram_editor_set_aux_info  (GimpDocked          *docked,
65                                                      GList               *aux_info);
66 static GList  * gimp_histogram_editor_get_aux_info  (GimpDocked          *docked);
67 
68 static void     gimp_histogram_editor_set_image     (GimpImageEditor     *editor,
69                                                      GimpImage           *image);
70 static void     gimp_histogram_editor_layer_changed (GimpImage           *image,
71                                                      GimpHistogramEditor *editor);
72 static void     gimp_histogram_editor_frozen_update (GimpHistogramEditor *editor,
73                                                      const GParamSpec    *pspec);
74 static void     gimp_histogram_editor_buffer_update (GimpHistogramEditor *editor,
75                                                      const GParamSpec    *pspec);
76 static void     gimp_histogram_editor_update        (GimpHistogramEditor *editor);
77 
78 static gboolean gimp_histogram_editor_idle_update   (GimpHistogramEditor *editor);
79 static gboolean gimp_histogram_menu_sensitivity     (gint                 value,
80                                                      gpointer             data);
81 static void     gimp_histogram_editor_menu_update   (GimpHistogramEditor *editor);
82 static void     gimp_histogram_editor_name_update   (GimpHistogramEditor *editor);
83 static void     gimp_histogram_editor_info_update   (GimpHistogramEditor *editor);
84 
85 static gboolean gimp_histogram_editor_view_expose   (GimpHistogramEditor *editor);
86 
87 
88 G_DEFINE_TYPE_WITH_CODE (GimpHistogramEditor, gimp_histogram_editor,
89                          GIMP_TYPE_IMAGE_EDITOR,
90                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
91                                                 gimp_histogram_editor_docked_iface_init))
92 
93 #define parent_class gimp_histogram_editor_parent_class
94 
95 static GimpDockedInterface *parent_docked_iface = NULL;
96 
97 
98 static void
gimp_histogram_editor_class_init(GimpHistogramEditorClass * klass)99 gimp_histogram_editor_class_init (GimpHistogramEditorClass *klass)
100 {
101   GObjectClass         *object_class       = G_OBJECT_CLASS (klass);
102   GimpImageEditorClass *image_editor_class = GIMP_IMAGE_EDITOR_CLASS (klass);
103 
104   object_class->set_property    = gimp_histogram_editor_set_property;
105   object_class->get_property    = gimp_histogram_editor_get_property;
106 
107   image_editor_class->set_image = gimp_histogram_editor_set_image;
108 
109   g_object_class_install_property (object_class, PROP_LINEAR,
110                                    g_param_spec_boolean ("linear",
111                                                          _("Linear"), NULL,
112                                                          TRUE,
113                                                          GIMP_PARAM_READWRITE |
114                                                          G_PARAM_CONSTRUCT));
115 }
116 
117 static void
gimp_histogram_editor_init(GimpHistogramEditor * editor)118 gimp_histogram_editor_init (GimpHistogramEditor *editor)
119 {
120   GimpHistogramView *view;
121   GtkWidget         *hbox;
122   GtkWidget         *label;
123   GtkWidget         *menu;
124   GtkWidget         *table;
125   gint               i;
126 
127   const gchar *gimp_histogram_editor_labels[] =
128     {
129       N_("Mean:"),
130       N_("Std dev:"),
131       N_("Median:"),
132       N_("Pixels:"),
133       N_("Count:"),
134       N_("Percentile:")
135     };
136 
137   editor->box = gimp_histogram_box_new ();
138 
139   gimp_editor_set_show_name (GIMP_EDITOR (editor), TRUE);
140 
141   view = GIMP_HISTOGRAM_BOX (editor->box)->view;
142 
143   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
144   gtk_box_pack_start (GTK_BOX (editor), hbox, FALSE, FALSE, 0);
145   gtk_widget_show (hbox);
146 
147   editor->menu = menu = gimp_prop_enum_combo_box_new (G_OBJECT (view),
148                                                       "histogram-channel",
149                                                       0, 0);
150   gimp_enum_combo_box_set_icon_prefix (GIMP_ENUM_COMBO_BOX (menu),
151                                        "gimp-channel");
152   gimp_int_combo_box_set_sensitivity (GIMP_INT_COMBO_BOX (editor->menu),
153                                       gimp_histogram_menu_sensitivity,
154                                       editor, NULL);
155   gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (editor->menu),
156                                  view->channel);
157   gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
158   gtk_widget_show (menu);
159 
160   gimp_help_set_help_data (editor->menu,
161                            _("Histogram channel"), NULL);
162 
163   menu = gimp_prop_enum_icon_box_new (G_OBJECT (view),
164                                       "histogram-scale", "gimp-histogram",
165                                       0, 0);
166   gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
167   gtk_widget_show (menu);
168 
169   menu = gimp_prop_boolean_icon_box_new (G_OBJECT (editor), "linear",
170                                          GIMP_ICON_COLOR_SPACE_LINEAR,
171                                          GIMP_ICON_COLOR_SPACE_PERCEPTUAL,
172                                          _("Show values in linear space"),
173                                          _("Show values in perceptual space"));
174   gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
175   gtk_widget_show (menu);
176 
177   gtk_box_pack_start (GTK_BOX (editor), editor->box, TRUE, TRUE, 0);
178   gtk_widget_show (GTK_WIDGET (editor->box));
179 
180   g_signal_connect_swapped (view, "range-changed",
181                             G_CALLBACK (gimp_histogram_editor_info_update),
182                             editor);
183   g_signal_connect_swapped (view, "notify::histogram-channel",
184                             G_CALLBACK (gimp_histogram_editor_info_update),
185                             editor);
186 
187   g_signal_connect_swapped (view, "expose-event",
188                             G_CALLBACK (gimp_histogram_editor_view_expose),
189                             editor);
190 
191   table = gtk_table_new (3, 4, FALSE);
192   gtk_table_set_col_spacings (GTK_TABLE (table), 2);
193   gtk_table_set_col_spacing (GTK_TABLE (table), 1, 6);
194   gtk_box_pack_start (GTK_BOX (editor), table, FALSE, FALSE, 0);
195   gtk_widget_show (table);
196 
197   for (i = 0; i < 6; i++)
198     {
199       gint x = (i / 3) * 2;
200       gint y = (i % 3);
201 
202       label = gtk_label_new (gettext (gimp_histogram_editor_labels[i]));
203       gimp_label_set_attributes (GTK_LABEL (label),
204                                  PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
205                                  PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
206                                  -1);
207       gtk_label_set_xalign (GTK_LABEL (label), 1.0);
208       gtk_table_attach (GTK_TABLE (table), label, x, x + 1, y, y + 1,
209                         GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
210       gtk_widget_show (label);
211 
212       editor->labels[i] =
213         label = g_object_new (GTK_TYPE_LABEL,
214                               "xalign",      0.0,
215                               "yalign",      0.5,
216                               "width-chars", i > 2 ? 9 : 5,
217                               NULL);
218       gimp_label_set_attributes (GTK_LABEL (editor->labels[i]),
219                                  PANGO_ATTR_SCALE, PANGO_SCALE_SMALL,
220                                  -1);
221       gtk_table_attach (GTK_TABLE (table), label, x + 1, x + 2, y, y + 1,
222                         GTK_FILL, GTK_FILL, 2, 2);
223       gtk_widget_show (label);
224     }
225 }
226 
227 static void
gimp_histogram_editor_docked_iface_init(GimpDockedInterface * docked_iface)228 gimp_histogram_editor_docked_iface_init (GimpDockedInterface *docked_iface)
229 {
230   parent_docked_iface = g_type_interface_peek_parent (docked_iface);
231 
232   if (! parent_docked_iface)
233     parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
234 
235   docked_iface->set_aux_info = gimp_histogram_editor_set_aux_info;
236   docked_iface->get_aux_info = gimp_histogram_editor_get_aux_info;
237 }
238 
239 static void
gimp_histogram_editor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)240 gimp_histogram_editor_set_property (GObject      *object,
241                                     guint         property_id,
242                                     const GValue *value,
243                                     GParamSpec   *pspec)
244 {
245   GimpHistogramEditor *editor = GIMP_HISTOGRAM_EDITOR (object);
246   GimpHistogramView   *view   = GIMP_HISTOGRAM_BOX (editor->box)->view;
247 
248   switch (property_id)
249     {
250     case PROP_LINEAR:
251       editor->linear = g_value_get_boolean (value);
252 
253       if (editor->histogram)
254         {
255           g_clear_object (&editor->histogram);
256           gimp_histogram_view_set_histogram (view, NULL);
257         }
258 
259       if (editor->bg_histogram)
260         {
261           g_clear_object (&editor->bg_histogram);
262           gimp_histogram_view_set_background (view, NULL);
263         }
264 
265       gimp_histogram_editor_update (editor);
266       break;
267 
268    default:
269       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
270       break;
271     }
272 }
273 
274 static void
gimp_histogram_editor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)275 gimp_histogram_editor_get_property (GObject    *object,
276                                     guint       property_id,
277                                     GValue     *value,
278                                     GParamSpec *pspec)
279 {
280   GimpHistogramEditor *editor = GIMP_HISTOGRAM_EDITOR (object);
281 
282   switch (property_id)
283     {
284     case PROP_LINEAR:
285       g_value_set_boolean (value, editor->linear);
286       break;
287 
288    default:
289       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
290       break;
291     }
292 }
293 
294 static void
gimp_histogram_editor_set_aux_info(GimpDocked * docked,GList * aux_info)295 gimp_histogram_editor_set_aux_info (GimpDocked *docked,
296                                     GList      *aux_info)
297 {
298   GimpHistogramEditor *editor = GIMP_HISTOGRAM_EDITOR (docked);
299   GimpHistogramView   *view   = GIMP_HISTOGRAM_BOX (editor->box)->view;
300 
301   parent_docked_iface->set_aux_info (docked, aux_info);
302 
303   gimp_session_info_aux_set_props (G_OBJECT (view), aux_info,
304                                    "histogram-channel",
305                                    "histogram-scale",
306                                    NULL);
307 }
308 
309 static GList *
gimp_histogram_editor_get_aux_info(GimpDocked * docked)310 gimp_histogram_editor_get_aux_info (GimpDocked *docked)
311 {
312   GimpHistogramEditor *editor = GIMP_HISTOGRAM_EDITOR (docked);
313   GimpHistogramView   *view   = GIMP_HISTOGRAM_BOX (editor->box)->view;
314   GList               *aux_info;
315 
316   aux_info = parent_docked_iface->get_aux_info (docked);
317 
318   return g_list_concat (aux_info,
319                         gimp_session_info_aux_new_from_props (G_OBJECT (view),
320                                                               "histogram-channel",
321                                                               "histogram-scale",
322                                                               NULL));
323 }
324 
325 static void
gimp_histogram_editor_set_image(GimpImageEditor * image_editor,GimpImage * image)326 gimp_histogram_editor_set_image (GimpImageEditor *image_editor,
327                                  GimpImage       *image)
328 {
329   GimpHistogramEditor *editor = GIMP_HISTOGRAM_EDITOR (image_editor);
330   GimpHistogramView   *view   = GIMP_HISTOGRAM_BOX (editor->box)->view;
331 
332   if (image_editor->image)
333     {
334       if (editor->idle_id)
335         {
336           g_source_remove (editor->idle_id);
337           editor->idle_id = 0;
338         }
339 
340       editor->update_pending = FALSE;
341 
342       g_signal_handlers_disconnect_by_func (image_editor->image,
343                                             gimp_histogram_editor_update,
344                                             editor);
345       g_signal_handlers_disconnect_by_func (image_editor->image,
346                                             gimp_histogram_editor_layer_changed,
347                                             editor);
348       g_signal_handlers_disconnect_by_func (image_editor->image,
349                                             gimp_histogram_editor_menu_update,
350                                             editor);
351 
352       if (editor->histogram)
353         {
354           g_clear_object (&editor->histogram);
355           gimp_histogram_view_set_histogram (view, NULL);
356         }
357 
358       if (editor->bg_histogram)
359         {
360           g_clear_object (&editor->bg_histogram);
361           gimp_histogram_view_set_background (view, NULL);
362         }
363     }
364 
365   GIMP_IMAGE_EDITOR_CLASS (parent_class)->set_image (image_editor, image);
366 
367   if (image)
368     {
369       g_signal_connect_object (image, "mode-changed",
370                                G_CALLBACK (gimp_histogram_editor_menu_update),
371                                editor, G_CONNECT_SWAPPED);
372       g_signal_connect_object (image, "active-layer-changed",
373                                G_CALLBACK (gimp_histogram_editor_layer_changed),
374                                editor, 0);
375       g_signal_connect_object (image, "mask-changed",
376                                G_CALLBACK (gimp_histogram_editor_update),
377                                editor, G_CONNECT_SWAPPED);
378     }
379 
380   gimp_histogram_editor_layer_changed (image, editor);
381 }
382 
383 GtkWidget *
gimp_histogram_editor_new(void)384 gimp_histogram_editor_new (void)
385 {
386   return g_object_new (GIMP_TYPE_HISTOGRAM_EDITOR, NULL);
387 }
388 
389 static void
gimp_histogram_editor_layer_changed(GimpImage * image,GimpHistogramEditor * editor)390 gimp_histogram_editor_layer_changed (GimpImage           *image,
391                                      GimpHistogramEditor *editor)
392 {
393   if (editor->drawable)
394     {
395       GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
396 
397       if (editor->histogram)
398         {
399           g_clear_object (&editor->histogram);
400           gimp_histogram_view_set_histogram (view, NULL);
401         }
402 
403       if (editor->bg_histogram)
404         {
405           g_clear_object (&editor->bg_histogram);
406           gimp_histogram_view_set_background (view, NULL);
407         }
408 
409       g_signal_handlers_disconnect_by_func (editor->drawable,
410                                             gimp_histogram_editor_name_update,
411                                             editor);
412       g_signal_handlers_disconnect_by_func (editor->drawable,
413                                             gimp_histogram_editor_menu_update,
414                                             editor);
415       g_signal_handlers_disconnect_by_func (editor->drawable,
416                                             gimp_histogram_editor_update,
417                                             editor);
418       g_signal_handlers_disconnect_by_func (editor->drawable,
419                                             gimp_histogram_editor_buffer_update,
420                                             editor);
421       g_signal_handlers_disconnect_by_func (editor->drawable,
422                                             gimp_histogram_editor_frozen_update,
423                                             editor);
424       editor->drawable = NULL;
425     }
426 
427   if (image)
428     editor->drawable = (GimpDrawable *) gimp_image_get_active_layer (image);
429 
430   gimp_histogram_editor_menu_update (editor);
431 
432   if (editor->drawable)
433     {
434       g_signal_connect_object (editor->drawable, "notify::frozen",
435                                G_CALLBACK (gimp_histogram_editor_frozen_update),
436                                editor, G_CONNECT_SWAPPED);
437       g_signal_connect_object (editor->drawable, "notify::buffer",
438                                G_CALLBACK (gimp_histogram_editor_buffer_update),
439                                editor, G_CONNECT_SWAPPED);
440       g_signal_connect_object (editor->drawable, "update",
441                                G_CALLBACK (gimp_histogram_editor_update),
442                                editor, G_CONNECT_SWAPPED);
443       g_signal_connect_object (editor->drawable, "alpha-changed",
444                                G_CALLBACK (gimp_histogram_editor_menu_update),
445                                editor, G_CONNECT_SWAPPED);
446       g_signal_connect_object (editor->drawable, "name-changed",
447                                G_CALLBACK (gimp_histogram_editor_name_update),
448                                editor, G_CONNECT_SWAPPED);
449 
450       gimp_histogram_editor_buffer_update (editor, NULL);
451     }
452   else if (editor->histogram)
453     {
454       editor->recompute = TRUE;
455       gtk_widget_queue_draw (GTK_WIDGET (editor->box));
456     }
457 
458   gimp_histogram_editor_info_update (editor);
459   gimp_histogram_editor_name_update (editor);
460 }
461 
462 static void
gimp_histogram_editor_calculate_async_callback(GimpAsync * async,GimpHistogramEditor * editor)463 gimp_histogram_editor_calculate_async_callback (GimpAsync           *async,
464                                                 GimpHistogramEditor *editor)
465 {
466   editor->calculate_async = NULL;
467 
468   if (gimp_async_is_finished (async) && editor->histogram)
469     {
470       if (editor->bg_pending)
471         {
472           GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
473 
474           editor->bg_histogram = gimp_histogram_duplicate (editor->histogram);
475 
476           gimp_histogram_view_set_background (view, editor->bg_histogram);
477         }
478 
479       gimp_histogram_editor_info_update (editor);
480     }
481 
482   editor->bg_pending = FALSE;
483 
484   if (editor->update_pending)
485     gimp_histogram_editor_update (editor);
486 }
487 
488 static gboolean
gimp_histogram_editor_validate(GimpHistogramEditor * editor)489 gimp_histogram_editor_validate (GimpHistogramEditor *editor)
490 {
491   if (editor->recompute || ! editor->histogram)
492     {
493       if (editor->drawable &&
494           /* avoid calculating the histogram of a detached layer.  this can
495            * happen during gimp_image_remove_layer(), as a result of a pending
496            * "expose-event" signal (handled in
497            * gimp_histogram_editor_view_expose()) executed through
498            * gtk_tree_view_clamp_node_visible(), as a result of the
499            * GimpLayerTreeView in the Layers dialog receiving the image's
500            * "active-layer-changed" signal before us.  See bug #795716,
501            * comment 6.
502            */
503           gimp_item_is_attached (GIMP_ITEM (editor->drawable)))
504         {
505           GimpAsync *async;
506 
507           if (! editor->histogram)
508             {
509               GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
510 
511               editor->histogram = gimp_histogram_new (editor->linear);
512 
513               gimp_histogram_clear_values (
514                 editor->histogram,
515                 babl_format_get_n_components (
516                   gimp_drawable_get_format (editor->drawable)));
517 
518               gimp_histogram_view_set_histogram (view, editor->histogram);
519             }
520 
521           async = gimp_drawable_calculate_histogram_async (editor->drawable,
522                                                            editor->histogram,
523                                                            TRUE);
524 
525           editor->calculate_async = async;
526 
527           gimp_async_add_callback (
528             async,
529             (GimpAsyncCallback) gimp_histogram_editor_calculate_async_callback,
530             editor);
531 
532           g_object_unref (async);
533         }
534       else if (editor->histogram)
535         {
536           gimp_histogram_clear_values (editor->histogram, 0);
537 
538           gimp_histogram_editor_info_update (editor);
539         }
540 
541       editor->recompute = FALSE;
542 
543       if (editor->idle_id)
544         {
545           g_source_remove (editor->idle_id);
546           editor->idle_id = 0;
547         }
548     }
549 
550   return (editor->histogram != NULL);
551 }
552 
553 static void
gimp_histogram_editor_frozen_update(GimpHistogramEditor * editor,const GParamSpec * pspec)554 gimp_histogram_editor_frozen_update (GimpHistogramEditor *editor,
555                                      const GParamSpec    *pspec)
556 {
557   GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
558 
559   if (gimp_viewable_preview_is_frozen (GIMP_VIEWABLE (editor->drawable)))
560     {
561       /* Only do the background histogram if the histogram is visible.
562        * This is a workaround for the fact that recalculating the
563        * histogram is expensive and that it is only validated when it
564        * is shown. So don't slow down painting by doing something that
565        * is not even seen by the user.
566        */
567       if (! editor->bg_histogram &&
568           gtk_widget_is_drawable (GTK_WIDGET (editor)))
569         {
570           if (editor->idle_id)
571             {
572               g_source_remove (editor->idle_id);
573 
574               gimp_histogram_editor_idle_update (editor);
575             }
576 
577           if (gimp_histogram_editor_validate (editor))
578             {
579               if (editor->calculate_async)
580                 {
581                   editor->bg_pending = TRUE;
582                 }
583               else
584                 {
585                   editor->bg_histogram = gimp_histogram_duplicate (
586                     editor->histogram);
587 
588                   gimp_histogram_view_set_background (view,
589                                                       editor->bg_histogram);
590                 }
591             }
592         }
593     }
594   else
595     {
596       if (editor->bg_histogram)
597         {
598           g_clear_object (&editor->bg_histogram);
599           gimp_histogram_view_set_background (view, NULL);
600         }
601 
602       editor->bg_pending = FALSE;
603 
604       if (editor->update_pending)
605         gimp_async_cancel_and_wait (editor->calculate_async);
606     }
607 }
608 
609 static void
gimp_histogram_editor_buffer_update(GimpHistogramEditor * editor,const GParamSpec * pspec)610 gimp_histogram_editor_buffer_update (GimpHistogramEditor *editor,
611                                      const GParamSpec    *pspec)
612 {
613   g_object_set (editor,
614                 "linear", gimp_drawable_get_linear (editor->drawable),
615                 NULL);
616 }
617 
618 static void
gimp_histogram_editor_update(GimpHistogramEditor * editor)619 gimp_histogram_editor_update (GimpHistogramEditor *editor)
620 {
621   if (editor->bg_pending)
622     {
623       editor->update_pending = TRUE;
624 
625       return;
626     }
627 
628   editor->update_pending = FALSE;
629 
630   if (editor->calculate_async)
631     gimp_async_cancel_and_wait (editor->calculate_async);
632 
633   if (editor->idle_id)
634     g_source_remove (editor->idle_id);
635 
636   editor->idle_id =
637     g_timeout_add_full (G_PRIORITY_LOW,
638                         200,
639                         (GSourceFunc) gimp_histogram_editor_idle_update,
640                         editor,
641                         NULL);
642 }
643 
644 static gboolean
gimp_histogram_editor_idle_update(GimpHistogramEditor * editor)645 gimp_histogram_editor_idle_update (GimpHistogramEditor *editor)
646 {
647   editor->idle_id = 0;
648 
649   /* Mark the histogram for recomputation and queue a redraw.
650    * We will then recalculate the histogram when the view is exposed.
651    */
652   editor->recompute = TRUE;
653   gtk_widget_queue_draw (GTK_WIDGET (editor->box));
654 
655   return FALSE;
656 }
657 
658 static gboolean
gimp_histogram_menu_sensitivity(gint value,gpointer data)659 gimp_histogram_menu_sensitivity (gint      value,
660                                  gpointer  data)
661 {
662   GimpHistogramEditor  *editor  = GIMP_HISTOGRAM_EDITOR (data);
663   GimpHistogramChannel  channel = value;
664 
665   if (editor->histogram)
666     return gimp_histogram_has_channel (editor->histogram, channel);
667 
668   return FALSE;
669 }
670 
671 static void
gimp_histogram_editor_menu_update(GimpHistogramEditor * editor)672 gimp_histogram_editor_menu_update (GimpHistogramEditor *editor)
673 {
674   GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
675 
676   gtk_widget_queue_draw (editor->menu);
677 
678   if (editor->histogram &&
679       ! gimp_histogram_has_channel (editor->histogram, view->channel))
680     {
681       gimp_histogram_view_set_channel (view, GIMP_HISTOGRAM_VALUE);
682     }
683 }
684 
685 static void
gimp_histogram_editor_name_update(GimpHistogramEditor * editor)686 gimp_histogram_editor_name_update (GimpHistogramEditor *editor)
687 {
688   const gchar *name = NULL;
689 
690   if (editor->drawable)
691     name = gimp_object_get_name (editor->drawable);
692 
693   gimp_editor_set_name (GIMP_EDITOR (editor), name);
694 }
695 
696 static void
gimp_histogram_editor_info_update(GimpHistogramEditor * editor)697 gimp_histogram_editor_info_update (GimpHistogramEditor *editor)
698 {
699   GimpHistogramView *view = GIMP_HISTOGRAM_BOX (editor->box)->view;
700   GimpHistogram     *hist = editor->histogram;
701 
702   if (hist)
703     {
704       gint    n_bins;
705       gdouble pixels;
706       gdouble count;
707       gchar   text[12];
708 
709       n_bins = gimp_histogram_n_bins (hist);
710 
711       pixels = gimp_histogram_get_count (hist, view->channel, 0, n_bins - 1);
712       count  = gimp_histogram_get_count (hist, view->channel,
713                                          view->start, view->end);
714 
715       g_snprintf (text, sizeof (text), "%.3f",
716                   gimp_histogram_get_mean (hist, view->channel,
717                                            view->start, view->end));
718       gtk_label_set_text (GTK_LABEL (editor->labels[0]), text);
719 
720       g_snprintf (text, sizeof (text), "%.3f",
721                   gimp_histogram_get_std_dev (hist, view->channel,
722                                               view->start, view->end));
723       gtk_label_set_text (GTK_LABEL (editor->labels[1]), text);
724 
725       g_snprintf (text, sizeof (text), "%.3f",
726                   gimp_histogram_get_median  (hist, view->channel,
727                                               view->start,
728                                               view->end));
729       gtk_label_set_text (GTK_LABEL (editor->labels[2]), text);
730 
731       g_snprintf (text, sizeof (text), "%d", (gint) pixels);
732       gtk_label_set_text (GTK_LABEL (editor->labels[3]), text);
733 
734       g_snprintf (text, sizeof (text), "%d", (gint) count);
735       gtk_label_set_text (GTK_LABEL (editor->labels[4]), text);
736 
737       g_snprintf (text, sizeof (text), "%.1f", (pixels > 0 ?
738                                                  (100.0 * count / pixels) :
739                                                  0.0));
740       gtk_label_set_text (GTK_LABEL (editor->labels[5]), text);
741     }
742   else
743     {
744       gint i;
745 
746       for (i = 0; i < 6; i++)
747         gtk_label_set_text (GTK_LABEL (editor->labels[i]), NULL);
748     }
749 }
750 
751 static gboolean
gimp_histogram_editor_view_expose(GimpHistogramEditor * editor)752 gimp_histogram_editor_view_expose (GimpHistogramEditor *editor)
753 {
754   gimp_histogram_editor_validate (editor);
755 
756   return FALSE;
757 }
758