Merged changes in the trunk up to revision 50956.
[blender-staging.git] / source / blender / editors / mask / mask_editaction.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/mask/mask_editaction.c
27  *  \ingroup edgpencil
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <math.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "DNA_mask_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "BKE_fcurve.h"
47 #include "BKE_mask.h"
48
49 #include "ED_anim_api.h"
50 #include "ED_keyframes_edit.h"
51 #include "ED_mask.h"  /* own include */
52
53 /* ***************************************** */
54 /* NOTE ABOUT THIS FILE:
55  *  This file contains code for editing Grease Pencil data in the Action Editor
56  *  as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
57  *  Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
58  */
59 /* ***************************************** */
60 /* Generics - Loopers */
61
62 /* Loops over the gp-frames for a gp-layer, and applies the given callback */
63 short ED_masklayer_frames_looper(MaskLayer *masklay, Scene *scene, short (*masklay_shape_cb)(MaskLayerShape *, Scene *))
64 {
65         MaskLayerShape *masklay_shape;
66
67         /* error checker */
68         if (masklay == NULL)
69                 return 0;
70
71         /* do loop */
72         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
73                 /* execute callback */
74                 if (masklay_shape_cb(masklay_shape, scene))
75                         return 1;
76         }
77
78         /* nothing to return */
79         return 0;
80 }
81
82 /* ****************************************** */
83 /* Data Conversion Tools */
84
85 /* make a listing all the gp-frames in a layer as cfraelems */
86 void ED_masklayer_make_cfra_list(MaskLayer *masklay, ListBase *elems, short onlysel)
87 {
88         MaskLayerShape *masklay_shape;
89         CfraElem *ce;
90
91         /* error checking */
92         if (ELEM(NULL, masklay, elems))
93                 return;
94
95         /* loop through gp-frames, adding */
96         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
97                 if ((onlysel == 0) || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
98                         ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
99
100                         ce->cfra = (float)masklay_shape->frame;
101                         ce->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? 1 : 0;
102
103                         BLI_addtail(elems, ce);
104                 }
105         }
106 }
107
108 /* ***************************************** */
109 /* Selection Tools */
110
111 /* check if one of the frames in this layer is selected */
112 short ED_masklayer_frame_select_check(MaskLayer *masklay)
113 {
114         MaskLayerShape *masklay_shape;
115
116         /* error checking */
117         if (masklay == NULL)
118                 return 0;
119
120         /* stop at the first one found */
121         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
122                 if (masklay_shape->flag & MASK_SHAPE_SELECT)
123                         return 1;
124         }
125
126         /* not found */
127         return 0;
128 }
129
130 /* helper function - select gp-frame based on SELECT_* mode */
131 static void masklayshape_select(MaskLayerShape *masklay_shape, short select_mode)
132 {
133         if (masklay_shape == NULL)
134                 return;
135
136         switch (select_mode) {
137                 case SELECT_ADD:
138                         masklay_shape->flag |= MASK_SHAPE_SELECT;
139                         break;
140                 case SELECT_SUBTRACT:
141                         masklay_shape->flag &= ~MASK_SHAPE_SELECT;
142                         break;
143                 case SELECT_INVERT:
144                         masklay_shape->flag ^= MASK_SHAPE_SELECT;
145                         break;
146         }
147 }
148
149 /* set all/none/invert select (like above, but with SELECT_* modes) */
150 void ED_mask_select_frames(MaskLayer *masklay, short select_mode)
151 {
152         MaskLayerShape *masklay_shape;
153
154         /* error checking */
155         if (masklay == NULL)
156                 return;
157
158         /* handle according to mode */
159         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
160                 masklayshape_select(masklay_shape, select_mode);
161         }
162 }
163
164 /* set all/none/invert select */
165 void ED_masklayer_frame_select_set(MaskLayer *masklay, short mode)
166 {
167         /* error checking */
168         if (masklay == NULL)
169                 return;
170
171         /* now call the standard function */
172         ED_mask_select_frames(masklay, mode);
173 }
174
175 /* select the frame in this layer that occurs on this frame (there should only be one at most) */
176 void ED_mask_select_frame(MaskLayer *masklay, int selx, short select_mode)
177 {
178         MaskLayerShape *masklay_shape;
179
180         if (masklay == NULL)
181                 return;
182
183         masklay_shape = BKE_mask_layer_shape_find_frame(masklay, selx);
184
185         if (masklay_shape) {
186                 masklayshape_select(masklay_shape, select_mode);
187         }
188 }
189
190 /* select the frames in this layer that occur within the bounds specified */
191 void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, short select_mode)
192 {
193         MaskLayerShape *masklay_shape;
194
195         if (masklay == NULL)
196                 return;
197
198         /* only select those frames which are in bounds */
199         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
200                 if (IN_RANGE(masklay_shape->frame, min, max))
201                         masklayshape_select(masklay_shape, select_mode);
202         }
203 }
204
205 /* ***************************************** */
206 /* Frame Editing Tools */
207
208 /* Delete selected frames */
209 void ED_masklayer_frames_delete(MaskLayer *masklay)
210 {
211         MaskLayerShape *masklay_shape, *masklay_shape_next;
212
213         /* error checking */
214         if (masklay == NULL)
215                 return;
216
217         /* check for frames to delete */
218         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape_next) {
219                 masklay_shape_next = masklay_shape->next;
220
221                 if (masklay_shape->flag & MASK_SHAPE_SELECT)
222                         BKE_mask_layer_shape_unlink(masklay, masklay_shape);
223         }
224 }
225
226 /* Duplicate selected frames from given gp-layer */
227 void ED_masklayer_frames_duplicate(MaskLayer *masklay)
228 {
229         MaskLayerShape *masklay_shape, *gpfn;
230
231         /* error checking */
232         if (masklay == NULL)
233                 return;
234
235         /* duplicate selected frames  */
236         for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = gpfn) {
237                 gpfn = masklay_shape->next;
238
239                 /* duplicate this frame */
240                 if (masklay_shape->flag & MASK_SHAPE_SELECT) {
241                         MaskLayerShape *mask_shape_dupe;
242
243                         /* duplicate frame, and deselect self */
244                         mask_shape_dupe = BKE_mask_layer_shape_duplicate(masklay_shape);
245                         masklay_shape->flag &= ~MASK_SHAPE_SELECT;
246
247                         /* XXX - how to handle duplicate frames? */
248                         BLI_insertlinkafter(&masklay->splines_shapes, masklay_shape, mask_shape_dupe);
249                 }
250         }
251 }