Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
color_picker_proxy.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2018-2021 Pascal Obry.
4 Copyright (C) 2019-2021 Diederik Ter Rahe.
5 Copyright (C) 2019 Edgardo Hoszowski.
6 Copyright (C) 2019 Ulrich Pegelow.
7 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
8 Copyright (C) 2020 Hubert Kowalski.
9 Copyright (C) 2020 Marco.
10 Copyright (C) 2021 Dan Torop.
11 Copyright (C) 2021 Paolo DePetrillo.
12 Copyright (C) 2021 Ralf Brown.
13 Copyright (C) 2022 Aldric Renaudin.
14 Copyright (C) 2022 Martin Bařinka.
15 Copyright (C) 2022 Philipp Lutz.
16 Copyright (C) 2023 Alynx Zhou.
17 Copyright (C) 2023, 2025-2026 Aurélien PIERRE.
18
19 darktable is free software: you can redistribute it and/or modify
20 it under the terms of the GNU Lesser General Public License as published by
21 the Free Software Foundation, either version 3 of the License, or
22 (at your option) any later version.
23
24 darktable is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU Lesser General Public License for more details.
28
29 You should have received a copy of the GNU Lesser General Public License
30 along with darktable. If not, see <http://www.gnu.org/licenses/>.
31*/
33#include "bauhaus/bauhaus.h"
34#include "common/color_picker.h"
35#include "control/signal.h"
36#include "control/control.h"
39#include "gui/gtk.h"
40#include "libs/colorpicker.h"
41#include "libs/lib.h"
42
43#include <inttypes.h>
44#include <math.h>
45#include <string.h>
46
47/*
48 The color_picker_proxy code is an interface which links the UI
49 colorpicker buttons in iops (and the colorpicker lib) with the rest
50 of the implementation (selecting/drawing colorpicker area in center
51 view, reading color value from preview pipe, and displaying results
52 in the colorpicker lib).
53
54 From the iop (or lib) POV, all that is necessary is to instantiate
55 color picker(s) via dt_color_picker_new() or
56 dt_color_picker_new_with_cst(), then subscribe to
57 DT_SIGNAL_CONTROL_PICKERDATA_READY and resolve the current ready sample
58 through dt_iop_color_picker_get_ready_data().
59
60 This code will initialize new pickers with a default area, then
61 remember the last area of the picker and use that when the picker is
62 reactivated.
63
64 The actual work of cache lookup and sampling happens here on the GUI
65 thread. The drawing & mouse-sensitivity of the picker overlay in the
66 center view happens in darkroom.c. The display of current sample
67 values occurs via libs/colorpicker.c, which uses this code to
68 activate its own picker.
69
70 The sample position is potentially stored in two places:
71
72 1. For each sampler widget, in dt_iop_color_picker_t.
73 2. For the active iop, the primary, and the live samples in
74 dt_colorpicker_sample_t.
75
76 There will be at most one editable sample, with one active picker, at
77 one time in the center view.
78*/
79
80
81// FIXME: should this be here or perhaps lib.c?
83{
84 const gboolean module_picker = dev->gui_module
85 && dev->gui_module->enabled
86 && dev->color_picker.enabled
87 && dev->color_picker.module == dev->gui_module;
88
89 const gboolean primary_picker = dev && dev->color_picker.enabled && !dev->color_picker.module;
90
91 return module_picker || primary_picker;
92}
93
95{
96 return module && module->dev
97 && module->dev->color_picker.enabled
98 && module->dev->color_picker.module == module;
99}
100
114{
115 dt_develop_t *const dev = darktable.develop;
116 const dt_colorpicker_sample_t *const sample = dev ? dev->color_picker.primary_sample : NULL;
117 gboolean changed = FALSE;
118 if(self && sample)
119 {
121 {
122 for(int k = 0; k < 2; k++)
123 {
124 if(self->pick_pos[k] != sample->point[k])
125 {
126 self->pick_pos[k] = sample->point[k];
127 changed = TRUE;
128 }
129 }
130 self->geometry_is_raw = TRUE;
131 }
132 else if(sample->size == DT_LIB_COLORPICKER_SIZE_BOX)
133 {
134 for(int k = 0; k < 4; k++)
135 {
136 if(self->pick_box[k] != sample->box[k])
137 {
138 self->pick_box[k] = sample->box[k];
139 changed = TRUE;
140 }
141 }
142 self->geometry_is_raw = TRUE;
143 }
144 }
145 return changed;
146}
147
153
160
161static void _refresh_active_picker(dt_develop_t *dev);
163static void _restart_picker_cache_wait(gpointer user_data);
164
165static inline void _picker_raw_point_to_image_norm(const dt_develop_t *dev, const float raw_point[2],
166 float image_point[2])
167{
168 image_point[0] = raw_point[0];
169 image_point[1] = raw_point[1];
171}
172
173static inline void _picker_raw_box_to_image_norm(const dt_develop_t *dev, const float raw_box[4],
174 float image_box[4])
175{
176 memcpy(image_box, raw_box, sizeof(float) * 4);
178}
179
181 const dt_iop_module_t *active_module,
182 float bounds[4])
183{
184 bounds[0] = 0.0f;
185 bounds[1] = 0.0f;
186 bounds[2] = 1.0f;
187 bounds[3] = 1.0f;
188
189 if(IS_NULL_PTR(dev) || IS_NULL_PTR(dev->preview_pipe) || IS_NULL_PTR(active_module)) return;
190 const float processed_width = dev->roi.processed_width;
191 const float processed_height = dev->roi.processed_height;
192 if(processed_width <= 0.0f || processed_height <= 0.0f) return;
193
195 (dt_iop_module_t *)active_module);
196 if(IS_NULL_PTR(piece)) return;
197
198 float quad[8] = {
199 0.0f, 0.0f,
200 (float)piece->buf_out.width, 0.0f,
201 (float)piece->buf_out.width, (float)piece->buf_out.height,
202 0.0f, (float)piece->buf_out.height
203 };
206
207 float min_x = fminf(fminf(quad[0], quad[2]), fminf(quad[4], quad[6]));
208 float min_y = fminf(fminf(quad[1], quad[3]), fminf(quad[5], quad[7]));
209 float max_x = fmaxf(fmaxf(quad[0], quad[2]), fmaxf(quad[4], quad[6]));
210 float max_y = fmaxf(fmaxf(quad[1], quad[3]), fmaxf(quad[5], quad[7]));
211
212 min_x = CLAMP(min_x / processed_width, 0.0f, 1.0f);
213 min_y = CLAMP(min_y / processed_height, 0.0f, 1.0f);
214 max_x = CLAMP(max_x / processed_width, 0.0f, 1.0f);
215 max_y = CLAMP(max_y / processed_height, 0.0f, 1.0f);
216 bounds[0] = fminf(min_x, max_x);
217 bounds[1] = fminf(min_y, max_y);
218 bounds[2] = fmaxf(min_x, max_x);
219 bounds[3] = fmaxf(min_y, max_y);
220}
221
223{
224 if(IS_NULL_PTR(picker) || IS_NULL_PTR(dev) || picker->geometry_is_raw) return;
225
226 float bounds[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
227 _picker_get_module_bounds_image_norm(dev, picker->module, bounds);
228
229 const float processed_width = dev->roi.processed_width;
230 const float processed_height = dev->roi.processed_height;
231 if(processed_width <= 0.0f || processed_height <= 0.0f) return;
232 // Fixed border inset in scale-1 image pixels, then converted to image-norm.
233 // Keep this explicit here so the caller directly controls default picker coverage.
234 const float inset_pixels = 64.0f;
235 const float inset_x = inset_pixels / processed_width;
236 const float inset_y = inset_pixels / processed_height;
237 const float width = fmaxf(bounds[2] - bounds[0], 0.0f);
238 const float height = fmaxf(bounds[3] - bounds[1], 0.0f);
239 picker->pick_pos[0] = 0.5f * (bounds[0] + bounds[2]);
240 picker->pick_pos[1] = 0.5f * (bounds[1] + bounds[3]);
241 picker->pick_box[0] = bounds[0] + fminf(inset_x, 0.5f * width);
242 picker->pick_box[1] = bounds[1] + fminf(inset_y, 0.5f * height);
243 picker->pick_box[2] = bounds[2] - fminf(inset_x, 0.5f * width);
244 picker->pick_box[3] = bounds[3] - fminf(inset_y, 0.5f * height);
245
246 picker->pick_pos[0] = CLAMP(picker->pick_pos[0], bounds[0], bounds[2]);
247 picker->pick_pos[1] = CLAMP(picker->pick_pos[1], bounds[1], bounds[3]);
248 picker->pick_box[0] = CLAMP(picker->pick_box[0], bounds[0], bounds[2]);
249 picker->pick_box[1] = CLAMP(picker->pick_box[1], bounds[1], bounds[3]);
250 picker->pick_box[2] = CLAMP(picker->pick_box[2], bounds[0], bounds[2]);
251 picker->pick_box[3] = CLAMP(picker->pick_box[3], bounds[1], bounds[3]);
252 if(picker->pick_box[0] > picker->pick_box[2])
253 {
254 const float center = 0.5f * (picker->pick_box[0] + picker->pick_box[2]);
255 picker->pick_box[0] = center;
256 picker->pick_box[2] = center;
257 }
258 if(picker->pick_box[1] > picker->pick_box[3])
259 {
260 const float center = 0.5f * (picker->pick_box[1] + picker->pick_box[3]);
261 picker->pick_box[1] = center;
262 picker->pick_box[3] = center;
263 }
264
267 picker->geometry_is_raw = TRUE;
268}
269
270static int _picker_sample_box(const dt_iop_module_t *module, const dt_iop_roi_t *roi,
271 const dt_pixelpipe_picker_source_t picker_source, int *box)
272{
273 dt_develop_t *const dev = darktable.develop;
274 const dt_colorpicker_sample_t *const sample = dev ? dev->color_picker.primary_sample : NULL;
275 if(IS_NULL_PTR(dev) || IS_NULL_PTR(module) || IS_NULL_PTR(roi) || IS_NULL_PTR(sample)) return 1;
276
277 dt_boundingbox_t fbox = { 0.0f };
278
279 if(sample->size == DT_LIB_COLORPICKER_SIZE_BOX)
280 {
281 _picker_raw_box_to_image_norm(dev, sample->box, fbox);
283 }
284 else if(sample->size == DT_LIB_COLORPICKER_SIZE_POINT)
285 {
286 _picker_raw_point_to_image_norm(dev, sample->point, fbox);
288 fbox[2] = fbox[0];
289 fbox[3] = fbox[1];
290 }
291
293 picker_source == PIXELPIPE_PICKER_INPUT
296 fbox, 2);
297
298 const float roi_scale = roi->scale;
299 if(roi_scale != 1.0f)
300 {
301 fbox[0] *= roi_scale;
302 fbox[1] *= roi_scale;
303 fbox[2] *= roi_scale;
304 fbox[3] *= roi_scale;
305 }
306
307 fbox[0] -= roi->x;
308 fbox[1] -= roi->y;
309 fbox[2] -= roi->x;
310 fbox[3] -= roi->y;
311
312 box[0] = fminf(fbox[0], fbox[2]);
313 box[1] = fminf(fbox[1], fbox[3]);
314 box[2] = fmaxf(fbox[0], fbox[2]);
315 box[3] = fmaxf(fbox[1], fbox[3]);
316
318 {
319 box[2] += 1;
320 box[3] += 1;
321 }
322
323 if(box[0] >= roi->width || box[1] >= roi->height || box[2] < 0 || box[3] < 0) return 1;
324
325 box[0] = MIN(roi->width - 1, MAX(0, box[0]));
326 box[1] = MIN(roi->height - 1, MAX(0, box[1]));
327 box[2] = MIN(roi->width - 1, MAX(0, box[2]));
328 box[3] = MIN(roi->height - 1, MAX(0, box[3]));
329
330 if(box[2] <= box[0] || box[3] <= box[1]) return 1;
331
332 return 0;
333}
334
336 const dt_iop_buffer_dsc_t *dsc, const dt_iop_roi_t *roi,
337 const float *pixel, dt_aligned_pixel_t avg_out,
338 dt_aligned_pixel_t min_out, dt_aligned_pixel_t max_out,
339 const dt_pixelpipe_picker_source_t picker_source)
340{
341 int box[4];
342 if(_picker_sample_box(module, roi, picker_source, box)) return FALSE;
343
344 dt_aligned_pixel_t avg = { 0.0f };
345 dt_aligned_pixel_t min = { INFINITY, INFINITY, INFINITY, INFINITY };
346 dt_aligned_pixel_t max = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
347
350 dt_color_picker_helper(dsc, pixel, roi, box, avg, min, max, dsc->cst, picker_cst, profile);
351
352 for(int k = 0; k < 4; k++)
353 {
354 avg_out[k] = avg[k];
355 min_out[k] = min[k];
356 max_out[k] = max[k];
357 }
358
359 return TRUE;
360}
361
363 dt_dev_pixelpipe_t **pipe,
364 const dt_dev_pixelpipe_iop_t **piece)
365{
366 dt_develop_t *const dev = darktable.develop;
367 if(IS_NULL_PTR(dev) || IS_NULL_PTR(module) || dev->color_picker.pending_module != module || IS_NULL_PTR(dev->color_picker.pending_pipe))
368 return 1;
369
370 dt_dev_pixelpipe_t *const current_pipe = dev->color_picker.pending_pipe;
371 const dt_dev_pixelpipe_iop_t *current_piece = NULL;
372
373 /* We walk the current preview graph and look for the current piece matching the sampled hash.
374 Piece pointers cannot cross the signal boundary because the pipe may have been rebuilt. */
375 for(GList *pieces = g_list_first(current_pipe->nodes); pieces; pieces = g_list_next(pieces))
376 {
377 const dt_dev_pixelpipe_iop_t *const current = pieces->data;
378 if(current->module == module && current->global_hash == dev->color_picker.piece_hash)
379 {
380 current_piece = current;
381 break;
382 }
383 }
384
385 if(IS_NULL_PTR(current_piece))
386 {
388 "[picker] ready-data miss module=%s pending_hash=%" PRIu64 " pipe=%p\n",
389 module->op, dev->color_picker.piece_hash, (void *)current_pipe);
390 return 1;
391 }
392
393 if(picker) *picker = dev->color_picker.widget;
394 if(pipe) *pipe = current_pipe;
395 if(piece) *piece = current_piece;
397 "[picker] ready-data module=%s hash=%" PRIu64 " pipe=%p picker=%p\n",
398 module->op, current_piece->global_hash, (void *)current_pipe, (void *)dev->color_picker.widget);
399 return 0;
400}
401
403{
405 || !dev->color_picker.module || !dev->gui_module || dev->color_picker.module != dev->gui_module
406 || !dev->gui_module->enabled)
407 {
409 "[picker] guard bailout picker=%p enabled=%d picker_module=%s gui_module=%s "
410 "same_module=%d gui_module_enabled=%d\n",
411 (void *)(dev ? dev->color_picker.picker : NULL),
412 dev ? dev->color_picker.enabled : -1,
413 (dev && dev->color_picker.module) ? dev->color_picker.module->op : "-",
414 (dev && dev->gui_module) ? dev->gui_module->op : "-",
415 (dev && dev->color_picker.module && dev->gui_module)
416 ? (dev->color_picker.module == dev->gui_module)
417 : -1,
418 (dev && dev->gui_module) ? dev->gui_module->enabled : -1);
420 }
421
422 dt_dev_pixelpipe_t *const pipe = dev->preview_pipe;
424 const dt_dev_pixelpipe_iop_t *const previous_piece
426 if(IS_NULL_PTR(piece) || IS_NULL_PTR(previous_piece))
427 {
428 dt_print(DT_DEBUG_DEV, "[picker] sample retry module=%s piece=%p prev=%p\n",
429 dev->color_picker.module ? dev->color_picker.module->op : "-", (void *)piece, (void *)previous_piece);
431 }
432
434 || previous_piece->global_hash == DT_PIXELPIPE_CACHE_HASH_INVALID)
435 {
437 "[picker] invalid hash module=%s piece=%" PRIu64 " prev=%" PRIu64 "\n",
438 piece->module->op, piece->global_hash, previous_piece->global_hash);
440 }
441
442 /* Check the module's own OUTPUT before its input. Computing a module's output requires computing
443 * its input first (process_rec always recurses upstream before producing the requesting node), so
444 * requesting the output as the MODULE cache target makes a single recompute satisfy both this and
445 * the input wait below. Checking input first (as before) would bail out on an input miss without
446 * ever touching output, costing a full separate recompute round-trip for output afterwards even
447 * though computing it would have produced the input as a side effect anyway -- the common case
448 * right after focusing a module whose input/output were never sampled on this image (e.g. right
449 * after loading, or a module that stayed collapsed since darkroom opened). Output is skipped here
450 * only when it can structurally never resolve (bypass_cache/no_cache/realtime), since then nothing
451 * would ever recurse through for us and we must fall back to requesting the input on its own. */
452 void *output = NULL;
453 dt_pixel_cache_entry_t *output_entry = NULL;
454 const gboolean output_cache_blocked_by_policy
455 = piece->bypass_cache || pipe->bypass_cache || pipe->no_cache || dt_dev_pixelpipe_get_realtime(pipe);
456 dt_dev_pixelpipe_cache_wait_set_owner(&dev->color_picker.output_wait, "color-picker-output", dev->color_picker.module);
457 const gboolean have_output = dt_dev_pixelpipe_cache_peek_gui(pipe, piece, &output, &output_entry,
460 if(!have_output && !output_cache_blocked_by_policy)
461 {
464 "[picker] output cache miss module=%s hash=%" PRIu64 " (recompute will also satisfy input)\n",
465 piece->module->op, piece->global_hash);
467 }
468
469 void *input = NULL;
470 dt_pixel_cache_entry_t *input_entry = NULL;
471 dt_dev_pixelpipe_cache_wait_set_owner(&dev->color_picker.input_wait, "color-picker-input", dev->color_picker.module);
472 if(!dt_dev_pixelpipe_cache_peek_gui(pipe, previous_piece, &input, &input_entry,
474 {
475 dev->color_picker.wait_input_hash = previous_piece->global_hash;
476 dt_print(DT_DEBUG_DEV, "[picker] input cache miss module=%s prev_hash=%" PRIu64 "\n",
477 piece->module->op, previous_piece->global_hash);
479 }
480
481 if(!have_output)
482 {
483 /* Only reachable when output_cache_blocked_by_policy: module GUIs such as color equalizer only
484 consume the module-input sample, and some pipe modes (bypass_cache/no_cache/realtime) can never
485 publish a module output cacheline at all. Keep output statistics explicitly invalid so
486 output-dependent consumers can detect the missing sample, but still publish the ready input
487 sample instead of blocking picker feedback forever. */
488 dt_print(DT_DEBUG_DEV, "[picker] output cache blocked by policy module=%s hash=%" PRIu64 "\n",
489 piece->module->op, piece->global_hash);
491
492 for(int k = 0; k < 4; k++)
493 {
494 piece->module->picked_output_color[k] = 0.0f;
495 piece->module->picked_output_color_min[k] = 666.0f;
496 piece->module->picked_output_color_max[k] = -666.0f;
497 }
498 }
499
500 if(previous_piece->dsc_out.datatype != TYPE_FLOAT || (have_output && piece->dsc_out.datatype != TYPE_FLOAT))
501 {
503 "[picker] non-float buffers module=%s input_type=%d output_type=%d\n",
504 piece->module->op, previous_piece->dsc_out.datatype, piece->dsc_out.datatype);
506 }
507
508 /* Unlike histogram/global backbuffers, module color-pickers do not publish a dedicated long-lived buffer.
509 * They reopen the current module input/output cachelines by immutable `global_hash`, then take a temporary
510 * ref plus read lock only for the duration of the sampling pass so concurrent cache recycling cannot free
511 * the payload mid-read. */
514 if(have_output)
515 {
518 }
519
520 const gboolean sampled_input
521 = _sample_picker_buffer(pipe, piece->module, &previous_piece->dsc_out, &previous_piece->roi_out,
522 input, piece->module->picked_color, piece->module->picked_color_min,
523 piece->module->picked_color_max, PIXELPIPE_PICKER_INPUT);
524 const gboolean sampled_output
525 = have_output
526 ? _sample_picker_buffer(pipe, piece->module, &piece->dsc_out, &piece->roi_out, output,
527 piece->module->picked_output_color, piece->module->picked_output_color_min,
528 piece->module->picked_output_color_max, PIXELPIPE_PICKER_OUTPUT)
529 : FALSE;
530
531 if(!have_output && sampled_input)
532 {
533 // Keep GUI picker feedback alive whenever module output is temporarily
534 // unavailable: mirror input sample statistics to output slots. If output
535 // cache becomes available later, subsequent refreshes overwrite these with
536 // true output samples.
537 for(int k = 0; k < 4; k++)
538 {
539 piece->module->picked_output_color[k] = piece->module->picked_color[k];
540 piece->module->picked_output_color_min[k] = piece->module->picked_color_min[k];
541 piece->module->picked_output_color_max[k] = piece->module->picked_color_max[k];
542 }
543 }
544
545 if(have_output)
546 {
549 }
552
553 if(!sampled_input)
554 {
555 dt_print(DT_DEBUG_DEV, "[picker] sample failed module=%s input=%d output=%d\n",
556 piece->module->op, sampled_input, sampled_output);
557 dev->color_picker.picker->update_pending = FALSE;
560 }
561
563 "[picker] sampled module=%s hash=%" PRIu64 " avg=(%g,%g,%g) min=(%g,%g,%g) max=(%g,%g,%g)\n",
564 piece->module->op, piece->global_hash,
565 piece->module->picked_color[0], piece->module->picked_color[1], piece->module->picked_color[2],
566 piece->module->picked_color_min[0], piece->module->picked_color_min[1], piece->module->picked_color_min[2],
567 piece->module->picked_color_max[0], piece->module->picked_color_max[1], piece->module->picked_color_max[2]);
568
569 dev->color_picker.piece_hash = piece->global_hash;
570 dev->color_picker.pending_module = piece->module;
571 dev->color_picker.pending_pipe = pipe;
574 dev->color_picker.picker->update_pending = FALSE;
576
578 dev->color_picker.pending_module = NULL;
579 dev->color_picker.pending_pipe = NULL;
582}
583
584static gboolean _refresh_active_picker_idle(gpointer user_data)
585{
586 dt_develop_t *const dev = (dt_develop_t *)user_data;
587 if(dev) dev->color_picker.refresh_idle_source = 0;
589 return G_SOURCE_REMOVE;
590}
591
593{
594 if(IS_NULL_PTR(dev)) return;
595 if(dev->color_picker.refresh_idle_source) return;
597}
598
599static void _restart_picker_cache_wait(gpointer user_data)
600{
601 dt_develop_t *const dev = (dt_develop_t *)user_data;
603}
604
606{
607 if(IS_NULL_PTR(dev) || IS_NULL_PTR(dev->color_picker.picker) || !dev->color_picker.enabled) return;
608 if(!dev->color_picker.picker->update_pending && !dev->color_picker.update_pending) return;
609
611 "[picker] refresh module=%s update_pending=%d widget_pending=%d processing=%d\n",
612 dev->color_picker.module ? dev->color_picker.module->op : "-",
613 dev->color_picker.update_pending, dev->color_picker.picker->update_pending,
614 dev->preview_pipe ? dev->preview_pipe->processing : -1);
615
617
618 /* A picker update is satisfied either from the current preview cache or from the next completed
619 preview run. If preview is already processing, re-dirtying it here only feeds TOP_CHANGED
620 loops and prevents the current run from ever publishing the cacheline we are waiting for. */
622 {
623 // Make sure CACHELINE_READY can wake us as soon as this in-flight run
624 // publishes input/output cachelines for the active picker.
626 return;
627 }
628
629 if(IS_NULL_PTR(dev->color_picker.module))
630 {
631 /* The global picker already samples from histogram backbuffers published by preview updates.
632 Refresh it directly from that GUI-owned cache when possible so dragging the picker updates
633 the histogram labels immediately without waiting for another preview completion. */
637 {
638 dev->color_picker.picker->update_pending = FALSE;
641 return;
642 }
643 }
644
645 if(dev->preview_pipe)
646 {
648 if(sampled != DT_COLOR_PICKER_RESAMPLE_RETRY)
649 return;
650 }
651}
652
654{
655 if(picker)
656 {
657 if(picker->module) dt_iop_set_cache_bypass(picker->module, FALSE);
658
660
662 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(picker->colorpick), FALSE);
663 else
665
667 }
668}
669
671{
672 (void)widget;
673 dt_develop_t *const dev = darktable.develop;
674 if(IS_NULL_PTR(dev) || dev->color_picker.picker != picker) return;
675
676 // Mirror dt_iop_color_picker_reset()'s cleanup: the picker's own button widget is the one being
677 // destroyed here (e.g. a module GUI panel rebuild), so there is no widget left to toggle off, but
678 // every other piece of dev-wide picker state must still be cleared the same way. Leaving
679 // dev->color_picker.enabled/.module stale keeps dt_iop_color_picker_is_visible() reporting a
680 // picker "active" for a module whose picker widget no longer exists -- observed as the custom
681 // cursor in iop/toneequal.c getting stuck, fixed only by fully reloading the image (issue #1028).
682 dt_iop_module_t *const module = dev->color_picker.module;
683
684 dt_dev_pixelpipe_cache_wait_cleanup(&dev->color_picker.input_wait, "picker-widget-destroyed-input");
685 dt_dev_pixelpipe_cache_wait_cleanup(&dev->color_picker.output_wait, "picker-widget-destroyed-output");
686
687 dev->color_picker.picker = NULL;
688 dev->color_picker.widget = NULL;
689 dev->color_picker.module = NULL;
694 if(module) module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
695}
696
697void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
698{
699 dt_develop_t *const dev = darktable.develop;
700 dt_iop_color_picker_t *picker = dev ? dev->color_picker.picker : NULL;
701 if(picker && picker->module == module)
702 {
703 if(!keep)
704 {
707 _color_picker_reset(picker);
708 dev->color_picker.picker = NULL;
709 dev->color_picker.widget = NULL;
710 dev->color_picker.module = NULL;
715 if(module) module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
716 }
717 }
718}
719
722{
723 // module is NULL if primary colorpicker
724 picker->module = module;
725 picker->kind = kind;
726 picker->picker_cst = module ? module->default_colorspace(module, NULL, NULL) : IOP_CS_NONE;
727 picker->colorpick = button;
728 picker->update_pending = FALSE;
729 picker->geometry_is_raw = FALSE;
730
731 // default values
732 const float middle = 0.5f;
733 const float area = 0.975f;
734 picker->pick_pos[0] = picker->pick_pos[1] = middle;
735 picker->pick_box[0] = (1.0f - area);
736 picker->pick_box[1] = (1.0f - area);
737 picker->pick_box[2] = area;
738 picker->pick_box[3] = area;
739
740 _color_picker_reset(picker);
741}
742
743static gboolean _color_picker_callback_button_press(GtkWidget *button, GdkEventButton *e, dt_iop_color_picker_t *self)
744{
745 // module is NULL if primary colorpicker
746 dt_iop_module_t *module = self->module;
747 dt_develop_t *const dev = darktable.develop;
748
750 {
751 dt_print(DT_DEBUG_DEV, "[picker] click ignored: widgets suppressed module=%s\n",
752 module ? module->op : "global");
753 return FALSE;
754 }
755
756 dt_iop_color_picker_t *prior_picker = dev ? dev->color_picker.picker : NULL;
757 if(prior_picker && prior_picker != self)
758 {
759 _color_picker_reset(prior_picker);
760 if(prior_picker->module) prior_picker->module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
761 }
762
763 if(module && module->off)
764 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), TRUE);
765
766 const GdkModifierType state = !IS_NULL_PTR(e) ? e->state : dt_key_modifier_state();
767 const gboolean ctrl_key_pressed = dt_modifier_is(state, GDK_CONTROL_MASK) || (!IS_NULL_PTR(e) && e->button == 3);
769
770 if(prior_picker != self || (kind == DT_COLOR_PICKER_POINT_AREA &&
771 (ctrl_key_pressed ^ (dev->color_picker.primary_sample->size == DT_LIB_COLORPICKER_SIZE_BOX))))
772 {
773 dev->color_picker.picker = self;
774 dev->color_picker.widget = self->colorpick;
775 dev->color_picker.module = module;
776 dev->color_picker.kind = kind;
777 dev->color_picker.picker_cst = self->picker_cst;
778 dev->color_picker.enabled = TRUE;
779
780 if(module) module->request_color_pick = DT_REQUEST_COLORPICK_MODULE;
781
783 {
784 kind = ctrl_key_pressed ? DT_COLOR_PICKER_AREA : DT_COLOR_PICKER_POINT;
785 }
787
789 {
790 dt_boundingbox_t image_box = { 0.0f };
791 _picker_raw_box_to_image_norm(dev, self->pick_box, image_box);
793 }
794 else if(kind == DT_COLOR_PICKER_POINT)
795 {
796 float image_point[2] = { 0.0f };
797 _picker_raw_point_to_image_norm(dev, self->pick_pos, image_point);
799 }
800 else
802
803 // important to have set up state before toggling button and
804 // triggering more callbacks
807 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->colorpick), TRUE);
808 else
811
812 dt_iop_module_t *const gui_module_before_focus = dev->gui_module;
813 if(module)
814 dt_iop_request_focus(module);
815
817 "[picker] activate module=%s picker=%p widget=%p kind=%d cst=%d gui_module_before=%s "
818 "gui_module_after=%s widgets_suppressed=%d\n",
819 module ? module->op : "global", (void *)self, (void *)self->colorpick, kind, self->picker_cst,
820 gui_module_before_focus ? gui_module_before_focus->op : "-",
821 dev->gui_module ? dev->gui_module->op : "-", dt_gui_widgets_suppressed());
822
823 }
824 else
825 {
826 dt_dev_pixelpipe_cache_wait_cleanup(&dev->color_picker.input_wait, "picker-deactivate-input");
827 dt_dev_pixelpipe_cache_wait_cleanup(&dev->color_picker.output_wait, "picker-deactivate-output");
828 dev->color_picker.picker = NULL;
829 dev->color_picker.widget = NULL;
830 dev->color_picker.module = NULL;
831 dev->color_picker.kind = DT_COLOR_PICKER_POINT;
832 dev->color_picker.picker_cst = IOP_CS_NONE;
833 dev->color_picker.enabled = FALSE;
834 dev->color_picker.update_pending = FALSE;
836 if(module)
837 {
838 module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
839 }
840 dt_print(DT_DEBUG_DEV, "[picker] deactivate module=%s picker=%p widget=%p\n",
841 module ? module->op : "global", (void *)self, (void *)self->colorpick);
842 }
843
844 // Draw picker geometry immediately; data sampling update can complete later.
846 if(dev->color_picker.enabled)
848
849 return TRUE;
850}
851
853{
854 _color_picker_callback_button_press(button, NULL, self);
855}
856
858{
859 dt_develop_t *const dev = darktable.develop;
860 dt_iop_color_picker_t *const picker = dev ? dev->color_picker.picker : NULL;
861 if(picker && picker->module == module && picker->picker_cst != picker_cst)
862 {
863 picker->picker_cst = picker_cst;
865 }
866}
867
869{
870 dt_develop_t *const dev = darktable.develop;
871 dt_iop_color_picker_t *picker = dev ? dev->color_picker.picker : NULL;
872 if(picker && picker->module == module)
873 return picker->picker_cst;
874 else
875 return IOP_CS_NONE;
876}
877
879{
880 dt_develop_t *const dev = darktable.develop;
881 dt_iop_color_picker_t *picker = dev ? dev->color_picker.picker : NULL;
882 if(picker) picker->update_pending = TRUE;
883 if(dev)
884 {
886 }
887 if(dev)
888 dt_print(DT_DEBUG_DEV, "[picker] request update module=%s picker=%p widget=%p\n",
889 dev->color_picker.module ? dev->color_picker.module->op : "-",
890 (void *)dev->color_picker.picker, (void *)dev->color_picker.widget);
892}
893
895 const dt_iop_module_t *module)
896{
898 pipe->dev->color_picker.module);
899 const dt_dev_pixelpipe_iop_t *const previous_piece = dt_dev_pixelpipe_get_prev_enabled_piece(pipe, piece);
900
901 return module == pipe->dev->color_picker.module || (previous_piece && previous_piece->module == module);
902}
903
905{
906 if(IS_NULL_PTR(dev))
907 return;
908
911
913 || !dev->color_picker.module || !dev->gui_module || dev->color_picker.module != dev->gui_module
914 || !dev->gui_module->enabled)
915 return;
916
918 dev->color_picker.module);
919 const dt_dev_pixelpipe_iop_t *const previous_piece
921 if(piece) dev->color_picker.wait_output_hash = piece->global_hash;
922 if(previous_piece) dev->color_picker.wait_input_hash = previous_piece->global_hash;
923}
924
925static void _iop_color_picker_history_resync_callback(gpointer instance, gpointer user_data)
926{
927 (void)instance;
928 (void)user_data;
929 dt_develop_t *const dev = darktable.develop;
932}
933
934static void _iop_color_picker_cacheline_ready_callback(gpointer instance, const guint64 hash,
935 const guint64 producer_node_key, gpointer user_data)
936{
937 (void)instance;
938 (void)producer_node_key; // the shared cache-wait manager serves the picker's input/output
939 // waits by producer node; this direct path stays exact-hash only.
940 (void)user_data;
941
942 dt_develop_t *const dev = darktable.develop;
943 if(IS_NULL_PTR(dev)) return;
944
945 gboolean matched = FALSE;
946 if(dev->color_picker.wait_input_hash == hash)
947 {
949 matched = TRUE;
950 }
951 if(dev->color_picker.wait_output_hash == hash)
952 {
954 matched = TRUE;
955 }
956
957 if(matched) _queue_refresh_active_picker(dev);
958}
959
979static void _iop_color_picker_pipe_finished_callback(gpointer instance, gpointer user_data)
980{
981 (void)instance;
982 (void)user_data;
983 dt_develop_t *const dev = darktable.develop;
984 if(IS_NULL_PTR(dev)) return;
986}
987
996static void _iop_color_picker_notebook_tab_changed_callback(gpointer instance, gpointer owner, gpointer user_data)
997{
998 (void)instance;
999 (void)user_data;
1000 if(IS_NULL_PTR(owner)) return;
1002}
1003
1015
1027
1029 const gboolean init_cst, const dt_iop_colorspace_type_t cst)
1030{
1031 dt_iop_color_picker_t *color_picker = (dt_iop_color_picker_t *)g_malloc(sizeof(dt_iop_color_picker_t));
1032
1033 if(IS_NULL_PTR(w) || GTK_IS_BOX(w))
1034 {
1036 _init_picker(color_picker, module, kind, button);
1037 if(init_cst)
1038 color_picker->picker_cst = cst;
1039 g_signal_connect_data(G_OBJECT(button), "button-press-event",
1040 G_CALLBACK(_color_picker_callback_button_press), color_picker, (GClosureNotify)g_free, 0);
1041 g_signal_connect(G_OBJECT(button), "destroy", G_CALLBACK(_color_picker_widget_destroy), color_picker);
1042 if(w) gtk_box_pack_start(GTK_BOX(w), button, FALSE, FALSE, 0);
1043
1044 dt_develop_t *const dev = darktable.develop;
1045 if(dev && dev->color_picker.enabled && dev->color_picker.module == module
1047 && dev->color_picker.kind == kind
1048 && dev->color_picker.picker_cst == color_picker->picker_cst)
1049 {
1050 dev->color_picker.picker = color_picker;
1051 dev->color_picker.widget = button;
1052
1054 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1056 }
1057
1058 return button;
1059 }
1060 else
1061 {
1064 _init_picker(color_picker, module, kind, w);
1065 if(init_cst)
1066 color_picker->picker_cst = cst;
1067 g_signal_connect_data(G_OBJECT(w), "quad-pressed",
1068 G_CALLBACK(_color_picker_callback), color_picker, (GClosureNotify)g_free, 0);
1069 g_signal_connect(G_OBJECT(w), "destroy", G_CALLBACK(_color_picker_widget_destroy), color_picker);
1070
1071 dt_develop_t *const dev = darktable.develop;
1072 if(dev && dev->color_picker.enabled && dev->color_picker.module == module
1074 && dev->color_picker.kind == kind
1075 && dev->color_picker.picker_cst == color_picker->picker_cst)
1076 {
1077 dev->color_picker.picker = color_picker;
1078 dev->color_picker.widget = w;
1079
1083 }
1084
1085 return w;
1086 }
1087}
1088
1093
1099
1100// clang-format off
1101// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1102// vim: shiftwidth=2 expandtab tabstop=2 cindent
1103// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1104// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_widget_set_quad_toggle(GtkWidget *widget, int toggle)
Definition bauhaus.c:1723
void dt_bauhaus_widget_set_quad_active(GtkWidget *widget, int active)
Definition bauhaus.c:1729
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
Definition bauhaus.c:1705
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_adaptation_t kind
dt_iop_colorspace_type_t
@ IOP_CS_NONE
void dt_color_picker_helper(const dt_iop_buffer_dsc_t *dsc, const float *const pixel, const dt_iop_roi_t *roi, const int *const box, dt_aligned_pixel_t picked_color, dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max, const dt_iop_colorspace_type_t image_cst, const dt_iop_colorspace_type_t picker_cst, const dt_iop_order_iccprofile_info_t *const profile)
static void _restart_picker_cache_wait(gpointer user_data)
static void _iop_color_picker_cacheline_ready_callback(gpointer instance, const guint64 hash, const guint64 producer_node_key, gpointer user_data)
static void _picker_raw_box_to_image_norm(const dt_develop_t *dev, const float raw_box[4], float image_box[4])
static void _color_picker_widget_destroy(GtkWidget *widget, dt_iop_color_picker_t *picker)
static void _queue_refresh_active_picker(dt_develop_t *dev)
void dt_iop_color_picker_init(void)
static void _refresh_active_picker(dt_develop_t *dev)
static int _picker_sample_box(const dt_iop_module_t *module, const dt_iop_roi_t *roi, const dt_pixelpipe_picker_source_t picker_source, int *box)
void dt_iop_color_picker_cleanup(void)
static void _iop_color_picker_notebook_tab_changed_callback(gpointer instance, gpointer owner, gpointer user_data)
static gboolean _record_point_area(dt_iop_color_picker_t *self)
Synchronize one picker cached geometry with the primary sample.
gboolean dt_iop_color_picker_force_cache(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module)
static gboolean _sample_picker_buffer(dt_dev_pixelpipe_t *pipe, dt_iop_module_t *module, const dt_iop_buffer_dsc_t *dsc, const dt_iop_roi_t *roi, const float *pixel, dt_aligned_pixel_t avg_out, dt_aligned_pixel_t min_out, dt_aligned_pixel_t max_out, const dt_pixelpipe_picker_source_t picker_source)
static void _iop_color_picker_pipe_finished_callback(gpointer instance, gpointer user_data)
void dt_iop_color_picker_request_update(void)
static void _picker_get_module_bounds_image_norm(const dt_develop_t *dev, const dt_iop_module_t *active_module, float bounds[4])
static void _track_active_picker_hashes(dt_develop_t *dev)
static gboolean _refresh_active_picker_idle(gpointer user_data)
static void _iop_color_picker_history_resync_callback(gpointer instance, gpointer user_data)
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
int dt_iop_color_picker_get_ready_data(const dt_iop_module_t *module, GtkWidget **picker, dt_dev_pixelpipe_t **pipe, const dt_dev_pixelpipe_iop_t **piece)
dt_pixelpipe_picker_source_t
@ PIXELPIPE_PICKER_INPUT
@ PIXELPIPE_PICKER_OUTPUT
static gboolean _color_picker_callback_button_press(GtkWidget *button, GdkEventButton *e, dt_iop_color_picker_t *self)
void dt_iop_color_picker_set_cst(dt_iop_module_t *module, const dt_iop_colorspace_type_t picker_cst)
GtkWidget * dt_color_picker_new_with_cst(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w, const dt_iop_colorspace_type_t cst)
static void _color_picker_reset(dt_iop_color_picker_t *picker)
static dt_color_picker_resample_status_t _sample_picker_from_cache(dt_develop_t *dev)
gboolean dt_iop_color_picker_is_active_module(const dt_iop_module_t *module)
Tell whether one module currently owns the active darkroom picker.
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
static void _picker_raw_point_to_image_norm(const dt_develop_t *dev, const float raw_point[2], float image_point[2])
gboolean dt_iop_color_picker_is_visible(const dt_develop_t *dev)
static void _color_picker_callback(GtkWidget *button, dt_iop_color_picker_t *self)
dt_color_picker_resample_status_t
@ DT_COLOR_PICKER_RESAMPLE_RETRY
@ DT_COLOR_PICKER_RESAMPLE_CONSUMED
@ DT_COLOR_PICKER_RESAMPLE_EMITTED
static void _init_picker(dt_iop_color_picker_t *picker, dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *button)
static GtkWidget * _color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w, const gboolean init_cst, const dt_iop_colorspace_type_t cst)
dt_iop_colorspace_type_t dt_iop_color_picker_get_active_cst(dt_iop_module_t *module)
static void _picker_initialize_geometry_raw(dt_iop_color_picker_t *picker, dt_develop_t *dev)
enum _iop_color_picker_kind_t dt_iop_color_picker_kind_t
@ DT_COLOR_PICKER_AREA
@ DT_COLOR_PICKER_POINT
@ DT_COLOR_PICKER_POINT_AREA
@ DT_LIB_COLORPICKER_SIZE_POINT
Definition colorpicker.h:37
@ DT_LIB_COLORPICKER_SIZE_BOX
Definition colorpicker.h:38
static const float const float const float min
const float max
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:877
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_DEV
Definition darktable.h:739
#define dt_gui_freeze_begin()
Definition darktable.h:900
#define dt_gui_freeze_end()
Definition darktable.h:901
float dt_boundingbox_t[4]
Definition darktable.h:731
void void void gboolean dt_gui_widgets_suppressed(void)
Definition gtk.c:194
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
Definition darktable.h:955
#define dt_unreachable_codepath()
Definition darktable.h:1041
#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 darktable.h:293
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_module_piece(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module)
void dt_dev_pixelpipe_cache_wait_cleanup(dt_dev_pixelpipe_cache_wait_t *wait, const char *reason)
Cancel one pending GUI cache wait request and clear its runtime state.
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_prev_enabled_piece(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void dt_dev_pixelpipe_cache_wait_set_owner(dt_dev_pixelpipe_cache_wait_t *wait, const char *owner_tag, gpointer owner_object)
Attach debug ownership metadata to one cache wait request.
gboolean dt_dev_pixelpipe_cache_peek_gui(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, void **data, dt_pixel_cache_entry_t **cache_entry, dt_dev_pixelpipe_cache_wait_t *wait, dt_dev_pixelpipe_cache_ready_callback_t restart, gpointer restart_data)
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1621
void dt_dev_coordinates_raw_norm_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1184
void dt_dev_coordinates_image_norm_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1177
void dt_dev_coordinates_image_norm_to_image_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1113
int dt_dev_distort_backtransform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1650
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
Definition develop.h:103
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
Definition develop.h:104
void dtgtk_cairo_paint_colorpicker(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ TYPE_FLOAT
Definition format.h:46
GdkModifierType dt_key_modifier_state()
Definition gtk.c:2397
void dt_iop_request_focus(dt_iop_module_t *module)
Definition imageop.c:2221
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
Definition imageop.c:2989
@ DT_REQUEST_COLORPICK_OFF
Definition imageop.h:226
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
void dt_lib_colorpicker_set_box_area(dt_lib_t *lib, const dt_boundingbox_t box)
Definition lib.c:1456
void dt_lib_colorpicker_set_point(dt_lib_t *lib, const float pos[2])
Definition lib.c:1478
float *const restrict const size_t k
float dt_aligned_pixel_t[4]
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:387
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:366
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:174
@ DT_SIGNAL_HISTORY_RESYNC
This signal is raised once darkroom history has been resynchronized into all live pipelines....
Definition signal.h:209
@ DT_SIGNAL_CACHELINE_READY
This signal is raised when one cacheline write lock is released. 1 : uint64_t cacheline hash no retur...
Definition signal.h:185
@ DT_SIGNAL_CONTROL_NOTEBOOK_TAB_CHANGED
This signal is raised when a GtkNotebook created/registered via dt_ui_notebook_set_picker_owner() swi...
Definition signal.h:302
@ DT_SIGNAL_CONTROL_PICKERDATA_READY
This signal is raised when new color picker data are available in darkroom. no param,...
Definition signal.h:293
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:376
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
struct dt_lib_t * lib
Definition darktable.h:799
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_develop_t * develop
Definition darktable.h:798
dt_lib_colorpicker_size_t size
Definition colorpicker.h:63
dt_boundingbox_t box
Definition colorpicker.h:62
dt_iop_buffer_dsc_t dsc_out
struct dt_iop_module_t *void * data
struct dt_develop_t * dev
int picker_cst
Definition develop.h:392
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
struct dt_colorpicker_sample_t * primary_sample
Definition develop.h:397
gboolean update_pending
Definition develop.h:394
uint64_t wait_output_hash
Definition develop.h:409
GtkWidget * widget
Definition develop.h:390
gboolean(* refresh_global_picker)(struct dt_lib_module_t *self)
Definition develop.h:405
struct dt_iop_module_t * pending_module
Definition develop.h:413
int32_t processed_width
Definition develop.h:233
struct dt_iop_module_t * gui_module
Definition develop.h:165
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:247
dt_dev_pixelpipe_cache_wait_t output_wait
Definition develop.h:411
struct dt_iop_module_t *struct dt_iop_color_picker_t * picker
Definition develop.h:389
struct dt_develop_t::@17 roi
uint64_t wait_input_hash
Definition develop.h:408
guint refresh_idle_source
Definition develop.h:395
int32_t processed_height
Definition develop.h:233
struct dt_dev_pixelpipe_t * pending_pipe
Definition develop.h:414
struct dt_lib_module_t * histogram_module
Definition develop.h:404
gboolean enabled
Definition develop.h:393
uint64_t piece_hash
Definition develop.h:407
dt_dev_pixelpipe_cache_wait_t input_wait
Definition develop.h:410
dt_iop_buffer_type_t datatype
Definition format.h:56
dt_iop_module_t *dt_iop_color_picker_kind_t kind
dt_boundingbox_t pick_box
dt_iop_colorspace_type_t picker_cst
GModule *dt_dev_operation_t op
Definition imageop.h:286
gboolean enabled
Definition imageop.h:335
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
#define DTGTK_IS_TOGGLEBUTTON(obj)