Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
dev_toolbox.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2026 Guillaume STUTIN.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14*/
15
16#include "views/dev_toolbox.h"
17#include "common/paths.h" // DT_PATH_MAX
18
19#include "widgets/bauhaus.h"
23#include "common/conf.h"
24#include "control/redraw.h"
25#include "control/signal.h"
26#include "develop/develop.h"
28#include "widgets/button.h"
29#include "widgets/paint.h"
32#include "gui/application.h"
33
34#include <limits.h>
35#include "widgets/popup.h"
36
37#define DT_DEV_TOOLBOX_BUTTON_TYPE_KEY "dt-dev-toolbox-button-type"
38
40{
41 if(dev->iso_12646.enabled)
42 {
43 // For ISO 12646, we want portraits and landscapes to cover roughly the same surface
44 // no matter the size of the widget. Meaning we force them to fit a square
45 // of length matching the smaller widget dimension. The goal is to leave
46 // a consistent perceptual impression between pictures, independent from orientation.
47 const int main_dim = MIN(dt_dev_viewport_widget_width(dev), dt_dev_viewport_widget_height(dev));
48 dt_dev_viewport_set_border(dev, 0.125 * main_dim);
49 }
50 else
51 {
52 dt_dev_viewport_set_border(dev, DT_PIXEL_APPLY_DPI(dt_conf_get_int("plugins/darkroom/ui/border_size")));
53 }
54
56}
57
58/*
59 * Popover show/anchor plumbing, generic: reusable for any button+popover
60 * pair, including ones outside the button set below (darkroom's guides and
61 * auto-set popovers use this too).
62 */
63
64#define DT_DEV_TOOLBOX_PRESHOW_FN_KEY "dt-dev-toolbox-popover-preshow-fn"
65#define DT_DEV_TOOLBOX_PRESHOW_DATA_KEY "dt-dev-toolbox-popover-preshow-data"
66
67void dt_dev_toolbox_popover_set_preshow(GtkWidget *popover, void (*preshow)(gpointer user_data), gpointer user_data)
68{
69 g_object_set_data(G_OBJECT(popover), DT_DEV_TOOLBOX_PRESHOW_FN_KEY, (gpointer)preshow);
70 g_object_set_data(G_OBJECT(popover), DT_DEV_TOOLBOX_PRESHOW_DATA_KEY, user_data);
71}
72
73gboolean dt_dev_toolbox_show_popup(gpointer user_data)
74{
75 GtkPopover *popover = GTK_POPOVER(user_data);
76
77 GtkWidget *button = gtk_popover_get_relative_to(popover);
78 GdkRectangle button_rect = { 0 };
79 GtkWidget *anchor = dt_gui_get_popup_relative_widget(button, &button_rect);
80 GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default()));
81
82 int x, y;
83 GdkWindow *pointer_window = gdk_device_get_window_at_position(pointer, &x, &y);
84 gpointer pointer_widget = NULL;
85 if(pointer_window) gdk_window_get_user_data(pointer_window, &pointer_widget);
86
87 gtk_popover_set_relative_to(popover, anchor ? anchor : button);
88
89 GdkRectangle rect = { button_rect.x + button_rect.width / 2, button_rect.y, 1, 1 };
90
91 if(pointer_widget == anchor)
92 {
93 rect.x = x;
94 rect.y = y;
95 }
96 else if(pointer_widget && anchor && pointer_widget != anchor)
97 {
98 gtk_widget_translate_coordinates(pointer_widget, anchor, x, y, &rect.x, &rect.y);
99 }
100
101 gtk_popover_set_pointing_to(popover, &rect);
102
103 void (*preshow)(gpointer) = (void (*)(gpointer))g_object_get_data(G_OBJECT(popover), DT_DEV_TOOLBOX_PRESHOW_FN_KEY);
104 if(preshow) preshow(g_object_get_data(G_OBJECT(popover), DT_DEV_TOOLBOX_PRESHOW_DATA_KEY));
105
106 gtk_widget_show_all(GTK_WIDGET(popover));
107
108 // cancel glib timeout if invoked by long button press
109 return FALSE;
110}
111
112static gboolean _quickbutton_press_release(GtkWidget *button, GdkEventButton *event, GtkWidget *popover)
113{
114 static guint start_time = 0;
115
116 int delay = 0;
117 g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL);
118
119 if((event->type == GDK_BUTTON_PRESS && event->button == 3)
120 || (event->type == GDK_BUTTON_RELEASE && event->time - start_time > delay))
121 {
122 gtk_popover_set_relative_to(GTK_POPOVER(popover), button);
123 g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL);
124
126 return TRUE;
127 }
128 else
129 {
130 start_time = event->time;
131 return FALSE;
132 }
133}
134
136{
137 g_signal_connect(button, "button-press-event", G_CALLBACK(_quickbutton_press_release), popover);
138 g_signal_connect(button, "button-release-event", G_CALLBACK(_quickbutton_press_release), popover);
139}
140
141/*
142 * Accelerators: forward keyboard activation to the existing Gtk buttons so
143 * the keyboard path reuses the exact same callbacks, state changes and
144 * popover anchoring as the pointer path. Generic — reused for guides and
145 * auto-set (outside the button set below) by whichever view owns them.
146 */
147
148gboolean dt_dev_toolbox_activate_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval,
149 GdkModifierType modifier, gpointer data)
150{
151 GtkWidget *button = GTK_WIDGET(data);
152 if(IS_NULL_PTR(button) || !gtk_widget_is_visible(button) || !gtk_widget_is_sensitive(button)) return FALSE;
153
154 gtk_button_clicked(GTK_BUTTON(button));
155 return TRUE;
156}
157
158gboolean dt_dev_toolbox_focus_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval,
159 GdkModifierType modifier, gpointer data)
160{
161 GtkWidget *button = GTK_WIDGET(data);
162 if(IS_NULL_PTR(button) || !gtk_widget_is_visible(button) || !gtk_widget_is_sensitive(button)) return FALSE;
163
164 GtkWidget *popover = g_object_get_data(G_OBJECT(button), DT_DEV_TOOLBOX_POPOVER_KEY);
165 if(IS_NULL_PTR(popover) || !gtk_widget_is_sensitive(popover)) return FALSE;
166
167 gtk_widget_grab_focus(button);
168 gtk_popover_set_relative_to(GTK_POPOVER(popover), button);
170 return TRUE;
171}
172
173void dt_dev_toolbox_add_accels(dt_develop_t *dev, GtkAccelGroup *accel_group, const char *category,
174 const dt_dev_toolbox_button_t *buttons, size_t n_buttons)
175{
176 for(size_t i = 0; i < n_buttons; i++)
177 {
178 GtkWidget *button = NULL;
179 const char *activate_label = NULL;
180 const char *focus_label = NULL;
181
182 switch(buttons[i])
183 {
185 button = dev->iso_12646.button;
186 activate_label = N_("Toggle ISO 12646 color assessment conditions");
187 break;
188
190 button = dev->overexposed.button;
191 activate_label = N_("Toggle clipping indication");
192 focus_label = N_("Focus clipping indication options");
193 break;
194
196 button = dev->rawoverexposed.button;
197 activate_label = N_("Toggle raw over exposed indication");
198 focus_label = N_("Focus raw over exposed indication options");
199 break;
200
202 button = dev->profile.softproof_button;
203 activate_label = N_("Toggle softproofing");
204 focus_label = N_("Focus softproof options");
205 break;
206
208 button = dev->profile.gamut_button;
209 activate_label = N_("Toggle gamut checking");
210 focus_label = N_("Focus gamut checking options");
211 break;
212
214 button = dev->display.button;
215 focus_label = N_("Focus picture display options");
216 break;
217 }
218
219 if(activate_label)
221 category, activate_label, 0, 0, FALSE, _("Triggers the action"));
222 if(focus_label)
224 category, focus_label, 0, 0, FALSE, _("Shows the options popover"));
225 }
226}
227
228/*
229 * Single click dispatcher for every button below: which one fired is read
230 * back from a tag set at creation time, instead of one callback per button.
231 */
232
233static void _button_clicked(GtkWidget *w, gpointer user_data);
234
235/* Keep both buttons' active state in sync with the proofing mode, since enabling one
236 implicitly disables the other. One snapshot, so the two buttons cannot be set from
237 two different readings of the mode. */
239{
242
243 g_signal_handlers_block_by_func(dev->profile.softproof_button, _button_clicked, dev);
244 g_signal_handlers_block_by_func(dev->profile.gamut_button, _button_clicked, dev);
245
246 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dev->profile.softproof_button),
247 settings.mode == DT_PROFILE_SOFTPROOF);
248 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dev->profile.gamut_button),
249 settings.mode == DT_PROFILE_GAMUTCHECK);
250
251 g_signal_handlers_unblock_by_func(dev->profile.softproof_button, _button_clicked, dev);
252 g_signal_handlers_unblock_by_func(dev->profile.gamut_button, _button_clicked, dev);
253}
254
255static void _button_clicked(GtkWidget *w, gpointer user_data)
256{
257 dt_develop_t *dev = (dt_develop_t *)user_data;
259 = (dt_dev_toolbox_button_t)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), DT_DEV_TOOLBOX_BUTTON_TYPE_KEY));
260
261 switch(type)
262 {
264 if(!dev->gui_attached) return;
265 dev->iso_12646.enabled = !dev->iso_12646.enabled;
267 // This is already called in apply_iso_12646_size but it's not enough
269 break;
270
274 break;
275
279 break;
280
285 break;
286
291 break;
292
294 // No toggle state: this button only anchors an options popover, attached by the caller.
295 break;
296 }
297}
298
299/*
300 * Popover content: generic controls only. View-specific extras (darkroom's
301 * rendering-size and mask-preview-checkerboard additions to Picture
302 * display) are packed into the returned box by the caller afterward.
303 */
304
305static void _overexposed_mode_callback(GtkWidget *slider, gpointer user_data)
306{
307 dt_develop_t *dev = (dt_develop_t *)user_data;
309 if(dev->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->overexposed.button));
311}
312
313static void _overexposed_colorscheme_callback(GtkWidget *combo, gpointer user_data)
314{
315 dt_develop_t *dev = (dt_develop_t *)user_data;
317 if(dev->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->overexposed.button));
319}
320
321static void _overexposed_lower_callback(GtkWidget *slider, gpointer user_data)
322{
323 dt_develop_t *dev = (dt_develop_t *)user_data;
325 if(dev->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->overexposed.button));
327}
328
329static void _overexposed_upper_callback(GtkWidget *slider, gpointer user_data)
330{
331 dt_develop_t *dev = (dt_develop_t *)user_data;
333 if(dev->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->overexposed.button));
335}
336
338{
340
341 dev->overexposed.floating_window = gtk_popover_new(dev->overexposed.button);
343 g_object_set_data(G_OBJECT(dev->overexposed.button), DT_DEV_TOOLBOX_POPOVER_KEY, dev->overexposed.floating_window);
344
345 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
346 gtk_container_add(GTK_CONTAINER(dev->overexposed.floating_window), vbox);
347
348 GtkWidget *mode;
349 DT_BAUHAUS_COMBOBOX_NEW_FULL(dt_bauhaus_get_global(), mode, NULL, N_("clipping preview mode"),
350 _("select the metric you want to preview\nfull gamut is the combination of all other modes"),
352 N_("full gamut"), N_("any RGB channel"), N_("luminance only"), N_("saturation only"));
353 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(mode), TRUE, TRUE, 0);
354
355 GtkWidget *colorscheme;
356 DT_BAUHAUS_COMBOBOX_NEW_FULL(dt_bauhaus_get_global(), colorscheme, NULL, N_("color scheme"),
357 _("select colors to indicate clipping"), dev->overexposed.colorscheme,
358 _overexposed_colorscheme_callback, dev, N_("black & white"), N_("red & blue"),
359 N_("purple & green"));
360 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(colorscheme), TRUE, TRUE, 0);
361
362 GtkWidget *lower = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(NULL), -32., -4., 1., -12.69, 2);
364 dt_bauhaus_slider_set_format(lower, _(" EV"));
365 dt_bauhaus_widget_set_label(lower, N_("lower threshold"));
366 gtk_widget_set_tooltip_text(lower, _("clipping threshold for the black point,\n"
367 "in EV, relatively to white (0 EV).\n"
368 "8 bits sRGB clips blacks at -12.69 EV,\n"
369 "8 bits Adobe RGB clips blacks at -19.79 EV,\n"
370 "16 bits sRGB clips blacks at -20.69 EV,\n"
371 "typical fine-art mat prints produce black at -5.30 EV,\n"
372 "typical color glossy prints produce black at -8.00 EV,\n"
373 "typical B&W glossy prints produce black at -9.00 EV."));
374 g_signal_connect(G_OBJECT(lower), "value-changed", G_CALLBACK(_overexposed_lower_callback), dev);
375 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(lower), TRUE, TRUE, 0);
376
377 GtkWidget *upper = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(NULL), 0.0, 100.0, 0.1, 99.99, 2);
380 dt_bauhaus_widget_set_label(upper, N_("upper threshold"));
381 /* xgettext:no-c-format */
382 gtk_widget_set_tooltip_text(upper, _("clipping threshold for the white point.\n100% is peak medium luminance."));
383 g_signal_connect(G_OBJECT(upper), "value-changed", G_CALLBACK(_overexposed_upper_callback), dev);
384 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(upper), TRUE, TRUE, 0);
385
386 gtk_widget_show_all(vbox);
387}
388
389static void _rawoverexposed_mode_callback(GtkWidget *combo, gpointer user_data)
390{
391 dt_develop_t *dev = (dt_develop_t *)user_data;
393 if(dev->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->rawoverexposed.button));
395}
396
397static void _rawoverexposed_colorscheme_callback(GtkWidget *combo, gpointer user_data)
398{
399 dt_develop_t *dev = (dt_develop_t *)user_data;
401 if(dev->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->rawoverexposed.button));
403}
404
405static void _rawoverexposed_threshold_callback(GtkWidget *slider, gpointer user_data)
406{
407 dt_develop_t *dev = (dt_develop_t *)user_data;
409 if(dev->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(dev->rawoverexposed.button));
411}
412
414{
416
417 dev->rawoverexposed.floating_window = gtk_popover_new(dev->rawoverexposed.button);
419 g_object_set_data(G_OBJECT(dev->rawoverexposed.button), DT_DEV_TOOLBOX_POPOVER_KEY,
421
422 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
423 gtk_container_add(GTK_CONTAINER(dev->rawoverexposed.floating_window), vbox);
424
425 GtkWidget *mode;
426 DT_BAUHAUS_COMBOBOX_NEW_FULL(dt_bauhaus_get_global(), mode, NULL, N_("mode"), _("select how to mark the clipped pixels"),
428 N_("mark with CFA color"), N_("mark with solid color"), N_("false color"));
429 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(mode), TRUE, TRUE, 0);
430
431 // FIXME can't use DT_BAUHAUS_COMBOBOX_NEW_FULL because of (unnecessary?) translation context
433 dt_bauhaus_widget_set_label(colorscheme, N_("color scheme"));
434 dt_bauhaus_combobox_add(colorscheme, C_("solidcolor", "red"));
435 dt_bauhaus_combobox_add(colorscheme, C_("solidcolor", "green"));
436 dt_bauhaus_combobox_add(colorscheme, C_("solidcolor", "blue"));
437 dt_bauhaus_combobox_add(colorscheme, C_("solidcolor", "black"));
439 gtk_widget_set_tooltip_text(
440 colorscheme, _("select the solid color to indicate over exposure.\nwill only be used if mode = mark with solid color"));
441 g_signal_connect(G_OBJECT(colorscheme), "value-changed", G_CALLBACK(_rawoverexposed_colorscheme_callback), dev);
442 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(colorscheme), TRUE, TRUE, 0);
443
446 dt_bauhaus_widget_set_label(threshold, N_("clipping threshold"));
447 gtk_widget_set_tooltip_text(threshold,
448 _("threshold of what shall be considered overexposed\n1.0 - white level\n0.0 - black level"));
449 g_signal_connect(G_OBJECT(threshold), "value-changed", G_CALLBACK(_rawoverexposed_threshold_callback), dev);
450 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(threshold), TRUE, TRUE, 0);
451
452 gtk_widget_show_all(vbox);
453}
454
455static void _softproof_profile_callback(GtkWidget *combo, gpointer user_data)
456{
457 dt_develop_t *dev = (dt_develop_t *)user_data;
458 gboolean profile_changed = FALSE;
459 const int pos = dt_bauhaus_combobox_get(combo);
460
463 {
465 goto end;
466 }
467
468 // profile not found, fall back to sRGB. shouldn't happen
469 fprintf(stderr, "can't find softproof profile `%s', using sRGB instead\n", dt_bauhaus_combobox_get_text(combo));
471
472end:
474 {
478 }
479}
480
482{
485
486 // the popup window, shared between the two profile buttons
487 dev->profile.floating_window = gtk_popover_new(NULL);
490 g_object_set_data(G_OBJECT(dev->profile.softproof_button), DT_DEV_TOOLBOX_POPOVER_KEY, dev->profile.floating_window);
491 g_object_set_data(G_OBJECT(dev->profile.gamut_button), DT_DEV_TOOLBOX_POPOVER_KEY, dev->profile.floating_window);
492
493 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
494 gtk_container_add(GTK_CONTAINER(dev->profile.floating_window), vbox);
495
496 char datadir[DT_PATH_MAX] = { 0 };
497 char confdir[DT_PATH_MAX] = { 0 };
498 dt_loc_get_user_config_dir(confdir, sizeof(confdir));
499 dt_loc_get_datadir(datadir, sizeof(datadir));
500
502 dt_bauhaus_widget_set_label(softproof_profile, N_("softproof profile"));
503 dt_bauhaus_combobox_set_entries_ellipsis(softproof_profile, PANGO_ELLIPSIZE_MIDDLE);
504 gtk_box_pack_start(GTK_BOX(vbox), softproof_profile, TRUE, TRUE, 0);
505
508
509 // the system display profile is only suitable for display purposes, hence OUT
510 dt_colorprofile_desc_t *out_profiles = NULL;
511 const size_t n_out_profiles = dt_colorspaces_enumerate_profiles(DT_PROFILE_ROLE_OUTPUT, &out_profiles);
512 for(size_t k = 0; k < n_out_profiles; k++)
513 dt_bauhaus_combobox_add(softproof_profile, out_profiles[k].name);
514 dt_free_align(out_profiles);
515
516 const int softproof_pos = dt_colorspaces_profile_index(DT_PROFILE_ROLE_OUTPUT, settings.softproof_type,
517 settings.softproof_filename);
518 if(softproof_pos > -1) dt_bauhaus_combobox_set(softproof_profile, softproof_pos);
519
520 char *system_profile_dir = g_build_filename(datadir, "color", "out", NULL);
521 char *user_profile_dir = g_build_filename(confdir, "color", "out", NULL);
522 char *tooltip = g_strdup_printf(_("softproof ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
523 gtk_widget_set_tooltip_text(softproof_profile, tooltip);
525 dt_free(system_profile_dir);
526 dt_free(user_profile_dir);
527
528 g_signal_connect(G_OBJECT(softproof_profile), "value-changed", G_CALLBACK(_softproof_profile_callback), dev);
529
530 gtk_widget_show_all(vbox);
531}
532
539
540static void _display_borders_callback(GtkWidget *slider, gpointer user_data)
541{
542 dt_develop_t *dev = (dt_develop_t *)user_data;
543 dt_conf_set_int("plugins/darkroom/ui/border_size", (int)dt_bauhaus_slider_get(slider));
547}
548
550{
551 dev->display.floating_window = gtk_popover_new(dev->display.button);
553 g_object_set_data(G_OBJECT(dev->display.button), DT_DEV_TOOLBOX_POPOVER_KEY, dev->display.floating_window);
554
555 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
556 gtk_widget_set_margin_bottom(vbox, DT_PIXEL_APPLY_DPI(DT_GUI_BOX_SPACING));
557 gtk_container_add(GTK_CONTAINER(dev->display.floating_window), vbox);
558
559 GtkWidget *brightness = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(NULL), 0, 100, 5, 50, 0);
560 dt_bauhaus_slider_set(brightness, (int)dt_conf_get_int("display/brightness"));
561 dt_bauhaus_widget_set_label(brightness, N_("Background brightness"));
562 dt_bauhaus_slider_set_format(brightness, "%");
563 g_signal_connect(G_OBJECT(brightness), "value-changed", G_CALLBACK(_display_brightness_callback), dev);
564 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(brightness), TRUE, TRUE, 0);
565
567 dt_bauhaus_slider_set(borders, dt_conf_get_int("plugins/darkroom/ui/border_size"));
568 dt_bauhaus_widget_set_label(borders, N_("Picture margins"));
569 dt_bauhaus_slider_set_format(borders, "px");
570 g_signal_connect(G_OBJECT(borders), "value-changed", G_CALLBACK(_display_borders_callback), dev);
571 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(borders), TRUE, TRUE, 0);
572
573 // Left un-shown: callers wanting view-specific extras (darkroom's rendering
574 // size and mask preview checkerboard) pack them into this same vbox and
575 // call gtk_widget_show_all() themselves once done.
576}
577
578/*
579 * Button creation.
580 */
581
583{
584 GtkWidget *button = NULL;
585 const char *tooltip = NULL;
586
587 switch(type)
588 {
591 tooltip = _("toggle ISO 12646 color assessment conditions");
592 dev->iso_12646.button = button;
593 break;
594
597 tooltip = _("toggle clipping indication\nright click for options");
598 dev->overexposed.button = button;
599 break;
600
603 tooltip = _("toggle raw over exposed indication\nright click for options");
604 dev->rawoverexposed.button = button;
605 break;
606
609 tooltip = _("toggle softproofing\nright click for profile options");
610 dev->profile.softproof_button = button;
611 break;
612
615 tooltip = _("toggle gamut checking\nright click for profile options");
616 dev->profile.gamut_button = button;
617 break;
618
621 tooltip = _("Picture display options");
622 dev->display.button = button;
623 break;
624 }
625
626 g_object_set_data(G_OBJECT(button), DT_DEV_TOOLBOX_BUTTON_TYPE_KEY, GINT_TO_POINTER(type));
627 gtk_widget_set_tooltip_text(button, tooltip);
628 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_button_clicked), dev);
630 return button;
631}
632
634 size_t n_buttons)
635{
636 gboolean has_softproof = FALSE;
637 gboolean has_gamut = FALSE;
638
639 for(size_t i = 0; i < n_buttons; i++)
640 {
641 _create_one_button(dev, views, buttons[i]);
642 // Popover options
643 switch(buttons[i])
644 {
646 // No options popover for this one: it's a plain toggle.
647 break;
649 has_softproof = TRUE;
650 break;
652 has_gamut = TRUE;
653 break;
656 break;
659 break;
662 break;
663 }
664 }
665
666 // Both buttons exist only once both are requested in the same call.
667 if(has_softproof && has_gamut)
668 {
671 }
672}
void dt_accels_new_action_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, GtkWidget *target_widget, GtkAccelGroup *accel_group, const gchar *action_scope, const gchar *action_name, guint key_val, GdkModifierType accel_mods, const gboolean lock, const char *description)
Register a new shortcut for a generic action, setting up its path, default keys and accel group....
Handle default and user-set shortcuts (accelerators)
struct dt_accels_t * dt_gui_get_accels(void)
void dt_gui_add_help_link(GtkWidget *widget, char *link)
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
const char ** views(dt_lib_module_t *self)
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3280
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_combobox_set_entries_ellipsis(GtkWidget *widget, PangoEllipsizeMode ellipis)
Definition bauhaus.c:1872
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:1970
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3331
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1632
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3407
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
#define DT_BAUHAUS_COMBOBOX_NEW_FULL(bauhaus, widget, action, label, tip, pos, callback, data,...)
Definition bauhaus.h:379
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:135
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static void profile_changed(GtkWidget *widget, gpointer user_data)
Definition colorin.c:505
static const float x
size_t dt_colorspaces_enumerate_profiles(const dt_colorspaces_profile_role_t role, dt_colorprofile_desc_t **out)
Ordered snapshot of every profile registered for one role.
int dt_colorspaces_profile_index(const dt_colorspaces_profile_role_t role, const dt_colorspaces_color_profile_type_t type, const char *const filename)
Combo position of (type, filename) within direction.
gboolean dt_colorprofiles_set_softproof_profile_choice(const dt_colorspaces_color_profile_type_t type, const char *const filename)
Set the soft-proofing target identity.
gboolean dt_colorspaces_profile_at(const dt_colorspaces_profile_role_t role, const int index, dt_colorprofile_desc_t *const out)
Identity of the profile at index within direction.
dt_colorspaces_color_mode_t dt_colorprofiles_toggle_mode(const dt_colorspaces_color_mode_t mode)
Turn mode on, or back to DT_PROFILE_NORMAL if it is already the current mode, as one locked read-modi...
void dt_colorprofiles_get_settings(dt_colorprofiles_settings_t *const out)
Copy the current settings into caller-provided storage, under one lock.
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const float threshold
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:924
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:599
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
void dt_dev_pixelpipe_change_zoom_main(dt_develop_t *dev)
#define dt_dev_pixelpipe_resync_history_main(dev)
#define dt_dev_pixelpipe_update_history_main(dev)
static gboolean _quickbutton_press_release(GtkWidget *button, GdkEventButton *event, GtkWidget *popover)
static void _rawoverexposed_colorscheme_callback(GtkWidget *combo, gpointer user_data)
#define DT_DEV_TOOLBOX_BUTTON_TYPE_KEY
Definition dev_toolbox.c:37
static void _overexposed_lower_callback(GtkWidget *slider, gpointer user_data)
static void _build_overexposed_popover(dt_develop_t *dev)
static GtkWidget * _create_one_button(dt_develop_t *dev, dt_view_type_flags_t views, dt_dev_toolbox_button_t type)
gboolean dt_dev_toolbox_focus_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
static void _build_display_popover(dt_develop_t *dev)
void dt_dev_toolbox_connect_popover(GtkWidget *button, GtkWidget *popover)
static void _build_softproof_gamut_popover(dt_develop_t *dev)
static void _display_brightness_callback(GtkWidget *slider, gpointer user_data)
gboolean dt_dev_toolbox_show_popup(gpointer user_data)
Definition dev_toolbox.c:73
gboolean dt_dev_toolbox_activate_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
void dt_dev_toolbox_popover_set_preshow(GtkWidget *popover, void(*preshow)(gpointer user_data), gpointer user_data)
Definition dev_toolbox.c:67
void dt_dev_toolbox_create(dt_develop_t *dev, dt_view_type_flags_t views, const dt_dev_toolbox_button_t *buttons, size_t n_buttons)
#define DT_DEV_TOOLBOX_PRESHOW_DATA_KEY
Definition dev_toolbox.c:65
static void _rawoverexposed_threshold_callback(GtkWidget *slider, gpointer user_data)
static void _display_borders_callback(GtkWidget *slider, gpointer user_data)
static void _update_softproof_gamut_checking(dt_develop_t *dev)
void dt_dev_toolbox_apply_iso_12646_size(dt_develop_t *dev)
Definition dev_toolbox.c:39
static void _button_clicked(GtkWidget *w, gpointer user_data)
static void _overexposed_upper_callback(GtkWidget *slider, gpointer user_data)
static void _overexposed_colorscheme_callback(GtkWidget *combo, gpointer user_data)
static void _overexposed_mode_callback(GtkWidget *slider, gpointer user_data)
static void _rawoverexposed_mode_callback(GtkWidget *combo, gpointer user_data)
static void _softproof_profile_callback(GtkWidget *combo, gpointer user_data)
static void _build_rawoverexposed_popover(dt_develop_t *dev)
void dt_dev_toolbox_add_accels(dt_develop_t *dev, GtkAccelGroup *accel_group, const char *category, const dt_dev_toolbox_button_t *buttons, size_t n_buttons)
#define DT_DEV_TOOLBOX_PRESHOW_FN_KEY
Definition dev_toolbox.c:64
dt_dev_toolbox_button_t
Definition dev_toolbox.h:28
@ DT_DEV_TOOLBOX_DISPLAY
Definition dev_toolbox.h:34
@ DT_DEV_TOOLBOX_GAMUT
Definition dev_toolbox.h:33
@ DT_DEV_TOOLBOX_RAWOVEREXPOSED
Definition dev_toolbox.h:31
@ DT_DEV_TOOLBOX_OVEREXPOSED
Definition dev_toolbox.h:30
@ DT_DEV_TOOLBOX_SOFTPROOF
Definition dev_toolbox.h:32
@ DT_DEV_TOOLBOX_ISO_12646
Definition dev_toolbox.h:29
#define DT_DEV_TOOLBOX_POPOVER_KEY
gboolean dt_dev_viewport_set_border(dt_develop_t *dev, const int32_t border_size)
int32_t dt_dev_viewport_border_size(const dt_develop_t *dev)
int32_t dt_dev_viewport_widget_height(const dt_develop_t *dev)
int32_t dt_dev_viewport_widget_width(const dt_develop_t *dev)
#define dt_dev_configure(dev, wd, ht)
Definition develop.h:591
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
#define DT_GUI_MODULE(x)
const char * tooltip
Definition image.h:310
_lib_location_type_t type
Definition location.c:1
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
const char * name
Definition pdf.h:90
GtkWidget * dt_gui_get_popup_relative_widget(GtkWidget *widget, GdkRectangle *rect)
Resolve the widget to use as parent for a nested popup on Wayland.
Definition popup.c:25
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_COLORSPACES_PROFILE_TYPE_SOFTPROOF
@ DT_PROFILE_ROLE_OUTPUT
Listed in the output/export-profile combo (colorout, export).
@ DT_PROFILE_GAMUTCHECK
@ DT_PROFILE_SOFTPROOF
Asking the interface to repaint itself.
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED
This signal is raised when a profile is changed by the user 1 uint32_t : the profile type that has ch...
Definition signal.h:245
@ DT_SIGNAL_DARKROOM_UI_CHANGED
Signal that the darkroom GUI color changed.
Definition signal.h:227
A profile's public identity: what the GUI displays and stores, and nothing else.
dt_colorspaces_color_profile_type_t type
what to store in params / conf
char filename[DT_IOP_COLOR_ICC_LEN]
"" unless type == DT_COLORSPACE_FILE
Consistent snapshot of the display and soft-proofing settings.
char softproof_filename[DT_IOP_COLOR_ICC_LEN]
only meaningful for DT_COLORSPACE_FILE
dt_colorspaces_color_profile_type_t softproof_type
proofing target identity
dt_colorspaces_color_mode_t mode
NORMAL / SOFTPROOF / GAMUTCHECK.
int32_t gui_attached
Definition develop.h:167
struct dt_develop_t::@17 display
dt_clipping_preview_mode_t mode
Definition develop.h:441
GtkWidget * floating_window
Definition develop.h:435
float lower
Definition develop.h:439
struct dt_develop_t::@15 overexposed
struct dt_develop_t::@19 profile
dt_dev_overexposed_colorscheme_t colorscheme
Definition develop.h:438
GtkWidget * button
Definition develop.h:435
GtkWidget * gamut_button
Definition develop.h:473
gboolean enabled
Definition develop.h:370
struct dt_develop_t::@18 iso_12646
struct dt_develop_t::@16 rawoverexposed
float threshold
Definition develop.h:452
float upper
Definition develop.h:440
GtkWidget * softproof_button
Definition develop.h:473
double x
double y
#define MIN(a, b)
Definition thinplate.c:32
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
char * dt_get_help_url(char *name)
void dt_view_manager_module_toolbox_add(dt_view_manager_t *vm, GtkWidget *tool, dt_view_type_flags_t views)
Definition view.c:1329
dt_view_type_flags_t
Definition view.h:76
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dtgtk_cairo_paint_bulb(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_overexposed(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_gamut_check(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_rawoverexposed(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_softproof(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_display(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)