GPencil: H/Shift-H/Alt-H now work to Hide and Reveal Layers in Strokes Edit Mode
[blender.git] / source / blender / editors / gpencil / gpencil_data.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, Joshua Leung
19  * This is a new part of Blender
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * Operators for dealing with GP datablocks and layers
26  */
27
28 /** \file blender/editors/gpencil/gpencil_data.c
29  *  \ingroup edgpencil
30  */
31
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stddef.h>
37 #include <math.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_utildefines.h"
43
44 #include "BLF_translation.h"
45
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_view3d_types.h"
50 #include "DNA_gpencil_types.h"
51
52 #include "BKE_context.h"
53 #include "BKE_global.h"
54 #include "BKE_gpencil.h"
55 #include "BKE_library.h"
56 #include "BKE_object.h"
57 #include "BKE_report.h"
58 #include "BKE_scene.h"
59 #include "BKE_screen.h"
60
61 #include "UI_interface.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68
69 #include "ED_gpencil.h"
70
71 #include "gpencil_intern.h"
72
73
74 /* ************************************************ */
75 /* Datablock Operators */
76
77 /* ******************* Add New Data ************************ */
78
79 /* add new datablock - wrapper around API */
80 static int gp_data_add_exec(bContext *C, wmOperator *op)
81 {
82         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
83         
84         if (gpd_ptr == NULL) {
85                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
86                 return OPERATOR_CANCELLED;
87         }
88         else {
89                 /* decrement user count and add new datablock */
90                 bGPdata *gpd = (*gpd_ptr);
91                 
92                 id_us_min(&gpd->id);
93                 *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
94         }
95         
96         /* notifiers */
97         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
98         
99         return OPERATOR_FINISHED;
100 }
101
102 void GPENCIL_OT_data_add(wmOperatorType *ot)
103 {
104         /* identifiers */
105         ot->name = "Grease Pencil Add New";
106         ot->idname = "GPENCIL_OT_data_add";
107         ot->description = "Add new Grease Pencil datablock";
108         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
109         
110         /* callbacks */
111         ot->exec = gp_data_add_exec;
112         ot->poll = gp_add_poll;
113 }
114
115 /* ******************* Unlink Data ************************ */
116
117 /* poll callback for adding data/layers - special */
118 static int gp_data_unlink_poll(bContext *C)
119 {
120         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
121         
122         /* if we have access to some active data, make sure there's a datablock before enabling this */
123         return (gpd_ptr && *gpd_ptr);
124 }
125
126
127 /* unlink datablock - wrapper around API */
128 static int gp_data_unlink_exec(bContext *C, wmOperator *op)
129 {
130         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
131         
132         if (gpd_ptr == NULL) {
133                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
134                 return OPERATOR_CANCELLED;
135         }
136         else {
137                 /* just unlink datablock now, decreasing its user count */
138                 bGPdata *gpd = (*gpd_ptr);
139
140                 id_us_min(&gpd->id);
141                 *gpd_ptr = NULL;
142         }
143         
144         /* notifiers */
145         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
146         
147         return OPERATOR_FINISHED;
148 }
149
150 void GPENCIL_OT_data_unlink(wmOperatorType *ot)
151 {
152         /* identifiers */
153         ot->name = "Grease Pencil Unlink";
154         ot->idname = "GPENCIL_OT_data_unlink";
155         ot->description = "Unlink active Grease Pencil datablock";
156         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
157         
158         /* callbacks */
159         ot->exec = gp_data_unlink_exec;
160         ot->poll = gp_data_unlink_poll;
161 }
162
163
164 /* ************************************************ */
165 /* Layer Operators */
166
167 /* ******************* Add New Layer ************************ */
168
169 /* add new layer - wrapper around API */
170 static int gp_layer_add_exec(bContext *C, wmOperator *op)
171 {
172         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
173         
174         /* if there's no existing Grease-Pencil data there, add some */
175         if (gpd_ptr == NULL) {
176                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
177                 return OPERATOR_CANCELLED;
178         }
179         if (*gpd_ptr == NULL)
180                 *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
181         
182         /* add new layer now */
183         gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
184         
185         /* notifiers */
186         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
187         
188         return OPERATOR_FINISHED;
189 }
190
191 void GPENCIL_OT_layer_add(wmOperatorType *ot)
192 {
193         /* identifiers */
194         ot->name = "Add New Layer";
195         ot->idname = "GPENCIL_OT_layer_add";
196         ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
197         
198         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
199         
200         /* callbacks */
201         ot->exec = gp_layer_add_exec;
202         ot->poll = gp_add_poll;
203 }
204
205 /* ******************* Remove Active Layer ************************* */
206
207 static int gp_layer_remove_exec(bContext *C, wmOperator *op)
208 {
209         bGPdata *gpd = ED_gpencil_data_get_active(C);
210         bGPDlayer *gpl = gpencil_layer_getactive(gpd);
211         
212         /* sanity checks */
213         if (ELEM(NULL, gpd, gpl))
214                 return OPERATOR_CANCELLED;
215         
216         if (gpl->flag & GP_LAYER_LOCKED) {
217                 BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
218                 return OPERATOR_CANCELLED;
219         }
220         
221         /* make the layer before this the new active layer
222          * - use the one after if this is the first
223          * - if this is the only layer, this naturally becomes NULL
224          */
225         if (gpl->prev)
226                 gpencil_layer_setactive(gpd, gpl->prev);
227         else
228                 gpencil_layer_setactive(gpd, gpl->next);
229         
230         /* delete the layer now... */
231         gpencil_layer_delete(gpd, gpl);
232         
233         /* notifiers */
234         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
235         
236         return OPERATOR_FINISHED;
237 }
238
239 void GPENCIL_OT_layer_remove(wmOperatorType *ot)
240 {
241         /* identifiers */
242         ot->name = "Remove Layer";
243         ot->idname = "GPENCIL_OT_layer_remove";
244         ot->description = "Remove active Grease Pencil layer";
245         
246         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
247         
248         /* callbacks */
249         ot->exec = gp_layer_remove_exec;
250         ot->poll = gp_active_layer_poll;
251 }
252
253 /* ******************* Move Layer Up/Down ************************** */
254
255 enum {
256         GP_LAYER_MOVE_UP   = -1,
257         GP_LAYER_MOVE_DOWN = 1
258 };
259
260 static int gp_layer_move_exec(bContext *C, wmOperator *op)
261 {
262         bGPdata *gpd = ED_gpencil_data_get_active(C);
263         bGPDlayer *gpl = gpencil_layer_getactive(gpd);
264         
265         int direction = RNA_enum_get(op->ptr, "type");
266         
267         /* sanity checks */
268         if (ELEM(NULL, gpd, gpl))
269                 return OPERATOR_CANCELLED;
270         
271         /* up or down? */
272         if (direction == GP_LAYER_MOVE_UP) {
273                 /* up */
274                 BLI_remlink(&gpd->layers, gpl);
275                 BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
276         }
277         else {
278                 /* down */
279                 BLI_remlink(&gpd->layers, gpl);
280                 BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
281         }
282         
283         /* notifiers */
284         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
285         
286         return OPERATOR_FINISHED;
287 }
288
289 void GPENCIL_OT_layer_move(wmOperatorType *ot)
290 {
291         static EnumPropertyItem slot_move[] = {
292                 {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
293                 {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
294                 {0, NULL, 0, NULL, NULL}
295         };
296         
297         /* identifiers */
298         ot->name = "Move Grease Pencil Layer";
299         ot->idname = "GPENCIL_OT_layer_move";
300         ot->description = "Move the active Grease Pencil layer up/down in the list";
301         
302         /* api callbacks */
303         ot->exec = gp_layer_move_exec;
304         ot->poll = gp_active_layer_poll;
305         
306         /* flags */
307         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
308         
309         ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
310 }
311
312 /* ********************* Duplicate Layer ************************** */
313
314 static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
315 {
316         bGPdata *gpd = ED_gpencil_data_get_active(C);
317         bGPDlayer *gpl = gpencil_layer_getactive(gpd);
318         bGPDlayer *new_layer;
319         
320         /* sanity checks */
321         if (ELEM(NULL, gpd, gpl))
322                 return OPERATOR_CANCELLED;
323         
324         /* make copy of layer, and add it immediately after the existing layer */
325         new_layer = gpencil_layer_duplicate(gpl);
326         BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
327         
328         /* ensure new layer has a unique name, and is now the active layer */
329         BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
330         gpencil_layer_setactive(gpd, new_layer);
331         
332         /* notifiers */
333         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
334         
335         return OPERATOR_FINISHED;
336 }
337
338 void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
339 {
340         /* identifiers */
341         ot->name = "Duplicate Layer";
342         ot->idname = "GPENCIL_OT_layer_duplicate";
343         ot->description = "Make a copy of the active Grease Pencil layer";
344         
345         /* callbacks */
346         ot->exec = gp_layer_copy_exec;
347         ot->poll = gp_active_layer_poll;
348         
349         /* flags */
350         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
351 }
352
353 /* *********************** Hide Layers ******************************** */
354
355 static int gp_hide_exec(bContext *C, wmOperator *op)
356 {
357         bGPdata *gpd = ED_gpencil_data_get_active(C);
358         bGPDlayer *layer = gpencil_layer_getactive(gpd);
359         bool unselected = RNA_boolean_get(op->ptr, "unselected");
360         
361         /* sanity checks */
362         if (ELEM(NULL, gpd, layer))
363                 return OPERATOR_CANCELLED;
364         
365         if (unselected) {
366                 bGPDlayer *gpl;
367                 
368                 /* hide unselected */
369                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
370                         if (gpl != layer) {
371                                 gpl->flag |= GP_LAYER_HIDE;
372                         }
373                 }
374         }
375         else {
376                 /* hide selected/active */
377                 layer->flag |= GP_LAYER_HIDE;
378         }
379         
380         /* notifiers */
381         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
382         
383         return OPERATOR_FINISHED;
384 }
385
386 void GPENCIL_OT_hide(wmOperatorType *ot)
387 {
388         /* identifiers */
389         ot->name = "Hide Layer(s)";
390         ot->idname = "GPENCIL_OT_hide";
391         ot->description = "Hide selected/unselected Grease Pencil layers";
392         
393         /* callbacks */
394         ot->exec = gp_hide_exec;
395         ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
396         
397         /* flags */
398         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
399         
400         /* props */
401         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
402 }
403
404 /* ********************** Show All Layers ***************************** */
405
406 /* poll callback for showing layers */
407 static int gp_reveal_poll(bContext *C)
408 {
409         return ED_gpencil_data_get_active(C) != NULL;
410 }
411
412 static int gp_reveal_exec(bContext *C, wmOperator *UNUSED(op))
413 {
414         bGPdata *gpd = ED_gpencil_data_get_active(C);
415         bGPDlayer *gpl;
416         
417         /* sanity checks */
418         if (gpd == NULL)
419                 return OPERATOR_CANCELLED;
420         
421         /* make all layers visible */
422         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
423                 gpl->flag &= ~GP_LAYER_HIDE;
424         }
425         
426         /* notifiers */
427         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
428         
429         return OPERATOR_FINISHED;
430 }
431
432 void GPENCIL_OT_reveal(wmOperatorType *ot)
433 {
434         /* identifiers */
435         ot->name = "Show All Layers";
436         ot->idname = "GPENCIL_OT_reveal";
437         ot->description = "Show all Grease Pencil layers";
438         
439         /* callbacks */
440         ot->exec = gp_reveal_exec;
441         ot->poll = gp_reveal_poll;
442         
443         /* flags */
444         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
445 }
446
447 /* ************************************************ */