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/atomic.h"
112#include "common/darktable.h"
113#include "common/opencl.h"
114#include "develop/pixelpipe.h"
115#include "dtgtk/button.h"
116#include "dtgtk/gradientslider.h"
117#include "gui/draw.h"
118#include "control/control.h"
119
120#include <assert.h>
121
122#ifdef __cplusplus
123extern "C" {
124#endif
125
126#define DEVELOP_MASKS_VERSION (6)
127
153
180
186
192
199
206
216
222
229
232{
233 float center[2]; // point in normalized input space
234 float radius;
235 float border;
237
247
257
269
280
289
290struct dt_masks_form_t;
292struct dt_develop_t;
293
294/*
295* Type of user interaction to map with internal properties of masks.
296* Those were initially handled implicitly by Shift/Ctrl/Shift+Ctrl + mouse scroll
297* at the scope of each mask type, which is a shitty design when using Wacom tablets.
298* This case is now covered by the DT_MASK_INTERACTION_UNDEF.
299* Otherwise, when calling the mouse_scroll callback from GUI, we set the case
300* explicitly, along with a value.
301*/
303{
304 DT_MASKS_INTERACTION_UNDEF = 0, // let it be deduced contextually from key modifiers, implicit
305 DT_MASKS_INTERACTION_SIZE = 1, // property of the form (shape), explicit
306 DT_MASKS_INTERACTION_HARDNESS = 2, // property of the form (shape), explicit
307 DT_MASKS_INTERACTION_OPACITY = 3, // property of the group in which the form is included, explicit
308 DT_MASKS_INTERACTION_ROTATION = 4, // property of the form (shape), explicit
311
315{
316 int point_struct_size; // sizeof(struct dt_masks_point_*_t)
318 void (*set_form_name)(struct dt_masks_form_t *const form, const size_t nb);
319 void (*set_hint_message)(const struct dt_masks_form_gui_t *const gui, const struct dt_masks_form_t *const form,
320 const int opacity, char *const __restrict__ msgbuf, const size_t msgbuf_len);
321 void (*duplicate_points)(struct dt_develop_t *const dev, struct dt_masks_form_t *base, struct dt_masks_form_t *dest);
322 void (*initial_source_pos)(const float iwd, const float iht, float *x, float *y);
323 // input coordinates are in absolute output-image space, dist is squared in the same space
324 void (*get_distance)(float x, float y, float as, struct dt_masks_form_gui_t *gui, int index, int num_points,
325 int *inside, int *inside_border, int *near, int *inside_source, float *dist);
326 int (*get_points)(struct dt_develop_t *dev, float x, float y, float radius_a, float radius_b, float rotation,
327 float **points, int *points_count);
328 int (*get_points_border)(struct dt_develop_t *dev, struct dt_masks_form_t *form, float **points, int *points_count,
329 float **border, int *border_count, int source, const dt_iop_module_t *const module);
330 int (*get_mask)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe,
331 const dt_dev_pixelpipe_iop_t *const piece,
332 struct dt_masks_form_t *const form,
333 float **buffer, int *width, int *height, int *posx, int *posy);
334 int (*get_mask_roi)(const dt_iop_module_t *const fmodule, struct dt_dev_pixelpipe_t *pipe,
335 const dt_dev_pixelpipe_iop_t *const piece,
336 struct dt_masks_form_t *const form,
337 const dt_iop_roi_t *roi, float *buffer);
338 int (*get_area)(const dt_iop_module_t *const module, struct dt_dev_pixelpipe_t *pipe,
339 const dt_dev_pixelpipe_iop_t *const piece,
340 struct dt_masks_form_t *const form,
341 int *width, int *height, int *posx, int *posy);
343 dt_dev_pixelpipe_iop_t *piece, struct dt_masks_form_t *form,
344 int *width, int *height, int *posx, int *posy);
345 gboolean (*get_gravity_center)(const struct dt_masks_form_t *form, float center[2], float *area);
346 float (*get_interaction_value)(const struct dt_masks_form_t *form, dt_masks_interaction_t interaction);
347 float (*set_interaction_value)(struct dt_masks_form_t *form, dt_masks_interaction_t interaction, float value,
348 dt_masks_increment_t increment, int flow,
349 struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module);
350 /* Recompute hovered handles/nodes from the cached cursor state in gui. */
351 int (*update_hover)(struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, int index);
352 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
353 int (*mouse_moved)(struct dt_iop_module_t *module, double x, double y, double pressure, int which,
354 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
355 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
356 int (*mouse_scrolled)(struct dt_iop_module_t *module, double x, double y, int up, const int delta_y, uint32_t state,
357 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index,
358 dt_masks_interaction_t interaction);
359 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
360 int (*button_pressed)(struct dt_iop_module_t *module, double x, double y,
361 double pressure, int which, int type, uint32_t state,
362 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
363 /* Mouse x and y are widget-space coordinates from GTK/Cairo */
364 int (*button_released)(struct dt_iop_module_t *module, double x, double y, int which, uint32_t state,
365 struct dt_masks_form_t *form, int parentid, struct dt_masks_form_gui_t *gui, int index);
366 /* Key event */
367 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);
368 void (*post_expose)(cairo_t *cr, float zoom_scale, struct dt_masks_form_gui_t *gui, int index, int num_points);
369 // The function to draw the shape in question.
370 void (*draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source);
373 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);
375
377typedef struct dt_masks_form_t
378{
379 GList *points; // list of point structures (nodes)
382 // TRUE when gui_points->points uses the Bezier layout (points[k*6+2])
384
385 // position of the origin point of source (used only for clone)
386 // in normalized coordinates in raw input space
387 float source[2];
388
389 // cached center of gravity
390 // in normalized coordinates in raw input space
392 // FALSE means gravity_center/area are stale and must be recomputed before being read
393 // (see dt_masks_form_update_gravity_center() / dt_masks_form_invalidate_gravity_center()).
394 // Lets bulk paths (loading history, undo/redo) defer the actual computation to the one
395 // GUI hit-testing read site instead of paying it for every form up front.
397
398 // cached shape area, taken as a weight estimator to get
399 // the gravity center of multi-shapes by combining
400 // weight and gravity centers of all shapes
401 float area;
402 // name of the form
403 char name[128];
404 // id used to store the form
406 // version of the form
408
409 // number of live pointers to this form: dev->forms/allforms, hist->forms
410 // snapshots, undo/redo snapshots. See develop/masks/masks_history.h.
413
414// dt_masks_form_t must be fully defined above this include.
416
419{
420 float *points; // points in absolute coordinates in output image space
422 float *border; // border points in absolute coordinates in output image space
424 float *source; // source point in absolute coordinates in output image space
426 gboolean clockwise;
428
430typedef struct dt_masks_dynbuf_t
431{
432 float *buffer;
433 char tag[128];
434 size_t pos;
435 size_t size;
437
438
441{
443 // currently visible form when editing masks (GUI-only; may be a temporary copy)
445 // points used to draw the form
446 GList *points; // list of dt_masks_form_gui_points_t
447
448 // points used to sample mouse moves
451
452 // values for mouse positions, etc...
453
454 // Mouse position in absolute coordinates in final image space
455 // This is used to map input event handlers to *_post_expose() drawing functions
456 // and to record drag & drop starting coordinates.
457 float pos[2];
458
459 // Mouse position in normalized coordinates in output image space.
460 // This is cached once per top-level event and replaces ad-hoc pzx/pzy recomputation.
461 float rel_pos[2];
462
463 // Mouse position in absolute coordinates in raw input image space.
464 // This is cached once per top-level event so nested handlers can reuse it.
465 float raw_pos[2];
466
467 // delta movement of the mouse in absolute coordinates in final image space
468 // This is used to map input event handlers to *_post_expose() drawing functions
469 float delta[2];
470
471 // scroll offset
473
474 // Position of a clone mask's source point (in what coordinates space ?)
475 float pos_source[2];
476
478
479 int node_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
480 int handle_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
481 int seg_hovered; // this is the index of the segment, refreshed on mouse_moved when a a group is selected
482 int handle_border_hovered; // this is the index of the node, refreshed on mouse_moved when a a group is selected
483
484 gboolean node_selected; // this is the state of the node referenced by node_hovered
485 gboolean handle_selected; // this is the state of the handle referenced by handle_hovered
486 gboolean seg_selected; // this is the state of the segment referenced by segment_hovered
487 gboolean handle_border_selected; // this is the state of the border handle referenced by handle_border_hovered
488 int node_selected_idx; // stable selected node index, distinct from current hover
489
494
496
498
508
509 // Throttle GUI rebuilds while dragging to avoid heavy border recomputation.
513
514 // Throttle handle hit-testing when cursor barely moves.
516
517 gboolean creation;
520 // Shape type reused to create the next temporary form in a continuous creation session.
522 // Form ids completed during the active creation session; only these are drawn while creation stays active.
524 // Last completed form id, selected when the creation session is disabled.
526
528
529 // ids
533
536void dt_masks_gui_init(struct dt_develop_t *dev);
537void dt_masks_gui_cleanup(struct dt_develop_t *dev);
541
542// Test wether the form, the border, the source or the pivot is selected
544{
545 return gui && (gui->form_selected || gui->border_selected || gui->source_selected || gui->pivot_selected);
546}
547
549{
550 return (gui && gui->node_selected) ? gui->node_selected_idx : -1;
551}
552
554{
555 return (gui && gui->handle_selected) ? gui->handle_hovered : -1;
556}
557
559{
560 return (gui && gui->handle_border_selected) ? gui->handle_border_hovered : -1;
561}
562
564{
565 return (gui) ? gui->seg_hovered : -1;
566}
567
569 const int index)
570{
571 if(IS_NULL_PTR(gui)) return TRUE;
572
573 const int selected_node = dt_masks_gui_selected_node_index(gui);
574 return selected_node < 0 || selected_node == index;
575}
576
577static inline float dt_masks_get_form_size_from_nodes(const GList *points)
578{
579 if(IS_NULL_PTR(points) || IS_NULL_PTR(points->data)) return 0.0f;
580
581 // Brush and polygon node payloads both start with `float node[2]`.
582 const float *first = (const float *)points->data;
583 float min_x = first[0];
584 float max_x = first[0];
585 float min_y = first[1];
586 float max_y = first[1];
587
588 for(const GList *point_node = points; point_node; point_node = g_list_next(point_node))
589 {
590 const float *node = (const float *)point_node->data;
591 if(IS_NULL_PTR(node)) continue;
592 min_x = fminf(min_x, node[0]);
593 max_x = fmaxf(max_x, node[0]);
594 min_y = fminf(min_y, node[1]);
595 max_y = fmaxf(max_y, node[1]);
596 }
597
598 return fmaxf(max_x - min_x, max_y - min_y);
599}
600
602{
603 const float hit_thresh = DT_GUI_MOUSE_EFFECT_RADIUS * 0.5f;
604 const float dx = gui->pos[0] - gui->last_hit_test_pos[0];
605 const float dy = gui->pos[1] - gui->last_hit_test_pos[1];
606 if(gui->last_hit_test_pos[0] < 0.0f || (dx * dx + dy * dy) > (hit_thresh * hit_thresh))
607 {
608 gui->last_hit_test_pos[0] = gui->pos[0];
609 gui->last_hit_test_pos[1] = gui->pos[1];
610 return TRUE;
611 }
612 return FALSE;
613}
614
615// High-level mask event dispatchers cache the current cursor in raw absolute coordinates.
616// Reuse that cache for current-cursor conversions instead of backtransforming `gui->pos` again.
617static inline void dt_masks_gui_cursor_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
618{
619 point[0] = gui->raw_pos[0];
620 point[1] = gui->raw_pos[1];
622}
623
624// Reuse the cached absolute output-image cursor and drag delta to derive a raw-normalized point.
625static inline void dt_masks_gui_delta_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
626{
627 point[0] = gui->pos[0] + gui->delta[0];
628 point[1] = gui->pos[1] + gui->delta[1];
630}
631
632static inline void dt_masks_gui_delta_to_image_abs(const dt_masks_form_gui_t *gui, float point[2])
633{
634 point[0] = gui->pos[0] + gui->delta[0];
635 point[1] = gui->pos[1] + gui->delta[1];
636}
637
638// Drag branches need the same "cursor + drag delta" converted back to raw space.
639// Keep that conversion in one place so all shapes use the same anchor semantics.
641 const float anchor[2], float *delta_x, float *delta_y)
642{
643 float point[2];
645 *delta_x = point[0] - anchor[0];
646 *delta_y = point[1] - anchor[1];
647}
648
649// Clone and spot forms share the same default presets, while regular drawn masks use their own.
650static inline gboolean dt_masks_form_uses_spot_defaults(const dt_masks_form_t *form)
651{
652 return (form->type & (DT_MASKS_CLONE | DT_MASKS_NON_CLONE)) != 0;
653}
654
655static inline gboolean dt_masks_form_is_clone(const dt_masks_form_t *form)
656{
657 return (form->type & DT_MASKS_CLONE) != 0;
658}
659
660static inline void dt_masks_reset_source(dt_masks_form_t *form)
661{
662 form->source[0] = 0.0f;
663 form->source[1] = 0.0f;
664}
665
666static inline void dt_masks_translate_source(dt_masks_form_t *form, const float delta_x, const float delta_y)
667{
668 form->source[0] += delta_x;
669 form->source[1] += delta_y;
670}
671
672static inline void dt_masks_translate_ctrl_node(float node[2], float ctrl1[2], float ctrl2[2],
673 const float delta_x, const float delta_y)
674{
675 node[0] += delta_x;
676 node[1] += delta_y;
677 ctrl1[0] += delta_x;
678 ctrl1[1] += delta_y;
679 ctrl2[0] += delta_x;
680 ctrl2[1] += delta_y;
681}
682
683static inline void dt_masks_set_ctrl_points(float ctrl1[2], float ctrl2[2], const float control_points[4])
684{
685 ctrl1[0] = control_points[0];
686 ctrl1[1] = control_points[1];
687 ctrl2[0] = control_points[2];
688 ctrl2[1] = control_points[3];
689}
690
691gboolean dt_masks_node_is_cusp(const dt_masks_form_gui_points_t *gpt, const int index);
693 struct dt_iop_module_t *module);
694
695// Brush and polygon nodes share the same node/control-point edit semantics.
696static inline gboolean dt_masks_toggle_bezier_node_type(struct dt_iop_module_t *module,
697 struct dt_masks_form_t *mask_form,
698 struct dt_masks_form_gui_t *mask_gui,
699 const int form_index,
700 const struct dt_masks_form_gui_points_t *gui_points,
701 const int node_index,
702 float node[2], float ctrl1[2], float ctrl2[2],
704{
705 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;
706
707 if(dt_masks_node_is_cusp(gui_points, node_index))
708 {
710 if(mask_form->functions && mask_form->functions->init_ctrl_points)
711 mask_form->functions->init_ctrl_points(mask_form);
712 }
713 else
714 {
715 ctrl1[0] = ctrl2[0] = node[0];
716 ctrl1[1] = ctrl2[1] = node[1];
718 }
719
720 dt_masks_gui_form_create(mask_form, mask_gui, form_index, module);
721 return TRUE;
722}
723
724static inline gboolean dt_masks_reset_bezier_ctrl_points(struct dt_iop_module_t *module,
725 struct dt_masks_form_t *mask_form,
726 struct dt_masks_form_gui_t *mask_gui,
727 const int form_index,
728 const struct dt_masks_form_gui_points_t *gui_points,
729 const int node_index,
731{
732 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;
733
734 if(*state != DT_MASKS_POINT_STATE_NORMAL && !dt_masks_node_is_cusp(gui_points, node_index))
735 {
737 if(mask_form->functions && mask_form->functions->init_ctrl_points)
738 mask_form->functions->init_ctrl_points(mask_form);
739 dt_masks_gui_form_create(mask_form, mask_gui, form_index, module);
740 }
741
742 return TRUE;
743}
744
745// Brush and polygon border handles both constrain the cursor to the node->handle axis.
746static inline void dt_masks_project_on_line(const float cursor[2], const float node[2],
747 const float handle[2], float point[2])
748{
749 const float dx_line = handle[0] - node[0];
750 const float dy_line = handle[1] - node[1];
751
752 if(fabsf(dx_line) < 1e-6f)
753 {
754 point[0] = node[0];
755 point[1] = cursor[1];
756 }
757 else
758 {
759 const float a = dy_line / dx_line;
760 const float b = node[1] - a * node[0];
761 const float denom = a * a + 1.0f;
762 const float xproj = (a * cursor[1] + cursor[0] - b * a) / denom;
763
764 point[0] = xproj;
765 point[1] = a * xproj + b;
766 }
767}
768
769// Border handles store normalized raw-space radii, but hit/drag code works in image space.
770// Convert both ends once here so all shapes derive border thickness the same way.
771static inline float dt_masks_border_from_projected_handle(dt_develop_t *dev, const float node[2],
772 const float projected_image_pos[2],
773 const float scale_ref)
774{
775 float projected_raw[2] = { projected_image_pos[0], projected_image_pos[1] };
776 float node_raw[2] = { node[0], node[1] };
777 dt_dev_coordinates_image_abs_to_raw_abs(dev, projected_raw, 1);
779
780 const float delta_x = projected_raw[0] - node_raw[0];
781 const float delta_y = projected_raw[1] - node_raw[1];
782 return sqrtf(delta_x * delta_x + delta_y * delta_y) / scale_ref;
783}
784
785// Circle, ellipse and gradient creation previews all follow the same drawing sequence:
786// optional save/restore, draw the shape, then draw the border preview if present.
787static inline void dt_masks_draw_preview_shape(cairo_t *cr, const float zoom_scale, const int num_points,
788 float *points, const int points_count,
789 float *border, const int border_count,
790 void (*const *draw_shape)(cairo_t *cr, const float *points,
791 const int points_count, const int nb,
792 const gboolean border,
793 const gboolean source),
794 const cairo_line_cap_t shape_cap,
795 const cairo_line_cap_t border_cap,
796 const gboolean save_restore,
797 const gboolean source)
798{
799 if(save_restore) cairo_save(cr);
800 if(points && points_count > 0)
801 dt_draw_shape_lines(DT_MASKS_NO_DASH, source, cr, num_points, FALSE, zoom_scale, points, points_count,
802 draw_shape, shape_cap);
803 if(border && border_count > 0)
804 dt_draw_shape_lines(DT_MASKS_DASH_STICK, source, cr, num_points, FALSE, zoom_scale, border, border_count,
805 draw_shape, border_cap);
806 if(save_restore) cairo_restore(cr);
807}
808
809// Shared scratch buffers for creation previews. Keeping them grouped makes the shape
810// preview helpers return a single value and centralizes cleanup.
820
827
829{
830 struct
831 {
832 float x;
833 float y;
835
836 struct
837 {
838 float x;
839 float y;
842
850
853
856int dt_masks_get_points_border(struct dt_develop_t *dev, dt_masks_form_t *form, float **points, int *points_count,
857 float **border, int *border_count, int source, dt_iop_module_t *module);
858
861 dt_masks_form_t *form,
862 int *width, int *height, int *posx, int *posy);
865 int *width, int *height, int *posx, int *posy);
867static inline int dt_masks_get_mask(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe,
868 const dt_dev_pixelpipe_iop_t *const piece,
869 dt_masks_form_t *const form,
870 float **buffer, int *width, int *height, int *posx, int *posy)
871{
872 return (form->functions && form->functions->get_mask)
873 ? form->functions->get_mask(module, pipe, piece, form, buffer, width, height, posx, posy)
874 : 1;
875}
876static inline int dt_masks_get_mask_roi(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe,
877 const dt_dev_pixelpipe_iop_t *const piece,
878 dt_masks_form_t *const form, const dt_iop_roi_t *roi, float *buffer)
879{
880 return (form->functions && form->functions->get_mask_roi)
881 ? form->functions->get_mask_roi(module, pipe, piece, form, roi, buffer)
882 : 1;
883}
884
886 const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form,
887 const dt_iop_roi_t *roi, float *buffer);
888
889// returns current masks version
890int dt_masks_version(void);
891
894void dt_masks_remove_node(struct dt_iop_module_t *module, dt_masks_form_t *form, int parentid,
895 dt_masks_form_gui_t *gui, int index, int node_index);
896
897// update masks from older versions
898int dt_masks_legacy_params(dt_develop_t *dev, void *params, const int old_version, const int new_version);
899/*
900 * TODO:
901 *
902 * int
903 * dt_masks_legacy_params(
904 * dt_develop_t *dev,
905 * const void *const old_params, const int old_version,
906 * void *new_params, const int new_version);
907 */
908
914dt_masks_form_t *dt_masks_get_from_id_ext(GList *forms, int id);
919 const struct dt_iop_module_t *mod_src);
922
924void dt_masks_read_masks_history(dt_develop_t *dev, const int32_t imgid);
926void dt_masks_write_masks_history_item(const int32_t imgid, const int num, dt_masks_form_t *form);
929
933void dt_masks_reset_form_gui(void);
936
937#define DEVELOP_MASKS_NB_SHAPES 5
938
947
969
970typedef gboolean (*dt_masks_shape_buttons_start_f)(GtkWidget *button, dt_iop_module_t *module,
971 dt_masks_type_t type, gpointer user_data);
973 gpointer user_data);
975 dt_masks_type_t type, gpointer user_data);
976
993
996
997int dt_masks_events_mouse_moved(struct dt_iop_module_t *module, double x, double y, double pressure,
998 int which);
999int dt_masks_events_button_released(struct dt_iop_module_t *module, double x, double y, int which,
1000 uint32_t state);
1001int dt_masks_events_button_pressed(struct dt_iop_module_t *module, double x, double y, double pressure,
1002 int which, int type, uint32_t state);
1003int dt_masks_events_mouse_scrolled(struct dt_iop_module_t *module, double x, double y, int up, uint32_t state, int delta_y);
1004
1005int dt_masks_events_key_pressed(struct dt_iop_module_t *module, GdkEventKey *event);
1017gboolean dt_masks_node_is_cusp(const dt_masks_form_gui_points_t *gpt, const int index);
1018
1029void dt_masks_draw_source(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const int nb,
1030 const float zoom_scale, struct dt_masks_gui_center_point_t *center_point, const shape_draw_function_t *draw_shape_func);
1031void dt_masks_draw_path_seg_by_seg(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const float *points,
1032 const int points_count, const int node_count, const float zoom_scale);
1033
1034void dt_masks_events_post_expose(struct dt_iop_module_t *module, cairo_t *cr, int32_t width, int32_t height,
1035 int32_t pointerx, int32_t pointery);
1038
1041 struct dt_iop_module_t *module);
1043 struct dt_iop_module_t *module, float posx, float posy);
1044
1055gboolean dt_masks_gui_remove(struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui, const int parentid);
1056
1067gboolean dt_masks_remove_or_delete(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id,
1068 dt_masks_form_gui_t *mask_gui, int form_id);
1069
1076gboolean dt_masks_remove_shape_from_group(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id,
1077 dt_masks_form_gui_t *mask_gui, int form_id);
1078
1085gboolean dt_masks_delete_shape(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id,
1086 dt_masks_form_gui_t *mask_gui, int form_id);
1087
1088
1089// Remove a mask
1091
1092
1095
1105 dt_masks_form_gui_t *gui);
1109
1113void dt_masks_iop_update(struct dt_iop_module_t *module);
1114void dt_masks_iop_combo_populate(GtkWidget *w, void *module);
1115void dt_masks_iop_use_same_as(struct dt_iop_module_t *module, struct dt_iop_module_t *src);
1121
1123int dt_masks_form_change_opacity(dt_masks_form_t *form, int parentid, int up, const int flow);
1124void dt_masks_form_move(dt_masks_form_t *grp, int formid, int up);
1125int dt_masks_form_duplicate(dt_develop_t *dev, int formid);
1126/* returns a duplicate tof form, including the formid */
1128
1130int dt_masks_point_in_form_exact(const float *pts, int num_pts, const float *points, int points_start, int points_count);
1131
1133void dt_masks_select_form(struct dt_iop_module_t *module, dt_masks_form_t *sel);
1134
1138void dt_masks_calculate_source_pos_origin(dt_masks_form_gui_t *gui, const float initial_xpos,
1139 const float initial_ypos, const float xpos, const float ypos, float *px,
1140 float *py, const int adding);
1141static inline void dt_masks_draw_source_preview(cairo_t *cr, const float zoom_scale, dt_masks_form_gui_t *gui,
1142 const float initial_xpos, const float initial_ypos,
1143 const float xpos, const float ypos, const int adding)
1144{
1145 float source_pos[2] = { 0.0f, 0.0f };
1146 dt_masks_calculate_source_pos_origin(gui, initial_xpos, initial_ypos, xpos, ypos,
1147 &source_pos[0], &source_pos[1], adding);
1148 dt_draw_cross(cr, zoom_scale, source_pos[0], source_pos[1]);
1149}
1160float dt_masks_rotate_with_anchor(dt_develop_t *dev, const float anchor[2], const float center[2], dt_masks_form_gui_t *gui);
1161
1164int dt_masks_group_index_from_formid(const dt_masks_form_t *group_form, int formid);
1166 const struct dt_masks_form_gui_t *gui);
1167
1169gboolean dt_masks_is_anything_selected(const dt_masks_form_gui_t *mask_gui);
1170
1172gboolean dt_masks_is_anything_hovered(const dt_masks_form_gui_t *mask_gui);
1173
1183 const struct dt_masks_form_gui_t *gui);
1185 dt_masks_interaction_t interaction);
1186gboolean dt_masks_form_get_gravity_center(const struct dt_masks_form_t *form, float center[2], float *area);
1192int dt_masks_center_view_on_form(struct dt_develop_t *dev, const struct dt_masks_form_t *form);
1194 dt_masks_interaction_t interaction,
1195 float value, dt_masks_increment_t increment, int flow,
1196 struct dt_masks_form_gui_t *gui, struct dt_iop_module_t *module);
1197
1210float dt_masks_get_set_conf_value(dt_masks_form_t *form, char *feature, float new_value, float v_min, float v_max,
1211 dt_masks_increment_t increment, const int flow);
1218float dt_masks_get_set_conf_value_with_toast(dt_masks_form_t *form, const char *feature, float amount,
1219 float v_min, float v_max, dt_masks_increment_t increment, int flow,
1220 const char *toast_fmt, float toast_scale);
1221
1227void dt_masks_duplicate_points(const dt_masks_form_t *base, dt_masks_form_t *dest, size_t node_size);
1228
1232float dt_masks_apply_increment(float current, float amount, dt_masks_increment_t increment, int flow);
1233
1237float dt_masks_apply_increment_precomputed(float current, float amount, float scale_amount, float offset_amount,
1238 dt_masks_increment_t increment);
1239
1241void dt_masks_extend_border(float *const mask, const int width, const int height, const int border);
1242void dt_masks_blur_9x9_coeff(float *coeffs, const float sigma);
1243void dt_masks_blur_9x9(float *const src, float *const out, const int width, const int height, const float sigma);
1244void dt_masks_calc_rawdetail_mask(float *const src, float *const out, float *const tmp, const int width,
1245 const int height, const dt_aligned_pixel_t wb);
1246void 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);
1247
1248void dt_group_events_post_expose(cairo_t *cr, float zoom_scale, dt_masks_form_t *form,
1249 dt_masks_form_gui_t *gui);
1250
1252static inline gboolean _dt_masks_dynbuf_growto(dt_masks_dynbuf_t *a, size_t size)
1253{
1254 const size_t newsize = dt_round_size_sse(sizeof(float) * size) / sizeof(float);
1255 float *newbuf = dt_pixelpipe_cache_alloc_align_float_cache(newsize, 0);
1256 if (IS_NULL_PTR(newbuf))
1257 {
1258 // not much we can do here except emit an error message
1259 fprintf(stderr, "critical: out of memory for dynbuf '%s' with size request %" G_GSIZE_FORMAT "!\n", a->tag, size);
1260 return FALSE;
1261 }
1262 if (a->buffer)
1263 {
1264 memcpy(newbuf, a->buffer, a->size * sizeof(float));
1265 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] grows to size %lu (is %p, was %p)\n", a->tag,
1266 (unsigned long)a->size, newbuf, a->buffer);
1268 }
1269 a->size = newsize;
1270 a->buffer = newbuf;
1271 return TRUE;
1272}
1273
1274static inline dt_masks_dynbuf_t *dt_masks_dynbuf_init(size_t size, const char *tag)
1275{
1276 assert(size > 0);
1277 dt_masks_dynbuf_t *a = (dt_masks_dynbuf_t *)calloc(1, sizeof(dt_masks_dynbuf_t));
1278
1279 if(!IS_NULL_PTR(a))
1280 {
1281 g_strlcpy(a->tag, tag, sizeof(a->tag)); //only for debugging purposes
1282 a->pos = 0;
1284 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] with initial size %lu (is %p)\n", a->tag,
1285 (unsigned long)a->size, a->buffer);
1286 if(IS_NULL_PTR(a->buffer))
1287 {
1288 dt_free(a);
1289 }
1290 }
1291 return a;
1292}
1293
1294static inline void dt_masks_dynbuf_add_2(dt_masks_dynbuf_t *a, float value1, float value2)
1295{
1296 assert(!IS_NULL_PTR(a));
1297 assert(a->pos <= a->size);
1298 if(__builtin_expect(a->pos + 2 >= a->size, 0))
1299 {
1300 if (a->size == 0 || !_dt_masks_dynbuf_growto(a, 2 * (a->size+1)))
1301 return;
1302 }
1303 a->buffer[a->pos++] = value1;
1304 a->buffer[a->pos++] = value2;
1305}
1306
1307// Return a pointer to N floats past the current end of the dynbuf's contents, marking them as already in use.
1308// The caller should then fill in the reserved elements using the returned pointer.
1309static inline float *dt_masks_dynbuf_reserve_n(dt_masks_dynbuf_t *a, const int n)
1310{
1311 assert(!IS_NULL_PTR(a));
1312 assert(a->pos <= a->size);
1313 if(__builtin_expect(a->pos + n >= a->size, 0))
1314 {
1315 if(a->size == 0) return NULL;
1316 size_t newsize = a->size;
1317 while(a->pos + n >= newsize) newsize *= 2;
1318 if (!_dt_masks_dynbuf_growto(a, newsize))
1319 {
1320 return NULL;
1321 }
1322 }
1323 // get the current end of the (possibly reallocated) buffer, then mark the next N items as in-use
1324 float *reserved = a->buffer + a->pos;
1325 a->pos += n;
1326 return reserved;
1327}
1328
1329static inline void dt_masks_dynbuf_add_zeros(dt_masks_dynbuf_t *a, const int n)
1330{
1331 assert(!IS_NULL_PTR(a));
1332 assert(a->pos <= a->size);
1333 if(__builtin_expect(a->pos + n >= a->size, 0))
1334 {
1335 if(a->size == 0) return;
1336 size_t newsize = a->size;
1337 while(a->pos + n >= newsize) newsize *= 2;
1338 if (!_dt_masks_dynbuf_growto(a, newsize))
1339 {
1340 return;
1341 }
1342 }
1343 // now that we've ensured a sufficiently large buffer add N zeros to the end of the existing data
1344 memset(a->buffer + a->pos, 0, n * sizeof(float));
1345 a->pos += n;
1346}
1347
1348
1349static inline float dt_masks_dynbuf_get(dt_masks_dynbuf_t *a, int offset)
1350{
1351 assert(!IS_NULL_PTR(a));
1352 // offset: must be negative distance relative to end of buffer
1353 assert(offset < 0);
1354 assert((long)a->pos + offset >= 0);
1355 return (a->buffer[a->pos + offset]);
1356}
1357
1358static inline void dt_masks_dynbuf_set(dt_masks_dynbuf_t *a, int offset, float value)
1359{
1360 assert(!IS_NULL_PTR(a));
1361 // offset: must be negative distance relative to end of buffer
1362 assert(offset < 0);
1363 assert((long)a->pos + offset >= 0);
1364 a->buffer[a->pos + offset] = value;
1365}
1366
1368{
1369 assert(!IS_NULL_PTR(a));
1370 return a->buffer;
1371}
1372
1373static inline gboolean dt_masks_center_of_gravity_from_points(const float *points, const int points_count,
1374 float center[2], float *area)
1375{
1376 if(IS_NULL_PTR(points) || IS_NULL_PTR(center) || IS_NULL_PTR(area) || points_count <= 0)
1377 {
1378 if(center)
1379 {
1380 center[0] = 0.0f;
1381 center[1] = 0.0f;
1382 }
1383 if(!IS_NULL_PTR(area)) *area = 0.0f;
1384 return FALSE;
1385 }
1386
1387 double start = 0.;
1389
1390 // Points must be ordered sequentially along the polygon boundary.
1391 // Use the shoelace formula to compute area and centroid.
1392 if(points_count >= 3)
1393 {
1394 double area2 = 0.0;
1395 double cx = 0.0;
1396 double cy = 0.0;
1397
1398 for(int i = 0; i < points_count; i++)
1399 {
1400 const int j = (i + 1 < points_count) ? (i + 1) : 0;
1401 const double x0 = points[i * 2];
1402 const double y0 = points[i * 2 + 1];
1403 const double x1 = points[j * 2];
1404 const double y1 = points[j * 2 + 1];
1405
1406 const double cross = x0 * y1 - x1 * y0;
1407 area2 += cross;
1408 cx += (x0 + x1) * cross;
1409 cy += (y0 + y1) * cross;
1410 }
1411
1412 if(fabs(area2) > 1e-12)
1413 {
1414 const double inv = 1.0 / (3.0 * area2);
1415 center[0] = (float)(cx * inv);
1416 center[1] = (float)(cy * inv);
1417
1418 *area = (float)(0.5 * fabs(area2));
1419 return TRUE;
1420 }
1421 }
1422
1423 // Fallback to arithmetic mean for degenerate polygons or short lists.
1424 float sum_x = 0.0f;
1425 float sum_y = 0.0f;
1426 const float inv_count = 1.0f / (float)points_count;
1427 for(int i = 0; i < points_count; i++)
1428 {
1429 sum_x += points[i * 2] * inv_count;
1430 sum_y += points[i * 2 + 1] * inv_count;
1431 }
1432
1434 dt_print(DT_DEBUG_MASKS, "[masks] computing centroid took %0.04f sec\n",
1435 dt_get_wtime() - start);
1436
1437
1438 center[0] = sum_x;
1439 center[1] = sum_y;
1440 *area = 0.0f;
1441 return TRUE;
1442}
1443
1445{
1446 assert(!IS_NULL_PTR(a));
1447 return a->pos;
1448}
1449
1451{
1452 assert(!IS_NULL_PTR(a));
1453 a->pos = 0;
1454}
1455
1457{
1458 // take out data buffer and make dynamic buffer obsolete
1459 if(IS_NULL_PTR(a)) return NULL;
1460 float *r = a->buffer;
1461 a->buffer = NULL;
1462 a->pos = a->size = 0;
1463 return r;
1464}
1465
1467{
1468 if(IS_NULL_PTR(a)) return;
1469 dt_print(DT_DEBUG_MASKS, "[masks dynbuf '%s'] freed (was %p)\n", a->tag,
1470 a->buffer);
1472 dt_free(a);
1473}
1474
1475static inline int dt_masks_roundup(int num, int mult)
1476{
1477 const int rem = num % mult;
1478
1479 return (rem == 0) ? num : num + mult - rem;
1480}
1481
1492gboolean dt_masks_point_is_within_radius(const float px, const float py,
1493 const float cx, const float cy,
1494 const float radius);
1495
1501typedef gboolean (*dt_masks_border_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_count,
1502 int node_index, float *handle_x, float *handle_y, void *user_data);
1508typedef void (*dt_masks_curve_handle_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index,
1509 float *handle_x, float *handle_y, void *user_data);
1515typedef void (*dt_masks_node_position_fn)(const dt_masks_form_gui_points_t *gui_points, int node_index,
1516 float *node_x, float *node_y, void *user_data);
1523typedef void (*dt_masks_distance_fn)(float pointer_x, float pointer_y, float cursor_radius,
1524 dt_masks_form_gui_t *mask_gui, int form_index, int node_count,
1525 int *inside, int *inside_border, int *near, int *inside_source, float *dist,
1526 void *user_data);
1530typedef void (*dt_masks_post_select_fn)(dt_masks_form_gui_t *mask_gui, int inside, int inside_border,
1531 int inside_source, void *user_data);
1532
1542 int form_index, int node_count_override,
1543 dt_masks_border_handle_fn border_handle_cb,
1544 dt_masks_curve_handle_fn curve_handle_cb,
1545 dt_masks_node_position_fn node_position_cb,
1546 dt_masks_distance_fn distance_cb,
1547 dt_masks_post_select_fn post_select_cb,
1548 void *user_data);
1549
1552void apply_operation(struct dt_masks_form_group_t *pt, const dt_masks_state_t apply_state);
1553
1556#define menu_item_set_fake_accel(menu_item, keyval, mods) \
1557 \
1558{ \
1559 GtkWidget *child = gtk_bin_get_child(GTK_BIN(menu_item)); \
1560 if(GTK_IS_ACCEL_LABEL(child)) \
1561 gtk_accel_label_set_accel(GTK_ACCEL_LABEL(child), keyval, mods); \
1562}
1563
1564void _masks_gui_delete_node_callback(GtkWidget *menu, gpointer user_data);
1565
1567
1569 const float pzx, const float pzy);
1570
1573int dt_masks_gui_confirm_delete_form_dialog(const char *form_name);
1574
1581gboolean dt_masks_gui_confirm_permanent_delete(const char *form_name);
1582
1583#ifdef __cplusplus
1584}
1585#endif
1586
1587// clang-format off
1588// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1589// vim: shiftwidth=2 expandtab tabstop=2 cindent
1590// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1591// 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
atomic_int dt_atomic_int
Definition atomic.h:66
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:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_PERF
Definition darktable.h:741
@ DT_DEBUG_MASKS
Definition darktable.h:749
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:459
static size_t dt_round_size_sse(const size_t size)
Definition darktable.h:415
#define dt_free(ptr)
Definition darktable.h:478
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:475
static const dt_aligned_pixel_simd_t value
Definition darktable.h:599
static double dt_get_wtime(void)
Definition darktable.h:976
#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
void dt_dev_coordinates_raw_norm_to_raw_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1162
int dt_dev_coordinates_image_abs_to_raw_abs(dt_develop_t *dev, float *points, size_t points_count)
Definition develop.c:1594
void dt_dev_coordinates_raw_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1145
void dt_dev_coordinates_image_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1191
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
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:632
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:563
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:972
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:970
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:1523
static int dt_masks_gui_selected_node_index(const dt_masks_form_gui_t *gui)
Definition masks.h:548
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:3775
static int dt_masks_gui_selected_handle_index(const dt_masks_form_gui_t *gui)
Definition masks.h:553
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:1367
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:940
@ DT_MASKS_SHAPE_INDEX_BRUSH
Definition masks.h:945
@ DT_MASKS_SHAPE_INDEX_ELLIPSE
Definition masks.h:943
@ DT_MASKS_SHAPE_INDEX_CIRCLE
Definition masks.h:944
@ DT_MASKS_SHAPE_INDEX_GRADIENT
Definition masks.h:941
@ DT_MASKS_SHAPE_INDEX_POLYGON
Definition masks.h:942
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:696
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:1294
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:201
@ DT_MASKS_EDIT_RESTRICTED
Definition masks.h:204
@ DT_MASKS_EDIT_OFF
Definition masks.h:202
@ DT_MASKS_EDIT_FULL
Definition masks.h:203
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:1141
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)
uint64_t dt_masks_form_get_own_hash(uint64_t hash, const 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:1274
static void dt_masks_translate_source(dt_masks_form_t *form, const float delta_x, const float delta_y)
Definition masks.h:666
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:1530
gboolean dt_masks_gui_confirm_permanent_delete(const char *form_name)
Ask the user to confirm a permanent shape deletion, gated by the "ask_before_delete_mask_shape" pref....
Definition masks_gui.c:464
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:1349
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:672
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:167
@ DT_MASKS_STATE_DIFFERENCE
Definition masks.h:174
@ DT_MASKS_STATE_INVERSE
Definition masks.h:171
@ DT_MASKS_STATE_INTERSECTION
Definition masks.h:173
@ DT_MASKS_STATE_IS_COMBINE_OP
Definition masks.h:178
@ DT_MASKS_STATE_SHOW
Definition masks.h:170
@ DT_MASKS_STATE_EXCLUSION
Definition masks.h:175
@ DT_MASKS_STATE_NONE
Definition masks.h:168
@ DT_MASKS_STATE_UNION
Definition masks.h:172
@ DT_MASKS_STATE_USE
Definition masks.h:169
@ DT_MASKS_STATE_NOOP
Definition masks.h:176
static float dt_masks_get_form_size_from_nodes(const GList *points)
Definition masks.h:577
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:1309
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:87
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:558
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:181
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:1252
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:1501
dt_masks_type_t
Definition masks.h:130
@ DT_MASKS_NON_CLONE
Definition masks.h:139
@ DT_MASKS_ALL
Definition masks.h:141
@ DT_MASKS_POLYGON
Definition masks.h:133
@ DT_MASKS_BRUSH
Definition masks.h:138
@ DT_MASKS_IS_PATH_SHAPE
Definition masks.h:149
@ DT_MASKS_IS_OPEN_SHAPE
Definition masks.h:145
@ DT_MASKS_ELLIPSE
Definition masks.h:137
@ DT_MASKS_CLONE
Definition masks.h:135
@ DT_MASKS_GRADIENT
Definition masks.h:136
@ DT_MASKS_NONE
Definition masks.h:131
@ DT_MASKS_CIRCLE
Definition masks.h:132
@ DT_MASKS_GROUP
Definition masks.h:134
@ DT_MASKS_IS_PRIMITIVE_SHAPE
Definition masks.h:150
@ DT_MASKS_IS_CLOSED_SHAPE
Definition masks.h:144
@ DT_MASKS_IS_RETOUCHE
Definition masks.h:147
dt_masks_interaction_t
Definition masks.h:303
@ DT_MASKS_INTERACTION_OPACITY
Definition masks.h:307
@ DT_MASKS_INTERACTION_HARDNESS
Definition masks.h:306
@ DT_MASKS_INTERACTION_SIZE
Definition masks.h:305
@ DT_MASKS_INTERACTION_LAST
Definition masks.h:309
@ DT_MASKS_INTERACTION_UNDEF
Definition masks.h:304
@ DT_MASKS_INTERACTION_ROTATION
Definition masks.h:308
int dt_masks_group_index_from_formid(const dt_masks_form_t *group_form, int formid)
void _masks_gui_delete_node_callback(GtkWidget *menu, gpointer user_data)
Definition masks_gui.c:541
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:617
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:771
static gboolean dt_masks_center_of_gravity_from_points(const float *points, const int points_count, float center[2], float *area)
Definition masks.h:1373
dt_masks_ellipse_flags_t
Definition masks.h:218
@ DT_MASKS_ELLIPSE_PROPORTIONAL
Definition masks.h:220
@ DT_MASKS_ELLIPSE_EQUIDISTANT
Definition masks.h:219
int dt_masks_events_mouse_leave(struct dt_iop_module_t *module)
void dt_masks_form_invalidate_gravity_center(struct dt_masks_form_t *form)
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:974
static size_t dt_masks_dynbuf_position(dt_masks_dynbuf_t *a)
Definition masks.h:1444
gboolean dt_masks_gui_is_dragging(const dt_masks_form_gui_t *gui)
gboolean dt_masks_remove_shape_from_group(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id, dt_masks_form_gui_t *mask_gui, int form_id)
Remove the form from its current group only, keeping it around unused for potential reuse....
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:821
dt_masks_source_pos_type_t
Definition masks.h:224
@ DT_MASKS_SOURCE_POS_RELATIVE_TEMP
Definition masks.h:226
@ DT_MASKS_SOURCE_POS_RELATIVE
Definition masks.h:225
@ DT_MASKS_SOURCE_POS_ABSOLUTE
Definition masks.h:227
static gboolean dt_masks_gui_was_anything_selected(const dt_masks_form_gui_t *gui)
Definition masks.h:543
int dt_masks_gui_confirm_delete_form_dialog(const char *form_name)
Definition masks_gui.c:440
const dt_masks_functions_t dt_masks_functions_polygon
Definition polygon.c:3655
static gboolean dt_masks_gui_change_affects_selected_node_or_all(const dt_masks_form_gui_t *gui, const int index)
Definition masks.h:568
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:157
@ DT_MASKS_EVENT_NONE
Definition masks.h:158
@ DT_MASKS_EVENT_UPDATE
Definition masks.h:161
@ DT_MASKS_EVENT_RESET
Definition masks.h:164
@ DT_MASKS_EVENT_ADD
Definition masks.h:159
@ DT_MASKS_EVENT_DELETE
Definition masks.h:162
@ DT_MASKS_EVENT_REMOVE
Definition masks.h:160
@ DT_MASKS_EVENT_CHANGE
Definition masks.h:163
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:601
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:640
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:655
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:949
@ DT_MASKS_SHAPE_BUTTONS_GRADIENT
Definition masks.h:961
@ DT_MASKS_SHAPE_BUTTONS_NONE
Definition masks.h:951
@ DT_MASKS_SHAPE_BUTTONS_CIRCLE
Definition masks.h:953
@ DT_MASKS_SHAPE_BUTTONS_BRUSH
Definition masks.h:959
@ DT_MASKS_SHAPE_BUTTONS_ALL
Definition masks.h:963
@ DT_MASKS_SHAPE_BUTTONS_ELLIPSE
Definition masks.h:955
@ DT_MASKS_SHAPE_BUTTONS_POLYGON
Definition masks.h:957
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:1329
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:194
@ DT_MASKS_INCREMENT_SCALE
Definition masks.h:196
@ DT_MASKS_INCREMENT_OFFSET
Definition masks.h:197
@ DT_MASKS_INCREMENT_ABSOLUTE
Definition masks.h:195
dt_masks_pressure_sensitivity_t
Definition masks.h:208
@ DT_MASKS_PRESSURE_OPACITY_REL
Definition masks.h:212
@ DT_MASKS_PRESSURE_OPACITY_ABS
Definition masks.h:213
@ DT_MASKS_PRESSURE_BRUSHSIZE_REL
Definition masks.h:214
@ DT_MASKS_PRESSURE_HARDNESS_REL
Definition masks.h:210
@ DT_MASKS_PRESSURE_OFF
Definition masks.h:209
@ DT_MASKS_PRESSURE_HARDNESS_ABS
Definition masks.h:211
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)
gboolean dt_masks_delete_shape(struct dt_iop_module_t *module, dt_masks_form_t *sel, int parent_id, dt_masks_form_gui_t *mask_gui, int form_id)
Permanently delete the form from every group and from dev->forms. Gated by dt_masks_gui_confirm_perma...
const dt_masks_functions_t dt_masks_functions_ellipse
Definition ellipse.c:1702
const dt_masks_functions_t dt_masks_functions_circle
Definition circle.c:1132
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
dt_masks_points_states_t
Definition masks.h:182
@ DT_MASKS_POINT_STATE_NORMAL
Definition masks.h:183
@ DT_MASKS_POINT_STATE_USER
Definition masks.h:184
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:867
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:657
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:876
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:746
dt_masks_gradient_states_t
Definition masks.h:188
@ DT_MASKS_GRADIENT_STATE_SIGMOIDAL
Definition masks.h:190
@ DT_MASKS_GRADIENT_STATE_LINEAR
Definition masks.h:189
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:1475
const dt_masks_functions_t dt_masks_functions_brush
static float * dt_masks_dynbuf_harvest(dt_masks_dynbuf_t *a)
Definition masks.h:1456
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:1515
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:787
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:1508
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:1358
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:724
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:625
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:650
const dt_masks_functions_t dt_masks_functions_gradient
Definition gradient.c:1526
static void dt_masks_dynbuf_reset(dt_masks_dynbuf_t *a)
Definition masks.h:1450
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:1466
static void dt_masks_reset_source(dt_masks_form_t *form)
Definition masks.h:660
static void dt_masks_set_ctrl_points(float ctrl1[2], float ctrl2[2], const float control_points[4])
Definition masks.h:683
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:788
struct dt_develop_t * dev
Definition imageop.h:333
Region of interest passed through the pixelpipe.
Definition imageop.h:72
dt_masks_gradient_states_t state
Definition masks.h:278
char tag[128]
Definition masks.h:433
float * buffer
Definition masks.h:432
gboolean rebuild_pending
Definition masks.h:512
gboolean node_selected
Definition masks.h:484
gboolean handle_border_selected
Definition masks.h:487
double last_rebuild_ts
Definition masks.h:510
gboolean border_toggling
Definition masks.h:502
dt_masks_dynbuf_t * guipoints_payload
Definition masks.h:449
gboolean source_selected
Definition masks.h:492
int handle_border_dragging
Definition masks.h:507
dt_masks_type_t creation_type
Definition masks.h:521
int creation_last_formid
Definition masks.h:525
int handle_border_hovered
Definition masks.h:482
gboolean source_dragging
Definition masks.h:500
dt_masks_edit_mode_t edit_mode
Definition masks.h:477
dt_iop_module_t * creation_module
Definition masks.h:519
gboolean creation_closing_form
Definition masks.h:518
uint64_t pipe_hash
Definition masks.h:531
GList * creation_formids
Definition masks.h:523
dt_masks_pressure_sensitivity_t pressure_sensitivity
Definition masks.h:527
gboolean seg_selected
Definition masks.h:486
gboolean form_dragging
Definition masks.h:499
gboolean gradient_toggling
Definition masks.h:503
gboolean creation
Definition masks.h:517
float pos_source[2]
Definition masks.h:475
dt_masks_type_t type
Definition masks.h:442
dt_masks_form_t * form_visible
Definition masks.h:444
gboolean form_selected
Definition masks.h:490
gboolean handle_selected
Definition masks.h:485
gboolean form_rotating
Definition masks.h:501
dt_masks_dynbuf_t * guipoints
Definition masks.h:449
float rel_pos[2]
Definition masks.h:461
gboolean border_selected
Definition masks.h:491
float last_rebuild_pos[2]
Definition masks.h:511
gboolean pivot_selected
Definition masks.h:493
float raw_pos[2]
Definition masks.h:465
float last_hit_test_pos[2]
Definition masks.h:515
float delta[2]
Definition masks.h:469
const dt_masks_functions_t * functions
Definition masks.h:381
dt_masks_type_t type
Definition masks.h:380
dt_atomic_int refcount
Definition masks.h:411
gboolean gravity_center_valid
Definition masks.h:396
float source[2]
Definition masks.h:387
char name[128]
Definition masks.h:403
GList * points
Definition masks.h:379
float gravity_center[2]
Definition masks.h:391
gboolean uses_bezier_points_layout
Definition masks.h:383
float(* get_interaction_value)(const struct dt_masks_form_t *form, dt_masks_interaction_t interaction)
Definition masks.h:346
gboolean(* get_gravity_center)(const struct dt_masks_form_t *form, float center[2], float *area)
Definition masks.h:345
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:360
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:326
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:364
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:334
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:342
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:367
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:353
void(* sanitize_config)(dt_masks_type_t type_flags)
Definition masks.h:317
void(* set_form_name)(struct dt_masks_form_t *const form, const size_t nb)
Definition masks.h:318
void(* duplicate_points)(struct dt_develop_t *const dev, struct dt_masks_form_t *base, struct dt_masks_form_t *dest)
Definition masks.h:321
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:373
int(* update_hover)(struct dt_masks_form_t *form, struct dt_masks_form_gui_t *gui, int index)
Definition masks.h:351
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:347
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:328
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:338
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:324
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:370
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:356
void(* initial_source_pos)(const float iwd, const float iht, float *x, float *y)
Definition masks.h:322
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:330
void(* post_expose)(cairo_t *cr, float zoom_scale, struct dt_masks_form_gui_t *gui, int index, int num_points)
Definition masks.h:368
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:319
void(* init_ctrl_points)(struct dt_masks_form_t *form)
Definition masks.h:372
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:267
dt_masks_ellipse_flags_t flags
Definition masks.h:245
dt_masks_points_states_t state
Definition masks.h:255
dt_iop_module_t * creation_module
Definition masks.h:980
dt_masks_shape_buttons_flags_t register_flags
Definition masks.h:985
dt_masks_shape_buttons_type_f form_type
Definition masks.h:989
dt_masks_shape_buttons_start_f can_start
Definition masks.h:988
dt_masks_shape_buttons_notify_f exited
Definition masks.h:991
dt_masks_shape_buttons_notify_f started
Definition masks.h:990
dt_iop_module_t * owner_module
Definition masks.h:979
dt_masks_shape_buttons_flags_t flags
Definition masks.h:984