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