Blender V5.0
mask_editaction.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_listbase.h"
17#include "BLI_utildefines.h"
18
19#include "DNA_mask_types.h"
20#include "DNA_scene_types.h"
21
22#include "BKE_mask.h"
23
24#include "ED_keyframes_edit.hh"
25#include "ED_markers.hh"
26#include "ED_mask.hh" /* own include */
27
28/* ***************************************** */
29/* NOTE ABOUT THIS FILE:
30 * This file contains code for editing Mask data in the Action Editor
31 * as a 'keyframes', so that a user can adjust the timing of Mask shape-keys.
32 * Therefore, this file mostly contains functions for selecting Mask frames (shape-keys).
33 */
34/* ***************************************** */
35/* Generics - Loopers */
36
38 Scene *scene,
39 bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
40{
41 /* error checker */
42 if (mask_layer == nullptr) {
43 return false;
44 }
45
46 /* do loop */
47 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
48 /* execute callback */
49 if (mask_layer_shape_cb(mask_layer_shape, scene)) {
50 return true;
51 }
52 }
53
54 /* nothing to return */
55 return false;
56}
57
58/* ****************************************** */
59/* Data Conversion Tools */
60
61void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
62{
63
64 /* error checking */
65 if (ELEM(nullptr, mask_layer, elems)) {
66 return;
67 }
68
69 /* loop through mask-frames, adding */
70 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
71 if ((onlysel == false) || (mask_layer_shape->flag & MASK_SHAPE_SELECT)) {
72 CfraElem *ce = MEM_callocN<CfraElem>("CfraElem");
73
74 ce->cfra = float(mask_layer_shape->frame);
75 ce->sel = (mask_layer_shape->flag & MASK_SHAPE_SELECT) ? 1 : 0;
76
77 BLI_addtail(elems, ce);
78 }
79 }
80}
81
82/* ***************************************** */
83/* Selection Tools */
84
86{
87 /* error checking */
88 if (mask_layer == nullptr) {
89 return false;
90 }
91
92 /* stop at the first one found */
93 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
94 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
95 return true;
96 }
97 }
98
99 /* not found */
100 return false;
101}
102
103/* helper function - select mask-frame based on SELECT_* mode */
104static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short select_mode)
105{
106 if (mask_layer_shape == nullptr) {
107 return;
108 }
109
110 switch (select_mode) {
111 case SELECT_ADD:
112 mask_layer_shape->flag |= MASK_SHAPE_SELECT;
113 break;
114 case SELECT_SUBTRACT:
115 mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
116 break;
117 case SELECT_INVERT:
118 mask_layer_shape->flag ^= MASK_SHAPE_SELECT;
119 break;
120 }
121}
122
123void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
124{
125 /* error checking */
126 if (mask_layer == nullptr) {
127 return;
128 }
129
130 /* handle according to mode */
131 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
132 mask_layer_shape_select(mask_layer_shape, select_mode);
133 }
134}
135
136void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
137{
138 /* error checking */
139 if (mask_layer == nullptr) {
140 return;
141 }
142
143 /* now call the standard function */
144 ED_mask_select_frames(mask_layer, mode);
145}
146
147void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
148{
149 MaskLayerShape *mask_layer_shape;
150
151 if (mask_layer == nullptr) {
152 return;
153 }
154
155 mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, selx);
156
157 if (mask_layer_shape) {
158 mask_layer_shape_select(mask_layer_shape, select_mode);
159 }
160}
161
162void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
163{
164 if (mask_layer == nullptr) {
165 return;
166 }
167
168 /* only select those frames which are in bounds */
169 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
170 if (IN_RANGE(mask_layer_shape->frame, min, max)) {
171 mask_layer_shape_select(mask_layer_shape, select_mode);
172 }
173 }
174}
175
177 MaskLayer *mask_layer,
178 short tool,
179 short select_mode)
180{
181 if (mask_layer == nullptr) {
182 return;
183 }
184
185 /* only select frames which are within the region */
186 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
187 /* construct a dummy point coordinate to do this testing with */
188 float pt[2] = {0};
189
190 pt[0] = mask_layer_shape->frame;
191 pt[1] = ked->channel_y;
192
193 /* check the necessary regions */
194 if (tool == BEZT_OK_CHANNEL_LASSO) {
195 /* Lasso */
196 if (keyframe_region_lasso_test(static_cast<KeyframeEdit_LassoData *>(ked->data), pt)) {
197 mask_layer_shape_select(mask_layer_shape, select_mode);
198 }
199 }
200 else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
201 /* Circle */
202 if (keyframe_region_circle_test(static_cast<KeyframeEdit_CircleData *>(ked->data), pt)) {
203 mask_layer_shape_select(mask_layer_shape, select_mode);
204 }
205 }
206 }
207}
208
209/* ***************************************** */
210/* Frame Editing Tools */
211
213{
214 bool changed = false;
215
216 /* error checking */
217 if (mask_layer == nullptr) {
218 return false;
219 }
220
221 /* check for frames to delete */
222 LISTBASE_FOREACH_MUTABLE (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
223 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
224 BKE_mask_layer_shape_unlink(mask_layer, mask_layer_shape);
225 changed = true;
226 }
227 }
228
229 return changed;
230}
231
233{
234 bool changed = false;
235
236 /* Error checking. */
237 if (mask_layer == nullptr) {
238 return changed;
239 }
240
241 /* Duplicate selected frames. */
242 LISTBASE_FOREACH_MUTABLE (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
243
244 /* Duplicate this frame. */
245 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
246 MaskLayerShape *mask_shape_dupe;
247
248 /* Duplicate frame, and deselect self. */
249 mask_shape_dupe = BKE_mask_layer_shape_duplicate(mask_layer_shape);
250 mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
251
252 /* XXX: how to handle duplicate frames? */
253 BLI_insertlinkafter(&mask_layer->splines_shapes, mask_layer_shape, mask_shape_dupe);
254 changed = true;
255 }
256 }
257
258 return changed;
259}
260
261/* -------------------------------------- */
262/* Snap Tools */
263
264static bool snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene * /*scene*/)
265{
266 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
267 mask_layer_shape->frame = int(floor(mask_layer_shape->frame + 0.5));
268 }
269 return false;
270}
271
272static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
273{
274 float secf = float(scene->frames_per_second());
275 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
276 mask_layer_shape->frame = int(floorf(mask_layer_shape->frame / secf + 0.5f) * secf);
277 }
278 return false;
279}
280
281static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
282{
283 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
284 mask_layer_shape->frame = scene->r.cfra;
285 }
286 return false;
287}
288
289static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
290{
291 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
292 mask_layer_shape->frame = ED_markers_find_nearest_marker_time(&scene->markers,
293 float(mask_layer_shape->frame));
294 }
295 return false;
296}
297
298void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
299{
300 switch (mode) {
301 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
303 break;
304 case SNAP_KEYS_CURFRAME: /* snap to current frame */
306 break;
307 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
309 break;
310 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
312 break;
313 default: /* just in case */
314 break;
315 }
316}
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
struct MaskLayerShape * BKE_mask_layer_shape_duplicate(struct MaskLayerShape *masklay_shape)
struct MaskLayerShape * BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, int frame)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
#define IN_RANGE(a, b, c)
#define ELEM(...)
@ MASK_SHAPE_SELECT
@ BEZT_OK_CHANNEL_CIRCLE
@ BEZT_OK_CHANNEL_LASSO
@ SNAP_KEYS_CURFRAME
@ SNAP_KEYS_NEARFRAME
@ SNAP_KEYS_NEARMARKER
@ SNAP_KEYS_NEARSEC
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_ADD
Read Guarded memory(de)allocation.
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
nullptr float
#define floor
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
static bool snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *)
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short select_mode)
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
bool ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *mask_layer, short tool, short select_mode)
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
bool ED_masklayer_frames_looper(MaskLayer *mask_layer, Scene *scene, bool(*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
#define floorf
#define min(a, b)
Definition sort.cc:36
ListBase splines_shapes
struct RenderData r
ListBase markers
max
Definition text_draw.cc:251