ae830bb92b5b7333a1802278d412e9beb1bebc5d
[blender.git] / source / blender / editors / mask / mask_select.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) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mask/mask_select.c
29  *  \ingroup edmask
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_utildefines.h"
35 #include "BLI_listbase.h"
36 #include "BLI_math.h"
37
38 #include "BKE_context.h"
39 #include "BKE_curve.h"
40 #include "BKE_depsgraph.h"
41 #include "BKE_mask.h"
42
43 #include "DNA_mask_types.h"
44 #include "DNA_object_types.h"  /* SELECT */
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "ED_screen.h"
50 #include "ED_mask.h"
51 #include "ED_clip.h"
52
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55
56 #include "mask_intern.h"  /* own include */
57
58 int ED_mask_spline_select_check(MaskSplinePoint *points, int tot_point)
59 {
60         int i;
61
62         for (i = 0; i < tot_point; i++) {
63                 MaskSplinePoint *point = &points[i];
64
65                 if (MASKPOINT_ISSEL(point))
66                         return TRUE;
67         }
68
69         return FALSE;
70 }
71
72 int ED_mask_select_check(Mask *mask)
73 {
74         MaskObject *maskobj;
75
76         for (maskobj = mask->maskobjs.first; maskobj; maskobj = maskobj->next) {
77                 MaskSpline *spline;
78
79                 for (spline = maskobj->splines.first; spline; spline = spline->next) {
80                         if (ED_mask_spline_select_check(spline->points, spline->tot_point)) {
81                                 return TRUE;
82                         }
83                 }
84         }
85
86         return FALSE;
87 }
88
89 void ED_mask_select_toggle_all(Mask *mask, int action)
90 {
91         MaskObject *maskobj;
92
93         if (action == SEL_TOGGLE) {
94                 if (ED_mask_select_check(mask))
95                         action = SEL_DESELECT;
96                 else
97                         action = SEL_SELECT;
98         }
99
100         for (maskobj = mask->maskobjs.first; maskobj; maskobj = maskobj->next) {
101                 MaskSpline *spline;
102
103                 for (spline = maskobj->splines.first; spline; spline = spline->next) {
104                         int i;
105
106                         for (i = 0; i < spline->tot_point; i++) {
107                                 MaskSplinePoint *point = &spline->points[i];
108
109                                 BKE_mask_point_select_set(point, (action == SEL_SELECT) ? TRUE : FALSE);
110                         }
111                 }
112         }
113 }
114
115 void ED_mask_select_flush_all(Mask *mask)
116 {
117         MaskObject *maskobj;
118
119         for (maskobj = mask->maskobjs.first; maskobj; maskobj = maskobj->next) {
120                 MaskSpline *spline;
121
122                 for (spline = maskobj->splines.first; spline; spline = spline->next) {
123                         int i;
124
125                         spline->flag &= ~SELECT;
126
127                         for (i = 0; i < spline->tot_point; i++) {
128                                 MaskSplinePoint *cur_point = &spline->points[i];
129
130                                 if (MASKPOINT_ISSEL(cur_point)) {
131                                         spline->flag |= SELECT;
132                                 }
133                                 else {
134                                         int j;
135
136                                         for (j = 0; j < cur_point->tot_uw; j++) {
137                                                 if (cur_point->uw[j].flag & SELECT) {
138                                                         spline->flag |= SELECT;
139                                                         break;
140                                                 }
141                                         }
142                                 }
143                         }
144                 }
145         }
146 }
147
148 /******************** toggle selection *********************/
149
150 static int select_all_exec(bContext *C, wmOperator *op)
151 {
152         Mask *mask = CTX_data_edit_mask(C);
153         int action = RNA_enum_get(op->ptr, "action");
154
155         ED_mask_select_toggle_all(mask, action);
156         ED_mask_select_flush_all(mask);
157
158         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
159
160         return OPERATOR_FINISHED;
161 }
162
163 void MASK_OT_select_all(wmOperatorType *ot)
164 {
165         /* identifiers */
166         ot->name = "Select or Deselect All";
167         ot->description = "Change selection of all curve points";
168         ot->idname = "MASK_OT_select_all";
169
170         /* api callbacks */
171         ot->exec = select_all_exec;
172         ot->poll = ED_maskediting_mask_poll;
173
174         /* flags */
175         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
176
177         /* properties */
178         WM_operator_properties_select_all(ot);
179 }
180
181 /******************** select *********************/
182
183 static int select_exec(bContext *C, wmOperator *op)
184 {
185         Mask *mask = CTX_data_edit_mask(C);
186         MaskObject *maskobj;
187         MaskSpline *spline;
188         MaskSplinePoint *point = NULL;
189         float co[2];
190         short extend = RNA_boolean_get(op->ptr, "extend");
191         short deselect = RNA_boolean_get(op->ptr, "deselect");
192         short toggle = RNA_boolean_get(op->ptr, "toggle");
193
194         int is_handle = 0;
195         const float threshold = 19;
196
197         RNA_float_get_array(op->ptr, "location", co);
198
199         point = ED_mask_point_find_nearest(C, mask, co, threshold, &maskobj, &spline, &is_handle, NULL);
200
201         if (point) {
202                 if (extend == 0 && deselect == 0 && toggle == 0)
203                         ED_mask_select_toggle_all(mask, SEL_DESELECT);
204
205                 if (is_handle) {
206                         if (extend) {
207                                 maskobj->act_spline = spline;
208                                 maskobj->act_point = point;
209
210                                 BKE_mask_point_select_set_handle(point, TRUE);
211                         }
212                         else if (deselect) {
213                                 BKE_mask_point_select_set_handle(point, FALSE);
214                         }
215                         else {
216                                 maskobj->act_spline = spline;
217                                 maskobj->act_point = point;
218
219                                 if (!MASKPOINT_HANDLE_ISSEL(point)) {
220                                         BKE_mask_point_select_set_handle(point, TRUE);
221                                 }
222                                 else if (toggle) {
223                                         BKE_mask_point_select_set_handle(point, FALSE);
224                                 }
225                         }
226                 }
227                 else {
228                         if (extend) {
229                                 maskobj->act_spline = spline;
230                                 maskobj->act_point = point;
231
232                                 BKE_mask_point_select_set(point, TRUE);
233                         }
234                         else if (deselect) {
235                                 BKE_mask_point_select_set(point, FALSE);
236                         }
237                         else {
238                                 maskobj->act_spline = spline;
239                                 maskobj->act_point = point;
240
241                                 if (!MASKPOINT_ISSEL(point)) {
242                                         BKE_mask_point_select_set(point, TRUE);
243                                 }
244                                 else if (toggle) {
245                                         BKE_mask_point_select_set(point, FALSE);
246                                 }
247                         }
248                 }
249
250                 maskobj->act_spline = spline;
251                 maskobj->act_point = point;
252
253                 ED_mask_select_flush_all(mask);
254
255                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
256
257                 return OPERATOR_FINISHED;
258         }
259         else {
260                 MaskSplinePointUW *uw;
261
262                 if (ED_mask_feather_find_nearest(C, mask, co, threshold, &maskobj, &spline, &point, &uw, NULL)) {
263                         if (!extend)
264                                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
265
266                         if (uw)
267                                 uw->flag |= SELECT;
268
269                         maskobj->act_spline = spline;
270                         maskobj->act_point = point;
271
272                         ED_mask_select_flush_all(mask);
273
274                         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
275
276                         return OPERATOR_FINISHED;
277                 }
278         }
279
280         return OPERATOR_PASS_THROUGH;
281 }
282
283 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
284 {
285         float co[2];
286
287         ED_mask_mouse_pos(C, event, co);
288
289         RNA_float_set_array(op->ptr, "location", co);
290
291         return select_exec(C, op);
292 }
293
294 void MASK_OT_select(wmOperatorType *ot)
295 {
296         /* identifiers */
297         ot->name = "Select";
298         ot->description = "Select spline points";
299         ot->idname = "MASK_OT_select";
300
301         /* api callbacks */
302         ot->exec = select_exec;
303         ot->invoke = select_invoke;
304         ot->poll = ED_maskediting_mask_poll;
305
306         /* flags */
307         ot->flag = OPTYPE_UNDO;
308
309         /* properties */
310         WM_operator_properties_mouse_select(ot);
311
312         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
313                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
314 }