Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
masks.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2013-2014, 2016, 2019, 2021 Aldric Renaudin.
4 Copyright (C) 2013, 2018, 2020-2021 Pascal Obry.
5 Copyright (C) 2013 Simon Spannagel.
6 Copyright (C) 2013-2014, 2016-2018 Tobias Ellinghaus.
7 Copyright (C) 2013-2017, 2019-2020 Ulrich Pegelow.
8 Copyright (C) 2014-2016 Roman Lebedev.
9 Copyright (C) 2017-2019 Edgardo Hoszowski.
10 Copyright (C) 2021 Hanno Schwalm.
11 Copyright (C) 2021 Hubert Kowalski.
12 Copyright (C) 2021 luzpaz.
13 Copyright (C) 2021 Philipp Lutz.
14 Copyright (C) 2021 Ralf Brown.
15 Copyright (C) 2022 Martin Bařinka.
16 Copyright (C) 2023, 2025-2026 Aurélien PIERRE.
17 Copyright (C) 2023 Luca Zulberti.
18 Copyright (C) 2025 Alynx Zhou.
19 Copyright (C) 2025-2026 Guillaume Stutin.
20
21 darktable is free software: you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation, either version 3 of the License, or
24 (at your option) any later version.
25
26 darktable is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with darktable. If not, see <http://www.gnu.org/licenses/>.
33*/
34
35
36/*
37Typical forms tree structure :
38
39GList darktable.develop->forms
40 |
41 0) dt_masks_form_t circle --------------------> ID 1771813676, "circle #2"
42 | { GList *points
43 | | dt_masks_form_t --------------------> dt_masks_type_t type; const dt_masks_functions_t *functions;
44 | | float source[2]; char name[128]; int formid; int version;
45 | { GList *points;
46 | | dt_masks_node_circle_t ----> float center[2]; float radius; float border;
47 |
48 |
49 1) dt_masks_form_t group ---------------------> ID 1771813678, "grp retouch"
50 | { GList *points
51 | |-> dt_masks_form_group_t : ID 1771813676, parentid: 1771813678, state: use show union
52 | |-> dt_masks_form_group_t : ID 1771942330, parentid: 1771813678, state: use show union
53 |
54 |
55 2) dt_masks_form_t polygon -------------------> ID 1771815454, "polygon #1"
56 | { GList *points
57 | | dt_masks_form_t -------------------> dt_masks_type_t type; const dt_masks_functions_t *functions;
58 | | float source[2]; char name[128]; int formid; int version;
59 | { GList *points;
60 | | dt_masks_node_polygon_t ---> float node[2]; float ctrl1[2]; float ctrl2[2]; float border[2];
61 | | dt_masks_node_polygon_t ---> ...
62 | | ...
63 | | ...
64 |
65 |
66 3) dt_masks_form_t group ---------------------> ID 1771942331, "grp exposure"
67 | { GList *points
68 | |-> dt_masks_form_group_t : ID 1771815454, parentid: 1771942331, state: use show union
69 | |-> dt_masks_form_group_t : ID 1771877226, parentid: 1771942331, state: use show union
70 | |-> dt_masks_form_group_t : ID 1771877232, parentid: 1771942331, state: use show union
71 |
72 |
73 4) dt_masks_form_t ellipse -------------------> ID 1771877226, "ellipse #1"
74 | { GList *points
75 | | dt_masks_form_t --------------------> dt_masks_type_t type; const dt_masks_functions_t *functions;
76 | | float source[2]; char name[128]; int formid; int version;
77 | { GList *points;
78 | | dt_masks_node_ellipse_t ---> float center[2]; float radius[2]; float rotation;
79 | float border; dt_masks_ellipse_flags_t flags;
80 |
81 |
82 5) dt_masks_form_t brush ---------------------> ID 1771877232, "brush #1"
83 | { GList *points
84 | | dt_masks_form_t --------------------> dt_masks_type_t type; const dt_masks_functions_t *functions;
85 | | float source[2]; char name[128]; int formid; int version;
86 | { GList *points;
87 | | dt_masks_node_brush_t -----> float node[2]; float pressure; float hardness; float size;
88 | | dt_masks_pressure_sensitivity_t pressure_sensitivity;
89 | | dt_masks_node_brush_t -----> ...
90 | |
91 | | ...
92 | | ...
93 |
94 |
95 6) dt_masks_form_t gradient -------------------> ID 1771942330, "gradient #1"
96 | { GList *points
97 | | dt_masks_form_t ---------------------> dt_masks_type_t type; const dt_masks_functions_t *functions;
98 | | float source[2]; char name[128]; int formid; int version;
99 | { GList *points;
100 | | dt_masks_anchor_gradient_t -> float center[2]; float rotation; float extent; float steepness; float curvature;
101 |
102 7)...
103 |
104 ...
105
106
107*/
108
109#pragma once
110
111#include "common/darktable.h"
112#include "common/opencl.h"
113#include "develop/pixelpipe.h"
114#include "dtgtk/button.h"
115#include "dtgtk/gradientslider.h"
116#include "gui/draw.h"
117#include "control/control.h"
118
119#include <assert.h>
120
121#ifdef __cplusplus
122extern "C" {
123#endif
124
125#define DEVELOP_MASKS_VERSION (6)
126
152
179
185
191
198
205
215
221
228
231{
232 float center[2]; // point in normalized input space
233 float radius;
234 float border;
236
246
256
268
279
288
289struct dt_masks_form_t;
291struct dt_develop_t;
292
293/*
294* Type of user interaction to map with internal properties of masks.
295* Those were initially handled implicitly by Shift/Ctrl/Shift+Ctrl + mouse scroll
296* at the scope of each mask type, which is a shitty design when using Wacom tablets.
297* This case is now covered by the DT_MASK_INTERACTION_UNDEF.
298* Otherwise, when calling the mouse_scroll callback from GUI, we set the case
299* explicitly, along with a value.
300*/
302{
303 DT_MASKS_INTERACTION_UNDEF = 0, // let it be deduced contextually from key modifiers, implicit
304 DT_MASKS_INTERACTION_SIZE = 1, // property of the form (shape), explicit
305 DT_MASKS_INTERACTION_HARDNESS = 2, // property of the form (shape), explicit
306 DT_MASKS_INTERACTION_OPACITY = 3, // property of the group in which the form is included, explicit
309
313{
314 int point_struct_size; // sizeof(struct dt_masks_point_*_t)
316 void (*set_form_name)(struct dt_masks_form_t *const form, const size_t nb);
317 void (*set_hint_message)(const struct dt_masks_form_gui_t *const gui, const struct dt_masks_form_t *const form,
318 const int opacity, char *const __restrict__ msgbuf, const size_t msgbuf_len);
319 void (*duplicate_points)(struct dt_develop_t *const dev, struct dt_masks_form_t *base, struct dt_masks_form_t *dest);
320 void (*initial_source_pos)(const float iwd, const float iht, float *x, float *y);
321 // input coordinates are in absolute output-image space, dist is squared in the same space
322 void (*get_distance)(float x, float y, float as, struct dt_masks_form_gui_t *gui, int index, int num_points,
323 int *inside, int *inside_border, int *near, int *inside_source, float *dist);
324 int (*get_points)(struct dt_develop_t *dev, float x, float y, float radius_a, float radius_b, float rotation,
325 float **points, int *points_count);
326 int (*get_points_border)(struct dt_develop_t *dev, struct dt_masks_form_t *form, float **points, int *points_count,
327 float **border, int *border_count, int source, const dt_iop_module_t *const module);
328 int (*get_mask)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe,
329 const dt_dev_pixelpipe_iop_t *const piece,
330 struct dt_masks_form_t *const form,
331 float **buffer, int *width, int *height, int *posx, int *posy);
332 int (*get_mask_roi)(const dt_iop_module_t *const fmodule, struct dt_dev_pixelpipe_t *pipe,
333 const dt_dev_pixelpipe_iop_t *const piece,
334 struct dt_masks_form_t *const form,
335 const dt_iop_roi_t *roi, float *buffer);
336 int (*get_area)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe,
337 const dt_dev_pixelpipe_iop_t *const piece,
338 struct dt_masks_form_t *const form,
339 int *width, int *height, int *posx, int *posy);
341 dt_dev_pixelpipe_iop_t *piece, struct dt_masks_form_t *form,
342 int *width, int *height, int *posx, int *posy);
343 gboolean (*get_gravity_center)(const struct dt_masks_form_t *form, float center[2], float *area);
344 float (*get_interaction_value)(const struct dt_masks_form_t *form, dt_masks_interaction_t interaction);
345 float (*set_interaction_value)(struct dt_masks_form_t *form, dt_masks_interaction_t interaction, float value,
346 dt_masks_increment_t increment, int flow,
347 struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module);
348 /* Recompute hovered handles/nodes from the cached cursor state in gui. */
349 int (*update_hover)(struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, int index);
350 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
351 int (*mouse_moved)(struct dt_iop_module_t *module, double x, double y, double pressure, int which,
352 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
353 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
354 int (*mouse_scrolled)(struct dt_iop_module_t *module, double x, double y, int up, const int delta_y, uint32_t state,
355 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index,
356 dt_masks_interaction_t interaction);
357 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
358 int (*button_pressed)(struct dt_iop_module_t *module, double x, double y,
359 double pressure, int which, int type, uint32_t state,
360 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
361 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
362 int (*button_released)(struct dt_iop_module_t *module, double x, double y, int which, uint32_t state,
363 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
364 /* Key event */
365 int (*key_pressed)(struct dt_iop_module_t *module, GdkEventKey *event, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
366 void (*post_expose)(cairo_t *cr, float zoom_scale, struct dt_masks_form_gui_t *gui, int index, int num_points);
367 // The function to draw the shape in question.
368 void (*draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source);
371 int (*populate_context_menu)(GtkWidget *menu, struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, const float pzx, const float pzy);
373
375typedef struct dt_masks_form_t
376{
377 GList *points; // list of point structures (nodes)
380 // TRUE when gui_points->points uses the Bezier layout (points[k*6+2])
382
383 // position of the origin point of source (used only for clone)
384 // in normalized coordinates in raw input space
385 float source[2];
386
387 // cached center of gravity
388 // in normalized coordinates in raw input space
390
391 // cached shape area, taken as a weight estimator to get
392 // the gravity center of multi-shapes by combining
393 // weight and gravity centers of all shapes
394 float area;
395 // name of the form
396 char name[128];
397 // id used to store the form
399 // version of the form
402
405{
406 float *points; // points in absolute coordinates in output image space
408 float *border; // border points in absolute coordinates in output image space
410 float *source; // source point in absolute coordinates in output image space
412 gboolean clockwise;
414
416typedef struct dt_masks_dynbuf_t
417{
418 float *buffer;
419 char tag[128];
420 size_t pos;
421 size_t size;
423
424
427{
429 // currently visible form when editing masks (GUI-only; may be a temporary copy)
431 // points used to draw the form
432 GList *points; // list of dt_masks_form_gui_points_t
433
434 // points used to sample mouse moves
437
438 // values for mouse positions, etc...
439
440 // Mouse position in absolute coordinates in final image space
441 // This is used to map input event handlers to *_post_expose() drawing functions
442 // and to record drag & drop starting coordinates.
443 float pos[2];
444
445 // Mouse position in normalized coordinates in output image space.
446 // This is cached once per top-level event and replaces ad-hoc pzx/pzy recomputation.
447 float rel_pos[2];
448
449 // Mouse position in absolute coordinates in raw input image space.
450 // This is cached once per top-level event so nested handlers can reuse it.
451 float raw_pos[2];
452
453 // delta movement of the mouse in absolute coordinates in final image space
454 // This is used to map input event handlers to *_post_expose() drawing functions
455 float delta[2];
456
457 // scroll offset
459
460 // Position of a clone mask's source point (in what coordinates space ?)
461 float pos_source[2];
462
464
465 int node_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
466 int handle_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
467 int seg_hovered; // this is the index of the segment, refreshed on mouse_moved when a a group is selected
468 int handle_border_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
469
470 gboolean node_selected; // this is the state of the node referenced by node_hovered
471 gboolean handle_selected; // this is the state of the handle referenced by handle_hovered
472 gboolean seg_selected; // this is the state of the segment referenced by segment_hovered
473 gboolean handle_border_selected; // this is the state of the border handle referenced by handle_border_hovered
474 int node_selected_idx; // stable selected node index, distinct from current hover
475
480
482
484
494
495 // Throttle GUI rebuilds while dragging to avoid heavy border recomputation.
499
500 // Throttle handle hit-testing when cursor barely moves.
502
503 gboolean creation;
506 // Shape type reused to create the next temporary form in a continuous creation session.
508 // Form ids completed during the active creation session; only these are drawn while creation stays active.
510 // Last completed form id, selected when the creation session is disabled.
512
514
515 // ids
519
522void dt_masks_gui_init(struct dt_develop_t *dev);
523void dt_masks_gui_cleanup(struct dt_develop_t *dev);
527
528// Test wether the form, the border, the source or the pivot is selected
530{
531 return gui && (gui->form_selected || gui->border_selected || gui->source_selected || gui->pivot_selected);
532}
533
535{
536 return (gui && gui->node_selected) ? gui->node_selected_idx : -1;
537}
538
540{
541 return (gui && gui->handle_selected) ? gui->handle_hovered : -1;
542}
543
545{
546 return (gui && gui->handle_border_selected) ? gui->handle_border_hovered : -1;
547}
548
550{
551 return (gui) ? gui->seg_hovered : -1;
552}
553
555 const int index)
556{
557 if(IS_NULL_PTR(gui)) return TRUE;
558
559 const int selected_node = dt_masks_gui_selected_node_index(gui);
560 return selected_node < 0 || selected_node == index;
561}
562
563static inline float dt_masks_get_form_size_from_nodes(const GList *points)
564{
565 if(IS_NULL_PTR(points) || IS_NULL_PTR(points->data)) return 0.0f;
566
567 // Brush and polygon node payloads both start with `float node[2]`.
568 const float *first = (const float *)points->data;
569 float min_x = first[0];
570 float max_x = first[0];
571 float min_y = first[1];
572 float max_y = first[1];
573
574 for(const GList *point_node = points; point_node; point_node = g_list_next(point_node))
575 {
576 const float *node = (const float *)point_node->data;
577 if(IS_NULL_PTR(node)) continue;
578 min_x = fminf(min_x, node[0]);
579 max_x = fmaxf(max_x, node[0]);
580 min_y = fminf(min_y, node[1]);
581 max_y = fmaxf(max_y, node[1]);
582 }
583
584 return fmaxf(max_x - min_x, max_y - min_y);
585}
586
588{
589 const float hit_thresh = DT_GUI_MOUSE_EFFECT_RADIUS * 0.5f;
590 const float dx = gui->pos[0] - gui->last_hit_test_pos[0];
591 const float dy = gui->pos[1] - gui->last_hit_test_pos[1];
592 if(gui->last_hit_test_pos[0] < 0.0f || (dx * dx + dy * dy) > (hit_thresh * hit_thresh))
593 {
594 gui->last_hit_test_pos[0] = gui->pos[0];
595 gui->last_hit_test_pos[1] = gui->pos[1];
596 return TRUE;
597 }
598 return FALSE;
599}
600
601// High-level mask event dispatchers cache the current cursor in raw absolute coordinates.
602// Reuse that cache for current-cursor conversions instead of backtransforming `gui->pos` again.
603static inline void dt_masks_gui_cursor_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
604{
605 point[0] = gui->raw_pos[0];
606 point[1] = gui->raw_pos[1];
608}
609
610// Reuse the cached absolute output-image cursor and drag delta to derive a raw-normalized point.
611static inline void dt_masks_gui_delta_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
612{
613 point[0] = gui->pos[0] + gui->delta[0];
614 point[1] = gui->pos[1] + gui->delta[1];
616}
617
618static inline void dt_masks_gui_delta_to_image_abs(const dt_masks_form_gui_t *gui, float point[2])
619{
620 point[0] = gui->pos[0] + gui->delta[0];
621 point[1] = gui->pos[1] + gui->delta[1];
622}
623
624// Drag branches need the same "cursor + drag delta" converted back to raw space.
625// Keep that conversion in one place so all shapes use the same anchor semantics.
627 const float anchor[2], float *delta_x, float *delta_y)
628{
629 float point[2];
631 *delta_x = point[0] - anchor[0];
632 *delta_y = point[1] - anchor[1];
633}
634
635// Clone and spot forms share the same default presets, while regular drawn masks use their own.
636static inline gboolean dt_masks_form_uses_spot_defaults(const dt_masks_form_t *form)
637{
638 return (form->type & (DT_MASKS_CLONE | DT_MASKS_NON_CLONE)) != 0;
639}
640
641static inline gboolean dt_masks_form_is_clone(const dt_masks_form_t *form)
642{
643 return (form->type & DT_MASKS_CLONE) != 0;
644}
645
646static inline void dt_masks_reset_source(dt_masks_form_t *form)
647{
648 form->source[0] = 0.0f;
649 form->source[1] = 0.0f;
650}
651
652static inline void dt_masks_translate_source(dt_masks_form_t *form, const float delta_x, const float delta_y)
653{
654 form->source[0] += delta_x;
655 form->source[1] += delta_y;
656}
657
658static inline void dt_masks_translate_ctrl_node(float node[2], float ctrl1[2], float ctrl2[2],
659 const float delta_x, const float delta_y)
660{
661 node[0] += delta_x;
662 node[1] += delta_y;
663 ctrl1[0] += delta_x;
664 ctrl1[1] += delta_y;
665 ctrl2[0] += delta_x;
666 ctrl2[1] += delta_y;
667}
668
669static inline void dt_masks_set_ctrl_points(float ctrl1[2], float ctrl2[2], const float control_points[4])
670{
671 ctrl1[0] = control_points[0];
672 ctrl1[1] = control_points[1];
673 ctrl2[0] = control_points[2];
674 ctrl2[1] = control_points[3];
675}
676
677gboolean dt_masks_node_is_cusp(const dt_masks_form_gui_points_t *gpt, const int index);
679 struct dt_iop_module_t *module);
680
681// Brush and polygon nodes share the same node/control-point edit semantics.
682static inline gboolean dt_masks_toggle_bezier_node_type(struct dt_iop_module_t *module,
683 struct dt_masks_form_t *mask_form,
684 struct dt_masks_form_gui_t *mask_gui,
685 const int form_index,
686 const struct dt_masks_form_gui_points_t *gui_points,
687 const int node_index,
688 float node[2], float ctrl1[2], float ctrl2[2],
690{
691 if(IS_NULL_PTR(mask_form) || IS_NULL_PTR(mask_gui) || IS_NULL_PTR(gui_points) || IS_NULL_PTR(state) || node_index < 0) return FALSE;
692
693 if(dt_masks_node_is_cusp(gui_points, node_index))
694 {
696 if(mask_form->functions && mask_form->functions->init_ctrl_points)
697 mask_form->functions->init_ctrl_points(mask_form);
698 }
699 else
700 {
701 ctrl1[0] = ctrl2[0] = node[0];
702 ctrl1[1] = ctrl2[1] = node[1];
704 }
705
706 dt_masks_gui_form_create(mask_form, mask_gui, form_index, module);
707 return TRUE;
708}
709
710static inline gboolean dt_masks_reset_bezier_ctrl_points(struct dt_iop_module_t *module,
711 struct dt_masks_form_t *mask_form,
712 struct dt_masks_form_gui_t *mask_gui,
713 const int form_index,
714 const struct dt_masks_form_gui_points_t *gui_points,
715 const int node_index,
717{
718 if(IS_NULL_PTR(mask_form) || IS_NULL_PTR(mask_gui) || IS_NULL_PTR(gui_points) || IS_NULL_PTR(state) || node_index < 0) return FALSE;
719
720 if(*state != DT_MASKS_POINT_STATE_NORMAL && !dt_masks_node_is_cusp(gui_points, node_index))
721 {
723 if(mask_form->functions && mask_form->functions->init_ctrl_points)
724 mask_form->functions->init_ctrl_points(mask_form);
725 dt_masks_gui_form_create(mask_form, mask_gui, form_index, module);
726 }
727
728 return TRUE;
729}
730
731// Brush and polygon border handles both constrain the cursor to the node->handle axis.
732static inline void dt_masks_project_on_line(const float cursor[2], const float node[2],
733 const float handle[2], float point[2])
734{
735 const float dx_line = handle[0] - node[0];
736 const float dy_line = handle[1] - node[1];
737
738 if(fabsf(dx_line) < 1e-6f)
739 {
740 point[0] = node[0];
741 point[1] = cursor[1];
742 }
743 else
744 {
745 const float a = dy_line / dx_line;
746 const float b = node[1] - a * node[0];
747 const float denom = a * a + 1.0f;
748 const float xproj = (a * cursor[1] + cursor[0] - b * a) / denom;
749
750 point[0] = xproj;
751 point[1] = a * xproj + b;
752 }
753}
754
755// Border handles store normalized raw-space radii, but hit/drag code works in image space.
756// Convert both ends once here so all shapes derive border thickness the same way.
757static inline float dt_masks_border_from_projected_handle(dt_develop_t *dev, const float node[2],
758 const float projected_image_pos[2],
759 const float scale_ref)
760{
761 float projected_raw[2] = { projected_image_pos[0], projected_image_pos[1] };
762 float node_raw[2] = { node[0], node[1] };
763 dt_dev_coordinates_image_abs_to_raw_abs(dev, projected_raw, 1);
765
766 const float delta_x = projected_raw[0] - node_raw[0];
767 const float delta_y = projected_raw[1] - node_raw[1];
768 return sqrtf(delta_x * delta_x + delta_y * delta_y) / scale_ref;
769}
770
771// Circle, ellipse and gradient creation previews all follow the same drawing sequence:
772// optional save/restore, draw the shape, then draw the border preview if present.
773static inline void dt_masks_draw_preview_shape(cairo_t *cr, const float zoom_scale, const int num_points,
774 float *points, const int points_count,
775 float *border, const int border_count,
776 void (*const *draw_shape)(cairo_t *cr, const float *points,
777 const int points_count, const int nb,
778 const gboolean border,
779 const gboolean source),
780 const cairo_line_cap_t shape_cap,
781 const cairo_line_cap_t border_cap,
782 const gboolean save_restore,
783 const gboolean source)
784{
785 if(save_restore) cairo_save(cr);
786 if(points && points_count > 0)
787 dt_draw_shape_lines(DT_MASKS_NO_DASH, source, cr, num_points, FALSE, zoom_scale, points, points_count,
788 draw_shape, shape_cap);
789 if(border && border_count > 0)
790 dt_draw_shape_lines(DT_MASKS_DASH_STICK, source, cr, num_points, FALSE, zoom_scale, border, border_count,
791 draw_shape, border_cap);
792 if(save_restore) cairo_restore(cr);
793}
794
795// Shared scratch buffers for creation previews. Keeping them grouped makes the shape
796// preview helpers return a single value and centralizes cleanup.
806
813
815{
816 struct
817 {
818 float x;
819 float y;
821
822 struct
823 {
824 float x;
825 float y;
828
836
839
842int dt_masks_get_points_border(struct dt_develop_t *dev, dt_masks_form_t *form, float **points, int *points_count,
843 float **border, int *border_count, int source, dt_iop_module_t *module);
844
847 dt_masks_form_t *form,
848 int *width, int *height, int *posx, int *posy);
851 int *width, int *height, int *posx, int *posy);
853static inline int dt_masks_get_mask(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe,
854 const dt_dev_pixelpipe_iop_t *const piece,
855 dt_masks_form_t *const form,
856 float **buffer, int *width, int *height, int *posx, int *posy)
857{
858 return (form->functions && form->functions->get_mask)
859 ? form->functions->get_mask(module, pipe, piece, form, buffer, width, height, posx, posy)
860 : 1;
861}
862static inline int dt_masks_get_mask_roi(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe,
863 const dt_dev_pixelpipe_iop_t *const piece,
864 dt_masks_form_t *const form, const dt_iop_roi_t *roi, float *buffer)
865{
866 return (form->functions && form->functions->get_mask_roi)
867 ? form->functions->get_mask_roi(module, pipe, piece, form, roi, buffer)
868 : 1;
869}
870
872 const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form,
873 const dt_iop_roi_t *roi, float *buffer);
874
875// returns current masks version
876int dt_masks_version(void);
877
880void dt_masks_remove_node(struct dt_iop_module_t *module, dt_masks_form_t *form, int parentid,
881 dt_masks_form_gui_t *gui, int index, int node_index);
882
883// update masks from older versions
884int dt_masks_legacy_params(dt_develop_t *dev, void *params, const int old_version, const int new_version);
885/*
886 * TODO:
887 *
888 * int
889 * dt_masks_legacy_params(
890 * dt_develop_t *dev,
891 * const void *const old_params, const int old_version,
892 * void *new_params, const int new_version);
893 */
894
900void dt_masks_replace_current_forms(dt_develop_t *dev, GList *forms);
902GList *dt_masks_snapshot_current_forms(dt_develop_t *dev, gboolean reset_changed);
904dt_masks_form_t *dt_masks_get_from_id_ext(GList *forms, int id);
909 const struct dt_iop_module_t *mod_src);
912
914void dt_masks_read_masks_history(dt_develop_t *dev, const int32_t imgid);
916void dt_masks_write_masks_history_item(const int32_t imgid, const int num, dt_masks_form_t *form);
919
923void dt_masks_reset_form_gui(void);
926
927#define DEVELOP_MASKS_NB_SHAPES 5
928
937
959
960typedef gboolean (*dt_masks_shape_buttons_start_f)(GtkWidget *button, dt_iop_module_t *module,
961 dt_masks_type_t type, gpointer user_data);
963 gpointer user_data);
965 dt_masks_type_t type, gpointer user_data);
966
983
986
987int dt_masks_events_mouse_moved(struct dt_iop_module_t *module, double x, double y, double pressure,
988 int which);
989int dt_masks_events_button_released(struct dt_iop_module_t *module, double x, double y, int which,
990 uint32_t state);
991int dt_masks_events_button_pressed(struct dt_iop_module_t *module, double x, double y, double pressure,
992 int which, int type, uint32_t state);
993int dt_masks_events_mouse_scrolled(struct dt_iop_module_t *module, double x, double y, int up, uint32_t state, int delta_y);
994
995int dt_masks_events_key_pressed(struct dt_iop_module_t *module, GdkEventKey *event);
1007gboolean dt_masks_node_is_cusp(const dt_masks_form_gui_points_t *gpt, const int index);
1008
1019void dt_masks_draw_source(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const int nb,
1020 const float zoom_scale, struct dt_masks_gui_center_point_t *center_point, const shape_draw_function_t *draw_shape_func);
1021void dt_masks_draw_path_seg_by_seg(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const float *points,
1022 const int points_count, const int node_count, const float zoom_scale);
1023
1024void dt_masks_events_post_expose(struct dt_iop_module_t *module, cairo_t *cr, int32_t width, int32_t height,
1025 int32_t pointerx, int32_t pointery);
1028
1031 struct dt_iop_module_t *module);
1033 struct dt_iop_module_t *module, float posx, float posy);
1034
1045gboolean dt_masks_gui_remove(struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui, const int parentid);
1046
1057gboolean dt_masks_remove_or_delete(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id,
1058 dt_masks_form_gui_t *mask_gui, int form_id);
1059
1060
1061// Remove a mask
1063
1064
1067
1077 dt_masks_form_gui_t *gui);
1081
1085void dt_masks_iop_update(struct dt_iop_module_t *module);
1086void dt_masks_iop_combo_populate(GtkWidget *w, void *module);
1087void dt_masks_iop_use_same_as(struct dt_iop_module_t *module, struct dt_iop_module_t *src);
1089
1091int dt_masks_form_change_opacity(dt_masks_form_t *form, int parentid, int up, const int flow);
1092void dt_masks_form_move(dt_masks_form_t *grp, int formid, int up);
1093int dt_masks_form_duplicate(dt_develop_t *dev, int formid);
1094/* returns a duplicate tof form, including the formid */
1096/* duplicate the list of forms, replace item in the list with form with the same formid */
1097GList *dt_masks_dup_forms_deep(GList *forms, dt_masks_form_t *form);
1098
1100int dt_masks_point_in_form_exact(const float *pts, int num_pts, const float *points, int points_start, int points_count);
1101
1103void dt_masks_select_form(struct dt_iop_module_t *module, dt_masks_form_t *sel);
1104
1108void dt_masks_calculate_source_pos_origin(dt_masks_form_gui_t *gui, const float initial_xpos,
1109 const float initial_ypos, const float xpos, const float ypos, float *px,
1110 float *py, const int adding);
1111static inline void dt_masks_draw_source_preview(cairo_t *cr, const float zoom_scale, dt_masks_form_gui_t *gui,
1112 const float initial_xpos, const float initial_ypos,
1113 const float xpos, const float ypos, const int adding)
1114{
1115 float source_pos[2] = { 0.0f, 0.0f };
1116 dt_masks_calculate_source_pos_origin(gui, initial_xpos, initial_ypos, xpos, ypos,
1117 &source_pos[0], &source_pos[1], adding);
1118 dt_draw_cross(cr, zoom_scale, source_pos[0], source_pos[1]);
1119}
1130float dt_masks_rotate_with_anchor(dt_develop_t *dev, const float anchor[2], const float center[2], dt_masks_form_gui_t *gui);
1131
1134int dt_masks_group_index_from_formid(const dt_masks_form_t *group_form, int formid);
1136 const struct dt_masks_form_gui_t *gui);
1137
1139gboolean dt_masks_is_anything_selected(const dt_masks_form_gui_t *mask_gui);
1140
1142gboolean dt_masks_is_anything_hovered(const dt_masks_form_gui_t *mask_gui);
1143
1153 const struct dt_masks_form_gui_t *gui);
1155 dt_masks_interaction_t interaction);
1156gboolean dt_masks_form_get_gravity_center(const struct dt_masks_form_t *form, float center[2], float *area);
1158int dt_masks_center_view_on_form(struct dt_develop_t *dev, const struct dt_masks_form_t *form);
1160 dt_masks_interaction_t interaction,
1161 float value, dt_masks_increment_t increment, int flow,
1162 struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module);
1163
1176float dt_masks_get_set_conf_value(dt_masks_form_t *form, char *feature, float new_value, float v_min, float v_max,
1177 dt_masks_increment_t increment, const int flow);
1184float dt_masks_get_set_conf_value_with_toast(dt_masks_form_t *form, const char *feature, float amount,
1185 float v_min, float v_max, dt_masks_increment_t increment, int flow,
1186 const char *toast_fmt, float toast_scale);
1187
1193void dt_masks_duplicate_points(const dt_masks_form_t *base, dt_masks_form_t *dest, size_t node_size);
1194
1198float dt_masks_apply_increment(float current, float amount, dt_masks_increment_t increment, int flow);
1199
1203float dt_masks_apply_increment_precomputed(float current, float amount, float scale_amount, float offset_amount,
1204 dt_masks_increment_t increment);
1205
1207void dt_masks_extend_border(float *const mask, const int width, const int height, const int border);
1208void dt_masks_blur_9x9_coeff(float *coeffs, const float sigma);
1209void dt_masks_blur_9x9(float *const src, float *const out, const int width, const int height, const float sigma);
1210void dt_masks_calc_rawdetail_mask(float *const src, float *const out, float *const tmp, const int width,
1211 const int height, const dt_aligned_pixel_t wb);
1212void dt_masks_calc_detail_mask(float *const src, float *const out, float *const tmp, const int width, const int height, const float threshold, const gboolean detail);
1213
1214void dt_group_events_post_expose(cairo_t *cr, float zoom_scale, dt_masks_form_t *form,
1215 dt_masks_form_gui_t *gui);
1216
1218static inline gboolean _dt_masks_dynbuf_growto(dt_masks_dynbuf_t *a, size_t size)
1219{
1220 const size_t newsize = dt_round_size_sse(sizeof(float) * size) / sizeof(float);
1221 float *newbuf = dt_pixelpipe_cache_alloc_align_float_cache(newsize, 0);
1222 if (IS_NULL_PTR(newbuf))
1223 {
1224 // not much we can do here except emit an error message
1225 fprintf(stderr, "critical: out of memory for dynbuf '%s' with size request %" G_GSIZE_FORMAT "!\n", a->tag, size);
1226 return FALSE;
1227 }
1228 if (a->buffer)
1229 {
1230 memcpy(newbuf, a->buffer, a->size * sizeof(float));
1231 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] grows to size %lu (is %p, was %p)\n", a->tag,
1232 (unsigned long)a->size, newbuf, a->buffer);
1234 }
1235 a->size = newsize;
1236 a->buffer = newbuf;
1237 return TRUE;
1238}
1239
1240static inline dt_masks_dynbuf_t *dt_masks_dynbuf_init(size_t size, const char *tag)
1241{
1242 assert(size > 0);
1243 dt_masks_dynbuf_t *a = (dt_masks_dynbuf_t *)calloc(1, sizeof(dt_masks_dynbuf_t));
1244
1245 if(!IS_NULL_PTR(a))
1246 {
1247 g_strlcpy(a->tag, tag, sizeof(a->tag)); //only for debugging purposes
1248 a->pos = 0;
1250 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] with initial size %lu (is %p)\n", a->tag,
1251 (unsigned long)a->size, a->buffer);
1252 if(IS_NULL_PTR(a->buffer))
1253 {
1254 dt_free(a);
1255 }
1256 }
1257 return a;
1258}
1259
1260static inline void dt_masks_dynbuf_add_2(dt_masks_dynbuf_t *a, float value1, float value2)
1261{
1262 assert(!IS_NULL_PTR(a));
1263 assert(a->pos <= a->size);
1264 if(__builtin_expect(a->pos + 2 >= a->size, 0))
1265 {
1266 if (a->size == 0 || !_dt_masks_dynbuf_growto(a, 2 * (a->size+1)))
1267 return;
1268 }
1269 a->buffer[a->pos++] = value1;
1270 a->buffer[a->pos++] = value2;
1271}
1272
1273// Return a pointer to N floats past the current end of the dynbuf's contents, marking them as already in use.
1274// The caller should then fill in the reserved elements using the returned pointer.
1275static inline float *dt_masks_dynbuf_reserve_n(dt_masks_dynbuf_t *a, const int n)
1276{
1277 assert(!IS_NULL_PTR(a));
1278 assert(a->pos <= a->size);
1279 if(__builtin_expect(a->pos + n >= a->size, 0))
1280 {
1281 if(a->size == 0) return NULL;
1282 size_t newsize = a->size;
1283 while(a->pos + n >= newsize) newsize *= 2;
1284 if (!_dt_masks_dynbuf_growto(a, newsize))
1285 {
1286 return NULL;
1287 }
1288 }
1289 // get the current end of the (possibly reallocated) buffer, then mark the next N items as in-use
1290 float *reserved = a->buffer + a->pos;
1291 a->pos += n;
1292 return reserved;
1293}
1294
1295static inline void dt_masks_dynbuf_add_zeros(dt_masks_dynbuf_t *a, const int n)
1296{
1297 assert(!IS_NULL_PTR(a));
1298 assert(a->pos <= a->size);
1299 if(__builtin_expect(a->pos + n >= a->size, 0))
1300 {
1301 if(a->size == 0) return;
1302 size_t newsize = a->size;
1303 while(a->pos + n >= newsize) newsize *= 2;
1304 if (!_dt_masks_dynbuf_growto(a, newsize))
1305 {
1306 return;
1307 }
1308 }
1309 // now that we've ensured a sufficiently large buffer add N zeros to the end of the existing data
1310 memset(a->buffer + a->pos, 0, n * sizeof(float));
1311 a->pos += n;
1312}
1313
1314
1315static inline float dt_masks_dynbuf_get(dt_masks_dynbuf_t *a, int offset)
1316{
1317 assert(!IS_NULL_PTR(a));
1318 // offset: must be negative distance relative to end of buffer
1319 assert(offset < 0);
1320 assert((long)a->pos + offset >= 0);
1321 return (a->buffer[a->pos + offset]);
1322}
1323
1324static inline void dt_masks_dynbuf_set(dt_masks_dynbuf_t *a, int offset, float value)
1325{
1326 assert(!IS_NULL_PTR(a));
1327 // offset: must be negative distance relative to end of buffer
1328 assert(offset < 0);
1329 assert((long)a->pos + offset >= 0);
1330 a->buffer[a->pos + offset] = value;
1331}
1332
1334{
1335 assert(!IS_NULL_PTR(a));
1336 return a->buffer;
1337}
1338
1339static inline gboolean dt_masks_center_of_gravity_from_points(const float *points, const int points_count,
1340 float center[2], float *area)
1341{
1342 if(IS_NULL_PTR(points) || IS_NULL_PTR(center) || IS_NULL_PTR(area) || points_count <= 0)
1343 {
1344 if(center)
1345 {
1346 center[0] = 0.0f;
1347 center[1] = 0.0f;
1348 }
1349 if(!IS_NULL_PTR(area)) *area = 0.0f;
1350 return FALSE;
1351 }
1352
1353 double start = 0.;
1355
1356 // Points must be ordered sequentially along the polygon boundary.
1357 // Use the shoelace formula to compute area and centroid.
1358 if(points_count >= 3)
1359 {
1360 double area2 = 0.0;
1361 double cx = 0.0;
1362 double cy = 0.0;
1363
1364 for(int i = 0; i < points_count; i++)
1365 {
1366 const int j = (i + 1 < points_count) ? (i + 1) : 0;
1367 const double x0 = points[i * 2];
1368 const double y0 = points[i * 2 + 1];
1369 const double x1 = points[j * 2];
1370 const double y1 = points[j * 2 + 1];
1371
1372 const double cross = x0 * y1 - x1 * y0;
1373 area2 += cross;
1374 cx += (x0 + x1) * cross;
1375 cy += (y0 + y1) * cross;
1376 }
1377
1378 if(fabs(area2) > 1e-12)
1379 {
1380 const double inv = 1.0 / (3.0 * area2);
1381 center[0] = (float)(cx * inv);
1382 center[1] = (float)(cy * inv);
1383
1384 *area = (float)(0.5 * fabs(area2));
1385 return TRUE;
1386 }
1387 }
1388
1389 // Fallback to arithmetic mean for degenerate polygons or short lists.
1390 float sum_x = 0.0f;
1391 float sum_y = 0.0f;
1392 const float inv_count = 1.0f / (float)points_count;
1393 for(int i = 0; i < points_count; i++)
1394 {
1395 sum_x += points[i * 2] * inv_count;
1396 sum_y += points[i * 2 + 1] * inv_count;
1397 }
1398
1400 dt_print(DT_DEBUG_MASKS, "[masks] computing centroid took %0.04f sec\n",
1401 dt_get_wtime() - start);
1402
1403
1404 center[0] = sum_x;
1405 center[1] = sum_y;
1406 *area = 0.0f;
1407 return TRUE;
1408}
1409
1411{
1412 assert(!IS_NULL_PTR(a));
1413 return a->pos;
1414}
1415
1417{
1418 assert(!IS_NULL_PTR(a));
1419 a->pos = 0;
1420}
1421
1423{
1424 // take out data buffer and make dynamic buffer obsolete
1425 if(IS_NULL_PTR(a)) return NULL;
1426 float *r = a->buffer;
1427 a->buffer = NULL;
1428 a->pos = a->size = 0;
1429 return r;
1430}
1431
1433{
1434 if(IS_NULL_PTR(a)) return;
1435 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] freed (was %p)\n", a->tag,
1436 a->buffer);
1438 dt_free(a);
1439}
1440
1441static inline int dt_masks_roundup(int num, int mult)
1442{
1443 const int rem = num % mult;
1444
1445 return (rem == 0) ? num : num + mult - rem;
1446}
1447
1458gboolean dt_masks_point_is_within_radius(const float px, const float py,
1459 const float cx, const float cy,
1460 const float radius);
1461
1467typedef gboolean (*dt_masks_border_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_count,
1468 int node_index, float *handle_x, float *handle_y, void *user_data);
1474typedef void (*dt_masks_curve_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index,
1475 float *handle_x, float *handle_y, void *user_data);
1481typedef void (*dt_masks_node_position_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index,
1482 float *node_x, float *node_y, void *user_data);
1489typedef void (*dt_masks_distance_fn)(float pointer_x, float pointer_y, float cursor_radius,
1490 dt_masks_form_gui_t *mask_gui, int form_index, int node_count,
1491 int *inside, int *inside_border, int *near, int *inside_source, float *dist,
1492 void *user_data);
1496typedef void (*dt_masks_post_select_fn)(dt_masks_form_gui_t *mask_gui, int inside, int inside_border,
1497 int inside_source, void *user_data);
1498
1508 int form_index, int node_count_override,
1509 dt_masks_border_handle_fn border_handle_cb,
1510 dt_masks_curve_handle_fn curve_handle_cb,
1511 dt_masks_node_position_fn node_position_cb,
1512 dt_masks_distance_fn distance_cb,
1513 dt_masks_post_select_fn post_select_cb,
1514 void *user_data);
1515
1518void apply_operation(struct dt_masks_form_group_t *pt, const dt_masks_state_t apply_state);
1519
1522#define menu_item_set_fake_accel(menu_item, keyval, mods) \
1523 \
1524{ \
1525 GtkWidget *child = gtk_bin_get_child(GTK_BIN(menu_item)); \
1526 if(GTK_IS_ACCEL_LABEL(child)) \
1527 gtk_accel_label_set_accel(GTK_ACCEL_LABEL(child), keyval, mods); \
1528}
1529
1530void _masks_gui_delete_node_callback(GtkWidget *menu, gpointer user_data);
1531
1533
1535 const float pzx, const float pzy);
1536
1539int dt_masks_gui_confirm_delete_form_dialog(const char *form_name);
1540
1541#ifdef __cplusplus
1542}
1543#endif
1544
1545// clang-format off
1546// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1547// vim: shiftwidth=2 expandtab tabstop=2 cindent
1548// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1549// clang-format on
static double dist(double x1, double y1, double x2, double y2)
Definition ashift_lsd.c:250
static double * inv
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const float threshold
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int type
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_PERF
Definition darktable.h:719
@ DT_DEBUG_MASKS
Definition darktable.h:727
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
static size_t dt_round_size_sse(const size_t size)
Definition darktable.h:403
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
static double dt_get_wtime(void)
Definition darktable.h:914
#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:281
void dt_dev_coordinates_raw_norm_to_raw_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1109
int dt_dev_coordinates_image_abs_to_raw_abs(dt_develop_t *dev, float *points, size_t points_count)
Definition develop.c:1530
void dt_dev_coordinates_raw_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1092
void dt_dev_coordinates_image_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1138
static void dt_draw_cross(cairo_t *cr, const float zoom_scale, const float x, const float y)
Definition draw.h:893
@ DT_MASKS_DASH_STICK
Definition draw.h:94
@ DT_MASKS_NO_DASH
Definition draw.h:93
static void dt_draw_shape_lines(const dt_draw_dash_type_t dash_type, const gboolean source, cairo_t *cr, const int nb, const gboolean selected, const float zoom_scale, const float *points, const int points_count, const shape_draw_function_t *draw_shape_func, const cairo_line_cap_t line_cap)
Draw the lines of a mask shape.
Definition draw.h:734
void(* shape_draw_function_t)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source)
Definition draw.h:719
#define DT_GUI_MOUSE_EFFECT_RADIUS
Definition gtk.h:70
static const float x
GList * dt_masks_dup_forms_deep(GList *forms, dt_masks_form_t *form)
Duplicate the list of forms, replacing a single item by formid match.
GdkModifierType dt_masks_get_accel_mods(dt_masks_interaction_t interaction)
static void dt_masks_gui_delta_to_image_abs(const dt_masks_form_gui_t *gui, float point[2])
Definition masks.h:618
gboolean dt_masks_remove_or_delete(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id, dt_masks_form_gui_t *mask_gui, int form_id)
If the form to remove is used once, ask to the user if he wants to delete it from the list or just re...
void apply_operation(struct dt_masks_form_group_t *pt, const dt_masks_state_t apply_state)
Apply a mask state operation on a group entry.
int dt_masks_group_render_roi(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float *buffer)
Definition group.c:663
void dt_masks_gui_form_remove(dt_masks_form_t *form, dt_masks_form_gui_t *gui, int index)
static int dt_masks_gui_selected_segment_index(const dt_masks_form_gui_t *gui)
Definition masks.h:549
void dt_masks_blur_9x9(float *const src, float *const out, const int width, const int height, const float sigma)
void dt_masks_events_post_expose(struct dt_iop_module_t *module, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
dt_masks_type_t(* dt_masks_shape_buttons_type_f)(dt_iop_module_t *module, dt_masks_type_t type, gpointer user_data)
Definition masks.h:962
gboolean(* dt_masks_shape_buttons_start_f)(GtkWidget *button, dt_iop_module_t *module, dt_masks_type_t type, gpointer user_data)
Definition masks.h:960
void(* dt_masks_distance_fn)(float pointer_x, float pointer_y, float cursor_radius, dt_masks_form_gui_t *mask_gui, int form_index, int node_count, int *inside, int *inside_border, int *near, int *inside_source, float *dist, void *user_data)
Shape-specific callback for inside/border/segment hit testing.
Definition masks.h:1489
static int dt_masks_gui_selected_node_index(const dt_masks_form_gui_t *gui)
Definition masks.h:534
void dt_masks_gui_set_dragging(dt_masks_form_gui_t *gui)
void dt_masks_iop_update(struct dt_iop_module_t *module)
Definition blend_gui.c:3743
static int dt_masks_gui_selected_handle_index(const dt_masks_form_gui_t *gui)
Definition masks.h:539
void dt_masks_calculate_source_pos_origin(dt_masks_form_gui_t *gui, const float initial_xpos, const float initial_ypos, const float xpos, const float ypos, float *px, float *py, const int adding)
Compute preview-space source position for drawing the clone indicator.
int dt_masks_legacy_params(dt_develop_t *dev, void *params, const int old_version, const int new_version)
static float * dt_masks_dynbuf_buffer(dt_masks_dynbuf_t *a)
Definition masks.h:1333
dt_masks_form_group_t * dt_masks_group_add_form(dt_masks_form_t *grp, dt_masks_form_t *form)
void dt_masks_remove_form(dt_develop_t *dev, dt_masks_form_t *form)
dt_masks_shape_button_index_t
Definition masks.h:930
@ DT_MASKS_SHAPE_INDEX_BRUSH
Definition masks.h:935
@ DT_MASKS_SHAPE_INDEX_ELLIPSE
Definition masks.h:933
@ DT_MASKS_SHAPE_INDEX_CIRCLE
Definition masks.h:934
@ DT_MASKS_SHAPE_INDEX_GRADIENT
Definition masks.h:931
@ DT_MASKS_SHAPE_INDEX_POLYGON
Definition masks.h:932
static gboolean dt_masks_toggle_bezier_node_type(struct dt_iop_module_t *module, struct dt_masks_form_t *mask_form, struct dt_masks_form_gui_t *mask_gui, const int form_index, const struct dt_masks_form_gui_points_t *gui_points, const int node_index, float node[2], float ctrl1[2], float ctrl2[2], dt_masks_points_states_t *state)
Definition masks.h:682
void dt_masks_gui_form_create(dt_masks_form_t *form, dt_masks_form_gui_t *gui, int index, struct dt_iop_module_t *module)
void dt_masks_change_form_gui(dt_masks_form_t *newform)
int dt_masks_events_key_pressed(struct dt_iop_module_t *module, GdkEventKey *event)
static void dt_masks_dynbuf_add_2(dt_masks_dynbuf_t *a, float value1, float value2)
Definition masks.h:1260
void dt_masks_creation_mode_quit(dt_masks_form_gui_t *gui)
Exit mask creation mode, restoring cursor visibility and resetting GUI state.
dt_masks_edit_mode_t
Definition masks.h:200
@ DT_MASKS_EDIT_RESTRICTED
Definition masks.h:203
@ DT_MASKS_EDIT_OFF
Definition masks.h:201
@ DT_MASKS_EDIT_FULL
Definition masks.h:202
gboolean dt_masks_gui_remove(struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui, const int parentid)
remove a mask shape or node form from the GUI. This function is used with a popupmenu "Delete" action...
gboolean dt_masks_node_is_cusp(const dt_masks_form_gui_points_t *gpt, const int index)
returns wether a node is a corner or not. A node is a corner if its 2 control handles are at the same...
static void dt_masks_draw_source_preview(cairo_t *cr, const float zoom_scale, dt_masks_form_gui_t *gui, const float initial_xpos, const float initial_ypos, const float xpos, const float ypos, const int adding)
Definition masks.h:1111
struct dt_iop_module_t * dt_masks_get_mask_manager(struct dt_develop_t *dev)
int dt_masks_form_change_opacity(dt_masks_form_t *form, int parentid, int up, const int flow)
int dt_masks_point_in_form_exact(const float *pts, int num_pts, const float *points, int points_start, int points_count)
Check whether any 2D point in pts[] lies inside the form points[].
void dt_masks_free_form(dt_masks_form_t *form)
void dt_masks_gui_reset_dragging(dt_masks_form_gui_t *gui)
static dt_masks_dynbuf_t * dt_masks_dynbuf_init(size_t size, const char *tag)
Definition masks.h:1240
static void dt_masks_translate_source(dt_masks_form_t *form, const float delta_x, const float delta_y)
Definition masks.h:652
void dt_masks_iop_use_same_as(struct dt_iop_module_t *module, struct dt_iop_module_t *src)
void dt_masks_reset_form_gui(void)
void dt_masks_read_masks_history(dt_develop_t *dev, const int32_t imgid)
void dt_masks_gui_init(struct dt_develop_t *dev)
void(* dt_masks_post_select_fn)(dt_masks_form_gui_t *mask_gui, int inside, int inside_border, int inside_source, void *user_data)
Optional hook to customize selection flags after inside/border/source resolution.
Definition masks.h:1496
int dt_masks_events_button_released(struct dt_iop_module_t *module, double x, double y, int which, uint32_t state)
int dt_masks_events_mouse_moved(struct dt_iop_module_t *module, double x, double y, double pressure, int which)
int dt_masks_events_mouse_scrolled(struct dt_iop_module_t *module, double x, double y, int up, uint32_t state, int delta_y)
static float dt_masks_dynbuf_get(dt_masks_dynbuf_t *a, int offset)
Definition masks.h:1315
static void dt_masks_translate_ctrl_node(float node[2], float ctrl1[2], float ctrl2[2], const float delta_x, const float delta_y)
Definition masks.h:658
gboolean dt_masks_is_anything_selected(const dt_masks_form_gui_t *mask_gui)
const dt_masks_functions_t dt_masks_functions_group
Definition group.c:745
dt_masks_form_t * dt_masks_dup_masks_form(const dt_masks_form_t *form)
Deep-copy a mask form, including its points list.
void dt_masks_duplicate_points(const dt_masks_form_t *base, dt_masks_form_t *dest, size_t node_size)
Duplicate a points list for a mask using a fixed node size.
dt_masks_state_t
Definition masks.h:166
@ DT_MASKS_STATE_DIFFERENCE
Definition masks.h:173
@ DT_MASKS_STATE_INVERSE
Definition masks.h:170
@ DT_MASKS_STATE_INTERSECTION
Definition masks.h:172
@ DT_MASKS_STATE_IS_COMBINE_OP
Definition masks.h:177
@ DT_MASKS_STATE_SHOW
Definition masks.h:169
@ DT_MASKS_STATE_EXCLUSION
Definition masks.h:174
@ DT_MASKS_STATE_NONE
Definition masks.h:167
@ DT_MASKS_STATE_UNION
Definition masks.h:171
@ DT_MASKS_STATE_USE
Definition masks.h:168
@ DT_MASKS_STATE_NOOP
Definition masks.h:175
static float dt_masks_get_form_size_from_nodes(const GList *points)
Definition masks.h:563
void dt_masks_write_masks_history_item(const int32_t imgid, const int num, dt_masks_form_t *form)
gboolean dt_masks_gui_form_create_throttled(dt_masks_form_t *form, dt_masks_form_gui_t *gui, int index, struct dt_iop_module_t *module, float posx, float posy)
static float * dt_masks_dynbuf_reserve_n(dt_masks_dynbuf_t *a, const int n)
Definition masks.h:1275
void dt_masks_gui_form_save_creation(dt_develop_t *dev, struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui)
Save the form creation right after a shape has been finished drawing.
void dt_masks_shape_buttons_deactivate_all(GtkWidget *active_button)
Definition masks_gui.c:86
void dt_masks_select_form(struct dt_iop_module_t *module, dt_masks_form_t *sel)
Select or clear the current mask form, notifying the owning module if needed.
void dt_masks_calc_detail_mask(float *const src, float *const out, float *const tmp, const int width, const int height, const float threshold, const gboolean detail)
static int dt_masks_gui_selected_handle_border_index(const dt_masks_form_gui_t *gui)
Definition masks.h:544
GList * dt_masks_snapshot_current_forms(dt_develop_t *dev, gboolean reset_changed)
GtkWidget * dt_masks_shape_buttons_create(const dt_masks_shape_buttons_config_t *config)
Build a synchronized toolbar for creating masks shapes.
Definition masks_gui.c:180
float dt_masks_get_set_conf_value(dt_masks_form_t *form, char *feature, float new_value, float v_min, float v_max, dt_masks_increment_t increment, const int flow)
Change a numerical property of a mask shape, either by in/de-crementing the current value or setting ...
float dt_masks_form_get_interaction_value(dt_masks_form_group_t *form_group, dt_masks_interaction_t interaction)
void dt_masks_clear_form_gui(dt_develop_t *dev)
gboolean dt_masks_form_exit_creation(dt_iop_module_t *module, dt_masks_form_gui_t *gui)
void dt_masks_draw_source(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const int nb, const float zoom_scale, struct dt_masks_gui_center_point_t *center_point, const shape_draw_function_t *draw_shape_func)
Draw the source for a correction mask.
static gboolean _dt_masks_dynbuf_growto(dt_masks_dynbuf_t *a, size_t size)
Definition masks.h:1218
void dt_masks_blur_9x9_coeff(float *coeffs, const float sigma)
Definition detail.c:159
gboolean(* dt_masks_border_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_count, int node_index, float *handle_x, float *handle_y, void *user_data)
Shape-specific callback to fetch a node's border handle in GUI space.
Definition masks.h:1467
dt_masks_type_t
Definition masks.h:129
@ DT_MASKS_NON_CLONE
Definition masks.h:138
@ DT_MASKS_ALL
Definition masks.h:140
@ DT_MASKS_POLYGON
Definition masks.h:132
@ DT_MASKS_BRUSH
Definition masks.h:137
@ DT_MASKS_IS_PATH_SHAPE
Definition masks.h:148
@ DT_MASKS_IS_OPEN_SHAPE
Definition masks.h:144
@ DT_MASKS_ELLIPSE
Definition masks.h:136
@ DT_MASKS_CLONE
Definition masks.h:134
@ DT_MASKS_GRADIENT
Definition masks.h:135
@ DT_MASKS_NONE
Definition masks.h:130
@ DT_MASKS_CIRCLE
Definition masks.h:131
@ DT_MASKS_GROUP
Definition masks.h:133
@ DT_MASKS_IS_PRIMITIVE_SHAPE
Definition masks.h:149
@ DT_MASKS_IS_CLOSED_SHAPE
Definition masks.h:143
@ DT_MASKS_IS_RETOUCHE
Definition masks.h:146
dt_masks_interaction_t
Definition masks.h:302
@ DT_MASKS_INTERACTION_OPACITY
Definition masks.h:306
@ DT_MASKS_INTERACTION_HARDNESS
Definition masks.h:305
@ DT_MASKS_INTERACTION_SIZE
Definition masks.h:304
@ DT_MASKS_INTERACTION_LAST
Definition masks.h:307
@ DT_MASKS_INTERACTION_UNDEF
Definition masks.h:303
int dt_masks_group_index_from_formid(const dt_masks_form_t *group_form, int formid)
void dt_masks_replace_current_forms(dt_develop_t *dev, GList *forms)
void _masks_gui_delete_node_callback(GtkWidget *menu, gpointer user_data)
Definition masks_gui.c:488
static void dt_masks_gui_cursor_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
Definition masks.h:603
int dt_masks_center_view_on_form(struct dt_develop_t *dev, const struct dt_masks_form_t *form)
int dt_masks_version(void)
dt_masks_form_group_t * dt_masks_form_get_selected_group(const struct dt_masks_form_t *form, const struct dt_masks_form_gui_t *gui)
static float dt_masks_border_from_projected_handle(dt_develop_t *dev, const float node[2], const float projected_image_pos[2], const float scale_ref)
Definition masks.h:757
static gboolean dt_masks_center_of_gravity_from_points(const float *points, const int points_count, float center[2], float *area)
Definition masks.h:1339
dt_masks_ellipse_flags_t
Definition masks.h:217
@ DT_MASKS_ELLIPSE_PROPORTIONAL
Definition masks.h:219
@ DT_MASKS_ELLIPSE_EQUIDISTANT
Definition masks.h:218
int dt_masks_events_mouse_leave(struct dt_iop_module_t *module)
void(* dt_masks_shape_buttons_notify_f)(GtkWidget *button, dt_iop_module_t *module, dt_masks_type_t type, gpointer user_data)
Definition masks.h:964
static size_t dt_masks_dynbuf_position(dt_masks_dynbuf_t *a)
Definition masks.h:1410
gboolean dt_masks_gui_is_dragging(const dt_masks_form_gui_t *gui)
void dt_masks_calc_rawdetail_mask(float *const src, float *const out, float *const tmp, const int width, const int height, const dt_aligned_pixel_t wb)
gboolean dt_masks_point_is_within_radius(const float px, const float py, const float cx, const float cy, const float radius)
Check if a point (px,py) is inside a radius from a center point (cx,cy)
static void dt_masks_preview_buffers_cleanup(dt_masks_preview_buffers_t *buffers)
Definition masks.h:807
dt_masks_source_pos_type_t
Definition masks.h:223
@ DT_MASKS_SOURCE_POS_RELATIVE_TEMP
Definition masks.h:225
@ DT_MASKS_SOURCE_POS_RELATIVE
Definition masks.h:224
@ DT_MASKS_SOURCE_POS_ABSOLUTE
Definition masks.h:226
static gboolean dt_masks_gui_was_anything_selected(const dt_masks_form_gui_t *gui)
Definition masks.h:529
int dt_masks_gui_confirm_delete_form_dialog(const char *form_name)
Definition masks_gui.c:439
const dt_masks_functions_t dt_masks_functions_polygon
Definition polygon.c:3643
static gboolean dt_masks_gui_change_affects_selected_node_or_all(const dt_masks_form_gui_t *gui, const int index)
Definition masks.h:554
void dt_masks_cleanup_unused(dt_develop_t *dev)
Cleanup unused masks and refresh the current forms snapshot.
dt_masks_event_t
Definition masks.h:156
@ DT_MASKS_EVENT_NONE
Definition masks.h:157
@ DT_MASKS_EVENT_UPDATE
Definition masks.h:160
@ DT_MASKS_EVENT_RESET
Definition masks.h:163
@ DT_MASKS_EVENT_ADD
Definition masks.h:158
@ DT_MASKS_EVENT_DELETE
Definition masks.h:161
@ DT_MASKS_EVENT_REMOVE
Definition masks.h:159
@ DT_MASKS_EVENT_CHANGE
Definition masks.h:162
void dt_masks_group_ungroup(dt_masks_form_t *dest_grp, dt_masks_form_t *grp)
dt_masks_form_t * dt_masks_create(dt_masks_type_t type)
static gboolean dt_masks_gui_should_hit_test(dt_masks_form_gui_t *gui)
Definition masks.h:587
int dt_masks_events_button_pressed(struct dt_iop_module_t *module, double x, double y, double pressure, int which, int type, uint32_t state)
static void dt_masks_gui_delta_from_raw_anchor(dt_develop_t *dev, const dt_masks_form_gui_t *gui, const float anchor[2], float *delta_x, float *delta_y)
Definition masks.h:626
float dt_masks_apply_increment(float current, float amount, dt_masks_increment_t increment, int flow)
Apply a scroll increment to a scalar value.
static gboolean dt_masks_form_is_clone(const dt_masks_form_t *form)
Definition masks.h:641
float dt_masks_get_set_conf_value_with_toast(dt_masks_form_t *form, const char *feature, float amount, float v_min, float v_max, dt_masks_increment_t increment, int flow, const char *toast_fmt, float toast_scale)
Update a mask configuration value and emit a toast message.
int dt_masks_events_mouse_enter(struct dt_iop_module_t *module)
float dt_masks_rotate_with_anchor(dt_develop_t *dev, const float anchor[2], const float center[2], dt_masks_form_gui_t *gui)
Rotate a mask shape around its center. WARNING: gui->delta will be updated with the new position afte...
dt_masks_shape_buttons_flags_t
Definition masks.h:939
@ DT_MASKS_SHAPE_BUTTONS_GRADIENT
Definition masks.h:951
@ DT_MASKS_SHAPE_BUTTONS_NONE
Definition masks.h:941
@ DT_MASKS_SHAPE_BUTTONS_CIRCLE
Definition masks.h:943
@ DT_MASKS_SHAPE_BUTTONS_BRUSH
Definition masks.h:949
@ DT_MASKS_SHAPE_BUTTONS_ALL
Definition masks.h:953
@ DT_MASKS_SHAPE_BUTTONS_ELLIPSE
Definition masks.h:945
@ DT_MASKS_SHAPE_BUTTONS_POLYGON
Definition masks.h:947
float dt_masks_apply_increment_precomputed(float current, float amount, float scale_amount, float offset_amount, dt_masks_increment_t increment)
Apply a scroll increment using precomputed scale/offset factors.
static void dt_masks_dynbuf_add_zeros(dt_masks_dynbuf_t *a, const int n)
Definition masks.h:1295
gboolean dt_masks_creation_mode_enter(dt_iop_module_t *module, const dt_masks_type_t type)
Enter mask creation mode for a given shape type.
void dt_masks_form_move(dt_masks_form_t *grp, int formid, int up)
dt_masks_increment_t
Definition masks.h:193
@ DT_MASKS_INCREMENT_SCALE
Definition masks.h:195
@ DT_MASKS_INCREMENT_OFFSET
Definition masks.h:196
@ DT_MASKS_INCREMENT_ABSOLUTE
Definition masks.h:194
dt_masks_pressure_sensitivity_t
Definition masks.h:207
@ DT_MASKS_PRESSURE_OPACITY_REL
Definition masks.h:211
@ DT_MASKS_PRESSURE_OPACITY_ABS
Definition masks.h:212
@ DT_MASKS_PRESSURE_BRUSHSIZE_REL
Definition masks.h:213
@ DT_MASKS_PRESSURE_HARDNESS_REL
Definition masks.h:209
@ DT_MASKS_PRESSURE_OFF
Definition masks.h:208
@ DT_MASKS_PRESSURE_HARDNESS_ABS
Definition masks.h:210
int dt_masks_get_points_border(struct dt_develop_t *dev, dt_masks_form_t *form, float **points, int *points_count, float **border, int *border_count, int source, dt_iop_module_t *module)
float dt_masks_form_set_interaction_value(dt_masks_form_group_t *form_group, dt_masks_interaction_t interaction, float value, dt_masks_increment_t increment, int flow, struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module)
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
const dt_masks_functions_t dt_masks_functions_ellipse
Definition ellipse.c:1692
const dt_masks_functions_t dt_masks_functions_circle
Definition circle.c:1129
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
dt_masks_points_states_t
Definition masks.h:181
@ DT_MASKS_POINT_STATE_NORMAL
Definition masks.h:182
@ DT_MASKS_POINT_STATE_USER
Definition masks.h:183
void dt_masks_append_form(dt_develop_t *dev, dt_masks_form_t *form)
void dt_masks_soft_reset_form_gui(dt_masks_form_gui_t *gui)
dt_masks_form_group_t * dt_masks_form_get_selected_group_live(const struct dt_masks_form_t *form, const struct dt_masks_form_gui_t *gui)
Return the currently selected group entry, resolving to the live form group when the GUI is operating...
void dt_masks_set_source_pos_initial_value(dt_masks_form_gui_t *gui, dt_masks_form_t *form)
Initialize the clone source position based on current GUI state.
dt_masks_edit_mode_t dt_masks_get_edit_mode(struct dt_iop_module_t *module)
void dt_masks_form_delete(struct dt_iop_module_t *module, dt_masks_form_t *grp, dt_masks_form_t *form)
void dt_masks_iop_value_changed_callback(GtkWidget *widget, struct dt_iop_module_t *module)
static int dt_masks_get_mask(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, dt_masks_form_t *const form, float **buffer, int *width, int *height, int *posx, int *posy)
Definition masks.h:853
GtkWidget * dt_masks_create_menu(dt_masks_form_gui_t *gui, dt_masks_form_t *form, const dt_masks_form_group_t *fpt, const float pzx, const float pzy)
Definition masks_gui.c:603
void dt_masks_gui_cleanup(struct dt_develop_t *dev)
void dt_masks_init_form_gui(dt_masks_form_gui_t *gui)
static int dt_masks_get_mask_roi(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, dt_masks_form_t *const form, const dt_iop_roi_t *roi, float *buffer)
Definition masks.h:862
static void dt_masks_project_on_line(const float cursor[2], const float node[2], const float handle[2], float point[2])
Definition masks.h:732
dt_masks_gradient_states_t
Definition masks.h:187
@ DT_MASKS_GRADIENT_STATE_SIGMOIDAL
Definition masks.h:189
@ DT_MASKS_GRADIENT_STATE_LINEAR
Definition masks.h:188
void dt_masks_reset_show_masks_icons(void)
void dt_masks_extend_border(float *const mask, const int width, const int height, const int border)
void dt_masks_gui_form_test_create(dt_masks_form_t *form, dt_masks_form_gui_t *gui, struct dt_iop_module_t *module)
static int dt_masks_roundup(int num, int mult)
Definition masks.h:1441
const dt_masks_functions_t dt_masks_functions_brush
static float * dt_masks_dynbuf_harvest(dt_masks_dynbuf_t *a)
Definition masks.h:1422
void(* dt_masks_node_position_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index, float *node_x, float *node_y, void *user_data)
Shape-specific callback to fetch a node's position in GUI space.
Definition masks.h:1481
gboolean dt_masks_is_anything_hovered(const dt_masks_form_gui_t *mask_gui)
static void dt_masks_draw_preview_shape(cairo_t *cr, const float zoom_scale, const int num_points, float *points, const int points_count, float *border, const int border_count, void(*const *draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source), const cairo_line_cap_t shape_cap, const cairo_line_cap_t border_cap, const gboolean save_restore, const gboolean source)
Definition masks.h:773
int dt_masks_find_closest_handle_common(dt_masks_form_t *mask_form, dt_masks_form_gui_t *mask_gui, int form_index, int node_count_override, dt_masks_border_handle_fn border_handle_cb, dt_masks_curve_handle_fn curve_handle_cb, dt_masks_node_position_fn node_position_cb, dt_masks_distance_fn distance_cb, dt_masks_post_select_fn post_select_cb, void *user_data)
Shared selection logic for node/handle/segment hit testing.
int dt_masks_get_source_area(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
void dt_masks_group_update_name(dt_iop_module_t *module)
dt_masks_form_t * dt_masks_get_visible_form(const struct dt_develop_t *dev)
void dt_masks_remove_node(struct dt_iop_module_t *module, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index, int node_index)
uint64_t dt_masks_group_get_hash(uint64_t hash, dt_masks_form_t *form)
void dt_masks_set_edit_mode(struct dt_iop_module_t *module, dt_masks_edit_mode_t value)
void dt_group_events_post_expose(cairo_t *cr, float zoom_scale, dt_masks_form_t *form, dt_masks_form_gui_t *gui)
Definition group.c:138
void(* dt_masks_curve_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index, float *handle_x, float *handle_y, void *user_data)
Shape-specific callback to fetch a node's curve handle in GUI space.
Definition masks.h:1474
int dt_masks_get_area(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
static void dt_masks_dynbuf_set(dt_masks_dynbuf_t *a, int offset, float value)
Definition masks.h:1324
dt_masks_form_group_t * dt_masks_form_group_from_parentid(int parentid, int formid)
Return the group entry for a (parent, form) pair.
dt_masks_form_t * dt_masks_create_ext(dt_masks_type_t type)
static gboolean dt_masks_reset_bezier_ctrl_points(struct dt_iop_module_t *module, struct dt_masks_form_t *mask_form, struct dt_masks_form_gui_t *mask_gui, const int form_index, const struct dt_masks_form_gui_points_t *gui_points, const int node_index, dt_masks_points_states_t *state)
Definition masks.h:710
int dt_masks_form_duplicate(dt_develop_t *dev, int formid)
void dt_masks_draw_path_seg_by_seg(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const float *points, const int points_count, const int node_count, const float zoom_scale)
static void dt_masks_gui_delta_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
Definition masks.h:611
void dt_masks_set_source_pos_initial_state(dt_masks_form_gui_t *gui, const uint32_t state)
Decide initial source positioning mode for clone masks.
static gboolean dt_masks_form_uses_spot_defaults(const dt_masks_form_t *form)
Definition masks.h:636
const dt_masks_functions_t dt_masks_functions_gradient
Definition gradient.c:1516
static void dt_masks_dynbuf_reset(dt_masks_dynbuf_t *a)
Definition masks.h:1416
void dt_masks_iop_combo_populate(GtkWidget *w, void *module)
void dt_masks_form_update_gravity_center(struct dt_masks_form_t *form)
void dt_masks_set_visible_form(struct dt_develop_t *dev, dt_masks_form_t *form)
static void dt_masks_dynbuf_free(dt_masks_dynbuf_t *a)
Definition masks.h:1432
static void dt_masks_reset_source(dt_masks_form_t *form)
Definition masks.h:646
static void dt_masks_set_ctrl_points(float ctrl1[2], float ctrl2[2], const float control_points[4])
Definition masks.h:669
gboolean dt_masks_form_get_gravity_center(const struct dt_masks_form_t *form, float center[2], float *area)
int dt_masks_copy_used_forms_for_module(dt_develop_t *dev_dest, dt_develop_t *dev_src, const struct dt_iop_module_t *mod_src)
size_t size
Definition mipmap_cache.c:3
float dt_aligned_pixel_t[4]
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
const float sigma
const float r
unsigned __int64 uint64_t
Definition strptime.c:75
int32_t unmuted
Definition darktable.h:760
struct dt_develop_t * dev
Definition imageop.h:296
Region of interest passed through the pixelpipe.
Definition imageop.h:72
dt_masks_gradient_states_t state
Definition masks.h:277
char tag[128]
Definition masks.h:419
float * buffer
Definition masks.h:418
gboolean rebuild_pending
Definition masks.h:498
gboolean node_selected
Definition masks.h:470
gboolean handle_border_selected
Definition masks.h:473
double last_rebuild_ts
Definition masks.h:496
gboolean border_toggling
Definition masks.h:488
dt_masks_dynbuf_t * guipoints_payload
Definition masks.h:435
gboolean source_selected
Definition masks.h:478
int handle_border_dragging
Definition masks.h:493
dt_masks_type_t creation_type
Definition masks.h:507
int creation_last_formid
Definition masks.h:511
int handle_border_hovered
Definition masks.h:468
gboolean source_dragging
Definition masks.h:486
dt_masks_edit_mode_t edit_mode
Definition masks.h:463
dt_iop_module_t * creation_module
Definition masks.h:505
gboolean creation_closing_form
Definition masks.h:504
uint64_t pipe_hash
Definition masks.h:517
GList * creation_formids
Definition masks.h:509
dt_masks_pressure_sensitivity_t pressure_sensitivity
Definition masks.h:513
gboolean seg_selected
Definition masks.h:472
gboolean form_dragging
Definition masks.h:485
gboolean gradient_toggling
Definition masks.h:489
gboolean creation
Definition masks.h:503
float pos_source[2]
Definition masks.h:461
dt_masks_type_t type
Definition masks.h:428
dt_masks_form_t * form_visible
Definition masks.h:430
gboolean form_selected
Definition masks.h:476
gboolean handle_selected
Definition masks.h:471
gboolean form_rotating
Definition masks.h:487
dt_masks_dynbuf_t * guipoints
Definition masks.h:435
float rel_pos[2]
Definition masks.h:447
gboolean border_selected
Definition masks.h:477
float last_rebuild_pos[2]
Definition masks.h:497
gboolean pivot_selected
Definition masks.h:479
float raw_pos[2]
Definition masks.h:451
float last_hit_test_pos[2]
Definition masks.h:501
float delta[2]
Definition masks.h:455
const dt_masks_functions_t * functions
Definition masks.h:379
dt_masks_type_t type
Definition masks.h:378
float source[2]
Definition masks.h:385
char name[128]
Definition masks.h:396
GList * points
Definition masks.h:377
float gravity_center[2]
Definition masks.h:389
gboolean uses_bezier_points_layout
Definition masks.h:381
float(* get_interaction_value)(const struct dt_masks_form_t *form, dt_masks_interaction_t interaction)
Definition masks.h:344
gboolean(* get_gravity_center)(const struct dt_masks_form_t *form, float center[2], float *area)
Definition masks.h:343
int(* button_pressed)(struct dt_iop_module_t *module, double x, double y, double pressure, int which, int type, uint32_t state, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:358
int(* get_points)(struct dt_develop_t *dev, float x, float y, float radius_a, float radius_b, float rotation, float **points, int *points_count)
Definition masks.h:324
int(* button_released)(struct dt_iop_module_t *module, double x, double y, int which, uint32_t state, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:362
int(* get_mask_roi)(const dt_iop_module_t *const fmodule, struct dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, struct dt_masks_form_t *const form, const dt_iop_roi_t *roi, float *buffer)
Definition masks.h:332
int(* get_source_area)(dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, struct dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
Definition masks.h:340
int(* key_pressed)(struct dt_iop_module_t *module, GdkEventKey *event, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:365
int(* mouse_moved)(struct dt_iop_module_t *module, double x, double y, double pressure, int which, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:351
void(* sanitize_config)(dt_masks_type_t type_flags)
Definition masks.h:315
void(* set_form_name)(struct dt_masks_form_t *const form, const size_t nb)
Definition masks.h:316
void(* duplicate_points)(struct dt_develop_t *const dev, struct dt_masks_form_t *base, struct dt_masks_form_t *dest)
Definition masks.h:319
int(* populate_context_menu)(GtkWidget *menu, struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, const float pzx, const float pzy)
Definition masks.h:371
int(* update_hover)(struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:349
float(* set_interaction_value)(struct dt_masks_form_t *form, dt_masks_interaction_t interaction, float value, dt_masks_increment_t increment, int flow, struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module)
Definition masks.h:345
int(* get_points_border)(struct dt_develop_t *dev, struct dt_masks_form_t *form, float **points, int *points_count, float **border, int *border_count, int source, const dt_iop_module_t *const module)
Definition masks.h:326
int(* get_area)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, struct dt_masks_form_t *const form, int *width, int *height, int *posx, int *posy)
Definition masks.h:336
void(* get_distance)(float x, float y, float as, struct dt_masks_form_gui_t *gui, int index, int num_points, int *inside, int *inside_border, int *near, int *inside_source, float *dist)
Definition masks.h:322
void(* draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source)
Definition masks.h:368
int(* mouse_scrolled)(struct dt_iop_module_t *module, double x, double y, int up, const int delta_y, uint32_t state, struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index, dt_masks_interaction_t interaction)
Definition masks.h:354
void(* initial_source_pos)(const float iwd, const float iht, float *x, float *y)
Definition masks.h:320
int(* get_mask)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, struct dt_masks_form_t *const form, float **buffer, int *width, int *height, int *posx, int *posy)
Definition masks.h:328
void(* post_expose)(cairo_t *cr, float zoom_scale, struct dt_masks_form_gui_t *gui, int index, int num_points)
Definition masks.h:366
void(* set_hint_message)(const struct dt_masks_form_gui_t *const gui, const struct dt_masks_form_t *const form, const int opacity, char *const __restrict__ msgbuf, const size_t msgbuf_len)
Definition masks.h:317
void(* init_ctrl_points)(struct dt_masks_form_t *form)
Definition masks.h:370
struct dt_masks_gui_center_point_t::@34 main
struct dt_masks_gui_center_point_t::@35 source
dt_masks_points_states_t state
Definition masks.h:266
dt_masks_ellipse_flags_t flags
Definition masks.h:244
dt_masks_points_states_t state
Definition masks.h:254
dt_iop_module_t * creation_module
Definition masks.h:970
dt_masks_shape_buttons_flags_t register_flags
Definition masks.h:975
dt_masks_shape_buttons_type_f form_type
Definition masks.h:979
dt_masks_shape_buttons_start_f can_start
Definition masks.h:978
dt_masks_shape_buttons_notify_f exited
Definition masks.h:981
dt_masks_shape_buttons_notify_f started
Definition masks.h:980
dt_iop_module_t * owner_module
Definition masks.h:969
dt_masks_shape_buttons_flags_t flags
Definition masks.h:974