Cleanup: Use const for RNA EnumPropertyItem args
[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, Antonio Vazquez
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 #include "BLI_ghash.h"
44 #include "BLI_math.h"
45 #include "BLI_string_utils.h"
46
47 #include "BLT_translation.h"
48
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_view3d_types.h"
53 #include "DNA_gpencil_types.h"
54
55 #include "BKE_context.h"
56 #include "BKE_global.h"
57 #include "BKE_gpencil.h"
58 #include "BKE_library.h"
59 #include "BKE_object.h"
60 #include "BKE_report.h"
61 #include "BKE_scene.h"
62 #include "BKE_screen.h"
63 #include "BKE_colortools.h"
64
65 #include "UI_interface.h"
66 #include "UI_resources.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73 #include "RNA_enum_types.h"
74
75 #include "ED_gpencil.h"
76
77 #include "gpencil_intern.h"
78
79 /* ************************************************ */
80 /* Datablock Operators */
81
82 /* ******************* Add New Data ************************ */
83
84 /* add new datablock - wrapper around API */
85 static int gp_data_add_exec(bContext *C, wmOperator *op)
86 {
87         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
88         ToolSettings *ts = CTX_data_tool_settings(C);
89
90         if (gpd_ptr == NULL) {
91                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
92                 return OPERATOR_CANCELLED;
93         }
94         else {
95                 /* decrement user count and add new datablock */
96                 bGPdata *gpd = (*gpd_ptr);
97                 
98                 id_us_min(&gpd->id);
99                 *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
100
101                 /* if not exist brushes, create a new set */
102                 if (ts) {
103                         if (BLI_listbase_is_empty(&ts->gp_brushes)) {
104                                 /* create new brushes */
105                                 BKE_gpencil_brush_init_presets(ts);
106                         }
107                 }
108
109         }
110         
111         /* notifiers */
112         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
113         
114         return OPERATOR_FINISHED;
115 }
116
117 void GPENCIL_OT_data_add(wmOperatorType *ot)
118 {
119         /* identifiers */
120         ot->name = "Grease Pencil Add New";
121         ot->idname = "GPENCIL_OT_data_add";
122         ot->description = "Add new Grease Pencil data-block";
123         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
124         
125         /* callbacks */
126         ot->exec = gp_data_add_exec;
127         ot->poll = gp_add_poll;
128 }
129
130 /* ******************* Unlink Data ************************ */
131
132 /* poll callback for adding data/layers - special */
133 static int gp_data_unlink_poll(bContext *C)
134 {
135         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
136         
137         /* if we have access to some active data, make sure there's a datablock before enabling this */
138         return (gpd_ptr && *gpd_ptr);
139 }
140
141
142 /* unlink datablock - wrapper around API */
143 static int gp_data_unlink_exec(bContext *C, wmOperator *op)
144 {
145         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
146         
147         if (gpd_ptr == NULL) {
148                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
149                 return OPERATOR_CANCELLED;
150         }
151         else {
152                 /* just unlink datablock now, decreasing its user count */
153                 bGPdata *gpd = (*gpd_ptr);
154
155                 id_us_min(&gpd->id);
156                 *gpd_ptr = NULL;
157         }
158         
159         /* notifiers */
160         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
161         
162         return OPERATOR_FINISHED;
163 }
164
165 void GPENCIL_OT_data_unlink(wmOperatorType *ot)
166 {
167         /* identifiers */
168         ot->name = "Grease Pencil Unlink";
169         ot->idname = "GPENCIL_OT_data_unlink";
170         ot->description = "Unlink active Grease Pencil data-block";
171         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
172         
173         /* callbacks */
174         ot->exec = gp_data_unlink_exec;
175         ot->poll = gp_data_unlink_poll;
176 }
177
178
179 /* ************************************************ */
180 /* Layer Operators */
181
182 /* ******************* Add New Layer ************************ */
183
184 /* add new layer - wrapper around API */
185 static int gp_layer_add_exec(bContext *C, wmOperator *op)
186 {
187         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
188         ToolSettings *ts = CTX_data_tool_settings(C);
189
190         /* if there's no existing Grease-Pencil data there, add some */
191         if (gpd_ptr == NULL) {
192                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
193                 return OPERATOR_CANCELLED;
194         }
195         if (*gpd_ptr == NULL)
196                 *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
197         
198         /* if not exist brushes, create a new set */
199         if (ts) {
200                 if (BLI_listbase_is_empty(&ts->gp_brushes)) {
201                         /* create new brushes */
202                         BKE_gpencil_brush_init_presets(ts);
203                 }
204         }
205
206         /* add new layer now */
207         BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
208         
209         /* notifiers */
210         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
211         
212         return OPERATOR_FINISHED;
213 }
214
215 void GPENCIL_OT_layer_add(wmOperatorType *ot)
216 {
217         /* identifiers */
218         ot->name = "Add New Layer";
219         ot->idname = "GPENCIL_OT_layer_add";
220         ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block";
221         
222         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
223         
224         /* callbacks */
225         ot->exec = gp_layer_add_exec;
226         ot->poll = gp_add_poll;
227 }
228
229 /* ******************* Remove Active Layer ************************* */
230
231 static int gp_layer_remove_exec(bContext *C, wmOperator *op)
232 {
233         bGPdata *gpd = ED_gpencil_data_get_active(C);
234         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
235         
236         /* sanity checks */
237         if (ELEM(NULL, gpd, gpl))
238                 return OPERATOR_CANCELLED;
239         
240         if (gpl->flag & GP_LAYER_LOCKED) {
241                 BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
242                 return OPERATOR_CANCELLED;
243         }
244         
245         /* make the layer before this the new active layer
246          * - use the one after if this is the first
247          * - if this is the only layer, this naturally becomes NULL
248          */
249         if (gpl->prev)
250                 BKE_gpencil_layer_setactive(gpd, gpl->prev);
251         else
252                 BKE_gpencil_layer_setactive(gpd, gpl->next);
253         
254         /* delete the layer now... */
255         BKE_gpencil_layer_delete(gpd, gpl);
256         
257         /* notifiers */
258         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
259         
260         return OPERATOR_FINISHED;
261 }
262
263 void GPENCIL_OT_layer_remove(wmOperatorType *ot)
264 {
265         /* identifiers */
266         ot->name = "Remove Layer";
267         ot->idname = "GPENCIL_OT_layer_remove";
268         ot->description = "Remove active Grease Pencil layer";
269         
270         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
271         
272         /* callbacks */
273         ot->exec = gp_layer_remove_exec;
274         ot->poll = gp_active_layer_poll;
275 }
276
277 /* ******************* Move Layer Up/Down ************************** */
278
279 enum {
280         GP_LAYER_MOVE_UP   = -1,
281         GP_LAYER_MOVE_DOWN = 1
282 };
283
284 static int gp_layer_move_exec(bContext *C, wmOperator *op)
285 {
286         bGPdata *gpd = ED_gpencil_data_get_active(C);
287         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
288         
289         int direction = RNA_enum_get(op->ptr, "type");
290         
291         /* sanity checks */
292         if (ELEM(NULL, gpd, gpl))
293                 return OPERATOR_CANCELLED;
294         
295         BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
296         if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
297                 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
298         }
299         
300         return OPERATOR_FINISHED;
301 }
302
303 void GPENCIL_OT_layer_move(wmOperatorType *ot)
304 {
305         static const EnumPropertyItem slot_move[] = {
306                 {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
307                 {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
308                 {0, NULL, 0, NULL, NULL}
309         };
310         
311         /* identifiers */
312         ot->name = "Move Grease Pencil Layer";
313         ot->idname = "GPENCIL_OT_layer_move";
314         ot->description = "Move the active Grease Pencil layer up/down in the list";
315         
316         /* api callbacks */
317         ot->exec = gp_layer_move_exec;
318         ot->poll = gp_active_layer_poll;
319         
320         /* flags */
321         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
322         
323         ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
324 }
325
326 /* ********************* Duplicate Layer ************************** */
327
328 static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
329 {
330         bGPdata *gpd = ED_gpencil_data_get_active(C);
331         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
332         bGPDlayer *new_layer;
333         
334         /* sanity checks */
335         if (ELEM(NULL, gpd, gpl))
336                 return OPERATOR_CANCELLED;
337         
338         /* make copy of layer, and add it immediately after the existing layer */
339         new_layer = BKE_gpencil_layer_duplicate(gpl);
340         BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
341         
342         /* ensure new layer has a unique name, and is now the active layer */
343         BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
344         BKE_gpencil_layer_setactive(gpd, new_layer);
345         
346         /* notifiers */
347         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
348         
349         return OPERATOR_FINISHED;
350 }
351
352 void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
353 {
354         /* identifiers */
355         ot->name = "Duplicate Layer";
356         ot->idname = "GPENCIL_OT_layer_duplicate";
357         ot->description = "Make a copy of the active Grease Pencil layer";
358         
359         /* callbacks */
360         ot->exec = gp_layer_copy_exec;
361         ot->poll = gp_active_layer_poll;
362         
363         /* flags */
364         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
365 }
366
367 /* *********************** Hide Layers ******************************** */
368
369 static int gp_hide_exec(bContext *C, wmOperator *op)
370 {
371         bGPdata *gpd = ED_gpencil_data_get_active(C);
372         bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
373         bool unselected = RNA_boolean_get(op->ptr, "unselected");
374         
375         /* sanity checks */
376         if (ELEM(NULL, gpd, layer))
377                 return OPERATOR_CANCELLED;
378         
379         if (unselected) {
380                 bGPDlayer *gpl;
381                 
382                 /* hide unselected */
383                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
384                         if (gpl != layer) {
385                                 gpl->flag |= GP_LAYER_HIDE;
386                         }
387                 }
388         }
389         else {
390                 /* hide selected/active */
391                 layer->flag |= GP_LAYER_HIDE;
392         }
393         
394         /* notifiers */
395         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
396         
397         return OPERATOR_FINISHED;
398 }
399
400 void GPENCIL_OT_hide(wmOperatorType *ot)
401 {
402         /* identifiers */
403         ot->name = "Hide Layer(s)";
404         ot->idname = "GPENCIL_OT_hide";
405         ot->description = "Hide selected/unselected Grease Pencil layers";
406         
407         /* callbacks */
408         ot->exec = gp_hide_exec;
409         ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
410         
411         /* flags */
412         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
413         
414         /* props */
415         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
416 }
417
418 /* ********************** Show All Layers ***************************** */
419
420 /* poll callback for showing layers */
421 static int gp_reveal_poll(bContext *C)
422 {
423         return ED_gpencil_data_get_active(C) != NULL;
424 }
425
426 static int gp_reveal_exec(bContext *C, wmOperator *UNUSED(op))
427 {
428         bGPdata *gpd = ED_gpencil_data_get_active(C);
429         bGPDlayer *gpl;
430         
431         /* sanity checks */
432         if (gpd == NULL)
433                 return OPERATOR_CANCELLED;
434         
435         /* make all layers visible */
436         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
437                 gpl->flag &= ~GP_LAYER_HIDE;
438         }
439         
440         /* notifiers */
441         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
442         
443         return OPERATOR_FINISHED;
444 }
445
446 void GPENCIL_OT_reveal(wmOperatorType *ot)
447 {
448         /* identifiers */
449         ot->name = "Show All Layers";
450         ot->idname = "GPENCIL_OT_reveal";
451         ot->description = "Show all Grease Pencil layers";
452         
453         /* callbacks */
454         ot->exec = gp_reveal_exec;
455         ot->poll = gp_reveal_poll;
456         
457         /* flags */
458         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
459 }
460
461 /* ***************** Lock/Unlock All Layers ************************ */
462
463 static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
464 {
465         bGPdata *gpd = ED_gpencil_data_get_active(C);
466         bGPDlayer *gpl;
467         
468         /* sanity checks */
469         if (gpd == NULL)
470                 return OPERATOR_CANCELLED;
471         
472         /* make all layers non-editable */
473         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
474                 gpl->flag |= GP_LAYER_LOCKED;
475         }
476         
477         /* notifiers */
478         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
479         
480         return OPERATOR_FINISHED;
481 }
482
483 void GPENCIL_OT_lock_all(wmOperatorType *ot)
484 {
485         /* identifiers */
486         ot->name = "Lock All Layers";
487         ot->idname = "GPENCIL_OT_lock_all";
488         ot->description = "Lock all Grease Pencil layers to prevent them from being accidentally modified";
489         
490         /* callbacks */
491         ot->exec = gp_lock_all_exec;
492         ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
493         
494         /* flags */
495         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
496 }
497
498 /* -------------------------- */
499
500 static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
501 {
502         bGPdata *gpd = ED_gpencil_data_get_active(C);
503         bGPDlayer *gpl;
504         
505         /* sanity checks */
506         if (gpd == NULL)
507                 return OPERATOR_CANCELLED;
508         
509         /* make all layers editable again */
510         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
511                 gpl->flag &= ~GP_LAYER_LOCKED;
512         }
513         
514         /* notifiers */
515         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
516         
517         return OPERATOR_FINISHED;
518 }
519
520 void GPENCIL_OT_unlock_all(wmOperatorType *ot)
521 {
522         /* identifiers */
523         ot->name = "Unlock All Layers";
524         ot->idname = "GPENCIL_OT_unlock_all";
525         ot->description = "Unlock all Grease Pencil layers so that they can be edited";
526         
527         /* callbacks */
528         ot->exec = gp_unlock_all_exec;
529         ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
530         
531         /* flags */
532         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
533 }
534
535 /* ********************** Isolate Layer **************************** */
536
537 static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
538 {
539         bGPdata *gpd = ED_gpencil_data_get_active(C);
540         bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
541         bGPDlayer *gpl;
542         int flags = GP_LAYER_LOCKED;
543         bool isolate = false;
544         
545         if (RNA_boolean_get(op->ptr, "affect_visibility"))
546                 flags |= GP_LAYER_HIDE;
547                 
548         if (ELEM(NULL, gpd, layer)) {
549                 BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
550                 return OPERATOR_CANCELLED;
551         }
552         
553         /* Test whether to isolate or clear all flags */
554         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
555                 /* Skip if this is the active layer */
556                 if (gpl == layer)
557                         continue;
558                 
559                 /* If the flags aren't set, that means that the layer is
560                  * not alone, so we have some layers to isolate still
561                  */
562                 if ((gpl->flag & flags) == 0) {
563                         isolate = true;
564                         break;
565                 }
566         }
567         
568         /* Set/Clear flags as appropriate */
569         /* TODO: Include onionskinning on this list? */
570         if (isolate) {
571                 /* Set flags on all "other" layers */
572                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
573                         if (gpl == layer)
574                                 continue;
575                         else
576                                 gpl->flag |= flags;
577                 }
578         }
579         else {
580                 /* Clear flags - Restore everything else */
581                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
582                         gpl->flag &= ~flags;
583                 }
584         }
585         
586         /* notifiers */
587         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
588         
589         return OPERATOR_FINISHED;
590 }
591
592 void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
593 {
594         /* identifiers */
595         ot->name = "Isolate Layer";
596         ot->idname = "GPENCIL_OT_layer_isolate";
597         ot->description = "Toggle whether the active layer is the only one that can be edited and/or visible";
598         
599         /* callbacks */
600         ot->exec = gp_isolate_layer_exec;
601         ot->poll = gp_active_layer_poll;
602         
603         /* flags */
604         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
605         
606         /* properties */
607         RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility",
608                         "In addition to toggling the editability, also affect the visibility");
609 }
610
611 /* ********************** Merge Layer with the next layer **************************** */
612
613 static int gp_merge_layer_exec(bContext *C, wmOperator *op)
614 {
615         bGPdata *gpd = ED_gpencil_data_get_active(C);
616         bGPDlayer *gpl_current = BKE_gpencil_layer_getactive(gpd);
617         bGPDlayer *gpl_next = gpl_current->next;
618
619         if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
620                 BKE_report(op->reports, RPT_ERROR, "No layers to merge");
621                 return OPERATOR_CANCELLED;
622         }
623
624         /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
625         GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
626         for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
627                 BLI_ghash_insert(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum), gpf);
628         }
629
630         /* read all frames from next layer */
631         for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
632                 /* try to find frame in active layer */
633                 bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum));
634                 if (!frame) {
635                         /* nothing found, create new */
636                         frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
637                 }
638                 /* add to tail all strokes */
639                 BLI_movelisttolist(&frame->strokes, &gpf->strokes);
640         }
641         /* Now delete next layer */
642         BKE_gpencil_layer_delete(gpd, gpl_next);
643         BLI_ghash_free(gh_frames_cur, NULL, NULL);
644
645         /* notifiers */
646         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
647
648         return OPERATOR_FINISHED;
649 }
650
651 void GPENCIL_OT_layer_merge(wmOperatorType *ot)
652 {
653         /* identifiers */
654         ot->name = "Merge Down";
655         ot->idname = "GPENCIL_OT_layer_merge";
656         ot->description = "Merge the current layer with the layer below";
657
658         /* callbacks */
659         ot->exec = gp_merge_layer_exec;
660         ot->poll = gp_active_layer_poll;
661
662         /* flags */
663         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
664 }
665
666 /* ********************** Change Layer ***************************** */
667
668 static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
669 {
670         uiPopupMenu *pup;
671         uiLayout *layout;
672         
673         /* call the menu, which will call this operator again, hence the canceled */
674         pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
675         layout = UI_popup_menu_layout(pup);
676         uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
677         UI_popup_menu_end(C, pup);
678         
679         return OPERATOR_INTERFACE;
680 }
681
682 static int gp_layer_change_exec(bContext *C, wmOperator *op)
683 {
684         bGPdata *gpd = CTX_data_gpencil_data(C);
685         bGPDlayer *gpl = NULL;
686         int layer_num = RNA_enum_get(op->ptr, "layer");
687         
688         /* Get layer or create new one */
689         if (layer_num == -1) {
690                 /* Create layer */
691                 gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
692         }
693         else {
694                 /* Try to get layer */
695                 gpl = BLI_findlink(&gpd->layers, layer_num);
696                 
697                 if (gpl == NULL) {
698                         BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
699                         return OPERATOR_CANCELLED;
700                 }
701         }
702         
703         /* Set active layer */
704         BKE_gpencil_layer_setactive(gpd, gpl);
705         
706         /* updates */
707         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
708         
709         return OPERATOR_FINISHED;
710 }
711
712 void GPENCIL_OT_layer_change(wmOperatorType *ot)
713 {
714         /* identifiers */
715         ot->name = "Change Layer";
716         ot->idname = "GPENCIL_OT_layer_change";
717         ot->description = "Change active Grease Pencil layer";
718         
719         /* callbacks */
720         ot->invoke = gp_layer_change_invoke;
721         ot->exec = gp_layer_change_exec;
722         ot->poll = gp_active_layer_poll;
723         
724         /* flags */
725         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
726         
727         /* gp layer to use (dynamic enum) */
728         ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
729         RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
730 }
731
732 /* ************************************************ */
733
734 /* ******************* Arrange Stroke Up/Down in drawing order ************************** */
735
736 enum {
737         GP_STROKE_MOVE_UP = -1,
738         GP_STROKE_MOVE_DOWN = 1,
739         GP_STROKE_MOVE_TOP = 2,
740         GP_STROKE_MOVE_BOTTOM = 3
741 };
742
743 static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
744 {
745         bGPdata *gpd = ED_gpencil_data_get_active(C);
746         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
747         bGPDstroke *gps;
748
749         /* sanity checks */
750         if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
751                 return OPERATOR_CANCELLED;
752         }
753
754         bGPDframe *gpf = gpl->actframe;
755         /* temp listbase to store selected strokes */
756         ListBase selected = {NULL};
757         const int direction = RNA_enum_get(op->ptr, "direction");
758
759         /* verify if any selected stroke is in the extreme of the stack and select to move */
760         for (gps = gpf->strokes.first; gps; gps = gps->next) {
761                 /* only if selected */
762                 if (gps->flag & GP_STROKE_SELECT) {
763                         /* skip strokes that are invalid for current view */
764                         if (ED_gpencil_stroke_can_use(C, gps) == false) {
765                                 continue;
766                         }
767                         /* check if the color is editable */
768                         if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
769                                 continue;
770                         }
771                         /* some stroke is already at front*/
772                         if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
773                                 if (gps == gpf->strokes.last) {
774                                         return OPERATOR_CANCELLED;
775                                 }
776                         }
777                         /* some stroke is already at botom */
778                         if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
779                                 if (gps == gpf->strokes.first) {
780                                         return OPERATOR_CANCELLED;
781                                 }
782                         }
783                         /* add to list */
784                         BLI_addtail(&selected, BLI_genericNodeN(gps));
785                 }
786         }
787
788         /* Now do the movement of the stroke */
789         switch (direction) {
790                 /* Bring to Front */
791                 case GP_STROKE_MOVE_TOP:
792                         for (LinkData *link = selected.first; link; link = link->next) {
793                                 gps = link->data;
794                                 BLI_remlink(&gpf->strokes, gps);
795                                 BLI_addtail(&gpf->strokes, gps);
796                         }
797                         break;
798                 /* Bring Forward */
799                 case GP_STROKE_MOVE_UP:
800                         for (LinkData *link = selected.last; link; link = link->prev) {
801                                 gps = link->data;
802                                 BLI_listbase_link_move(&gpf->strokes, gps, 1);
803                         }
804                         break;
805                 /* Send Backward */
806                 case GP_STROKE_MOVE_DOWN:
807                         for (LinkData *link = selected.first; link; link = link->next) {
808                                 gps = link->data;
809                                 BLI_listbase_link_move(&gpf->strokes, gps, -1);
810                         }
811                         break;
812                 /* Send to Back */
813                 case GP_STROKE_MOVE_BOTTOM:
814                         for (LinkData *link = selected.last; link; link = link->prev) {
815                                 gps = link->data;
816                                 BLI_remlink(&gpf->strokes, gps);
817                                 BLI_addhead(&gpf->strokes, gps);
818                         }
819                         break;
820                 default:
821                         BLI_assert(0);
822                         break;
823         }
824         BLI_freelistN(&selected);
825
826         /* notifiers */
827         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
828
829         return OPERATOR_FINISHED;
830 }
831
832 void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
833 {
834         static const EnumPropertyItem slot_move[] = {
835                 {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
836                 {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
837                 {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
838                 {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
839                 {0, NULL, 0, NULL, NULL }
840         };
841
842         /* identifiers */
843         ot->name = "Arrange Stroke";
844         ot->idname = "GPENCIL_OT_stroke_arrange";
845         ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
846
847         /* api callbacks */
848         ot->exec = gp_stroke_arrange_exec;
849         ot->poll = gp_active_layer_poll;
850
851         /* flags */
852         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
853
854         ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
855 }
856 /* ******************* Move Stroke to new color ************************** */
857
858 static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
859 {
860         bGPdata *gpd = ED_gpencil_data_get_active(C);
861         bGPDpalette *palette;
862         bGPDpalettecolor *color;
863
864         /* sanity checks */
865         if (ELEM(NULL, gpd)) {
866                 return OPERATOR_CANCELLED;
867         }
868
869         palette = BKE_gpencil_palette_getactive(gpd);
870         color = BKE_gpencil_palettecolor_getactive(palette);
871         if (ELEM(NULL, palette, color)) {
872                 return OPERATOR_CANCELLED;
873         }
874
875         /* loop all strokes */
876         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
877                 /* only editable and visible layers are considered */
878                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
879                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
880                                 /* only if selected */
881                                 if (gps->flag & GP_STROKE_SELECT) {
882                                         /* skip strokes that are invalid for current view */
883                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
884                                                 continue;
885                                         /* check if the color is editable */
886                                         if (ED_gpencil_stroke_color_use(gpl, gps) == false)
887                                                 continue;
888
889                                         /* asign new color (only if different) */
890                                         if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
891                                                 BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
892                                                 gps->palcolor = color;
893                                         }
894                                 }
895                         }
896                 }
897         }
898         /* notifiers */
899         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
900
901         return OPERATOR_FINISHED;
902 }
903
904 void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
905 {
906         /* identifiers */
907         ot->name = "Change Stroke Color";
908         ot->idname = "GPENCIL_OT_stroke_change_color";
909         ot->description = "Move selected strokes to active color";
910
911         /* api callbacks */
912         ot->exec = gp_stroke_change_color_exec;
913         ot->poll = gp_active_layer_poll;
914 }
915
916 /* ******************* Lock color of non selected Strokes colors ************************** */
917
918 static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
919 {
920         bGPdata *gpd = ED_gpencil_data_get_active(C);
921         bGPDpalette *palette;
922
923         /* sanity checks */
924         if (ELEM(NULL, gpd))
925                 return OPERATOR_CANCELLED;
926
927         palette = BKE_gpencil_palette_getactive(gpd);
928         if (ELEM(NULL, palette))
929                 return OPERATOR_CANCELLED;
930
931         /* first lock all colors */
932         for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
933                 palcolor->flag |= PC_COLOR_LOCKED;
934         }
935
936         /* loop all selected strokes and unlock any color */
937         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
938                 /* only editable and visible layers are considered */
939                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
940                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
941                                 /* only if selected */
942                                 if (gps->flag & GP_STROKE_SELECT) {
943                                         /* skip strokes that are invalid for current view */
944                                         if (ED_gpencil_stroke_can_use(C, gps) == false) {
945                                                 continue;
946                                         }
947                                         /* unlock color */
948                                         if (gps->palcolor != NULL) {
949                                                 gps->palcolor->flag &= ~PC_COLOR_LOCKED;
950                                         }
951                                 }
952                         }
953                 }
954         }
955         /* notifiers */
956         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
957
958         return OPERATOR_FINISHED;
959 }
960
961 void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
962 {
963         /* identifiers */
964         ot->name = "Lock Unused Colors";
965         ot->idname = "GPENCIL_OT_stroke_lock_color";
966         ot->description = "Lock any color not used in any selected stroke";
967
968         /* api callbacks */
969         ot->exec = gp_stroke_lock_color_exec;
970         ot->poll = gp_active_layer_poll;
971 }
972
973 /* ************************************************ */
974 /* Drawing Brushes Operators */
975
976 /* ******************* Add New Brush ************************ */
977
978 /* add new brush - wrapper around API */
979 static int gp_brush_add_exec(bContext *C, wmOperator *op)
980 {
981         ToolSettings *ts = CTX_data_tool_settings(C);
982
983         /* if there's no existing container */
984         if (ts == NULL) {
985                 BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
986                 return OPERATOR_CANCELLED;
987         }
988         /* add new brush now */
989         BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
990
991         /* notifiers */
992         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
993
994         return OPERATOR_FINISHED;
995 }
996
997 void GPENCIL_OT_brush_add(wmOperatorType *ot)
998 {
999         /* identifiers */
1000         ot->name = "Add Brush";
1001         ot->idname = "GPENCIL_OT_brush_add";
1002         ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block";
1003
1004         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1005
1006         /* callbacks */
1007         ot->exec = gp_brush_add_exec;
1008         ot->poll = gp_add_poll;
1009 }
1010
1011 /* ******************* Remove Active Brush ************************* */
1012
1013 static int gp_brush_remove_exec(bContext *C, wmOperator *op)
1014 {
1015         ToolSettings *ts = CTX_data_tool_settings(C);
1016         bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
1017
1018         /* sanity checks */
1019         if (ELEM(NULL, ts, brush))
1020                 return OPERATOR_CANCELLED;
1021
1022         if (BLI_listbase_count_ex(&ts->gp_brushes, 2) < 2) {
1023                 BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one");
1024                 return OPERATOR_CANCELLED;
1025         }
1026
1027
1028         /* make the brush before this the new active brush
1029          * - use the one after if this is the first
1030          * - if this is the only brush, this naturally becomes NULL
1031          */
1032         if (brush->prev)
1033                 BKE_gpencil_brush_setactive(ts, brush->prev);
1034         else
1035                 BKE_gpencil_brush_setactive(ts, brush->next);
1036
1037         /* delete the brush now... */
1038         BKE_gpencil_brush_delete(ts, brush);
1039
1040         /* notifiers */
1041         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1042
1043         return OPERATOR_FINISHED;
1044 }
1045
1046 void GPENCIL_OT_brush_remove(wmOperatorType *ot)
1047 {
1048         /* identifiers */
1049         ot->name = "Remove Brush";
1050         ot->idname = "GPENCIL_OT_brush_remove";
1051         ot->description = "Remove active Grease Pencil drawing brush";
1052
1053         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1054
1055         /* callbacks */
1056         ot->exec = gp_brush_remove_exec;
1057         ot->poll = gp_active_brush_poll;
1058 }
1059
1060 /* ********************** Change Brush ***************************** */
1061
1062 static int gp_brush_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
1063 {
1064         uiPopupMenu *pup;
1065         uiLayout *layout;
1066
1067         /* call the menu, which will call this operator again, hence the canceled */
1068         pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
1069         layout = UI_popup_menu_layout(pup);
1070         uiItemsEnumO(layout, "GPENCIL_OT_brush_change", "brush");
1071         UI_popup_menu_end(C, pup);
1072
1073         return OPERATOR_INTERFACE;
1074 }
1075
1076 static int gp_brush_change_exec(bContext *C, wmOperator *op)
1077 {
1078         ToolSettings *ts = CTX_data_tool_settings(C);
1079         bGPDbrush *brush = NULL;
1080         int brush_num = RNA_enum_get(op->ptr, "brush");
1081
1082         /* Get brush or create new one */
1083         if (brush_num == -1) {
1084                 /* Create brush */
1085                 brush = BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
1086         }
1087         else {
1088                 /* Try to get brush */
1089                 brush = BLI_findlink(&ts->gp_brushes, brush_num);
1090
1091                 if (brush == NULL) {
1092                         BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num);
1093                         return OPERATOR_CANCELLED;
1094                 }
1095         }
1096
1097         /* Set active brush */
1098         BKE_gpencil_brush_setactive(ts, brush);
1099
1100         /* updates */
1101         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1102
1103         return OPERATOR_FINISHED;
1104 }
1105
1106 void GPENCIL_OT_brush_change(wmOperatorType *ot)
1107 {
1108         /* identifiers */
1109         ot->name = "Change Brush";
1110         ot->idname = "GPENCIL_OT_brush_change";
1111         ot->description = "Change active Grease Pencil drawing brush";
1112
1113         /* callbacks */
1114         ot->invoke = gp_brush_change_invoke;
1115         ot->exec = gp_brush_change_exec;
1116         ot->poll = gp_active_brush_poll;
1117
1118         /* flags */
1119         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1120
1121         /* gp brush to use (dynamic enum) */
1122         ot->prop = RNA_def_enum(ot->srna, "brush", DummyRNA_DEFAULT_items, 0, "Grease Pencil Brush", "");
1123         RNA_def_enum_funcs(ot->prop, ED_gpencil_brushes_enum_itemf);
1124 }
1125
1126 /* ******************* Move Brush Up/Down ************************** */
1127
1128 enum {
1129         GP_BRUSH_MOVE_UP = -1,
1130         GP_BRUSH_MOVE_DOWN = 1
1131 };
1132
1133 static int gp_brush_move_exec(bContext *C, wmOperator *op)
1134 {
1135         ToolSettings *ts = CTX_data_tool_settings(C);
1136         bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
1137
1138         int direction = RNA_enum_get(op->ptr, "type");
1139
1140         /* sanity checks */
1141         if (ELEM(NULL, ts, brush)) {
1142                 return OPERATOR_CANCELLED;
1143         }
1144
1145         /* up or down? */
1146         if (direction == GP_BRUSH_MOVE_UP) {
1147                 /* up */
1148                 BLI_remlink(&ts->gp_brushes, brush);
1149                 BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush);
1150         }
1151         else if (direction == GP_BRUSH_MOVE_DOWN) {
1152                 /* down */
1153                 BLI_remlink(&ts->gp_brushes, brush);
1154                 BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush);
1155         }
1156         else {
1157                 BLI_assert(0);
1158         }
1159
1160         /* notifiers */
1161         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1162
1163         return OPERATOR_FINISHED;
1164 }
1165
1166 void GPENCIL_OT_brush_move(wmOperatorType *ot)
1167 {
1168         static const EnumPropertyItem slot_move[] = {
1169                 {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""},
1170                 {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""},
1171                 {0, NULL, 0, NULL, NULL }
1172         };
1173
1174         /* identifiers */
1175         ot->name = "Move Brush";
1176         ot->idname = "GPENCIL_OT_brush_move";
1177         ot->description = "Move the active Grease Pencil drawing brush up/down in the list";
1178
1179         /* api callbacks */
1180         ot->exec = gp_brush_move_exec;
1181         ot->poll = gp_active_brush_poll;
1182
1183         /* flags */
1184         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1185
1186         ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", "");
1187 }
1188
1189 /* ******************* Brush create presets ************************** */
1190
1191 static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
1192 {
1193         ToolSettings *ts = CTX_data_tool_settings(C);
1194         BKE_gpencil_brush_init_presets(ts);
1195
1196         /* notifiers */
1197         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1198
1199         return OPERATOR_FINISHED;
1200 }
1201
1202 void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
1203 {
1204         /* identifiers */
1205         ot->name = "Create Preset Brushes";
1206         ot->idname = "GPENCIL_OT_brush_presets_create";
1207         ot->description = "Create a set of predefined Grease Pencil drawing brushes";
1208
1209         /* api callbacks */
1210         ot->exec = gp_brush_presets_create_exec;
1211
1212         /* flags */
1213         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1214
1215 }
1216
1217 /* ***************** Copy Brush ************************ */
1218
1219 static int gp_brush_copy_exec(bContext *C, wmOperator *op)
1220 {
1221         ToolSettings *ts = CTX_data_tool_settings(C);
1222
1223         /* if there's no existing container */
1224         if (ts == NULL) {
1225                 BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
1226                 return OPERATOR_CANCELLED;
1227         }
1228
1229         bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
1230         bGPDbrush *newbrush;
1231
1232         /* sanity checks */
1233         if (ELEM(NULL, brush))
1234                 return OPERATOR_CANCELLED;
1235
1236         /* create a brush and duplicate data */
1237         newbrush = BKE_gpencil_brush_addnew(ts, brush->info, true);
1238         newbrush->thickness = brush->thickness;
1239         newbrush->draw_smoothfac = brush->draw_smoothfac;
1240         newbrush->draw_smoothlvl = brush->draw_smoothlvl;
1241         newbrush->sublevel = brush->sublevel;
1242         newbrush->flag = brush->flag;
1243         newbrush->draw_sensitivity = brush->draw_sensitivity;
1244         newbrush->draw_strength = brush->draw_strength;
1245         newbrush->draw_jitter = brush->draw_jitter;
1246         newbrush->draw_angle = brush->draw_angle;
1247         newbrush->draw_angle_factor = brush->draw_angle_factor;
1248         newbrush->draw_random_press = brush->draw_random_press;
1249         newbrush->draw_random_sub = brush->draw_random_sub;
1250
1251         /* free automatic curves created by default (replaced by copy) */
1252         curvemapping_free(newbrush->cur_sensitivity);
1253         curvemapping_free(newbrush->cur_strength);
1254         curvemapping_free(newbrush->cur_jitter);
1255
1256         /* make a copy of curves */
1257         newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity);
1258         newbrush->cur_strength = curvemapping_copy(brush->cur_strength);
1259         newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter);
1260
1261         BKE_gpencil_brush_setactive(ts, newbrush);
1262         /* notifiers */
1263         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1264
1265         return OPERATOR_FINISHED;
1266 }
1267
1268 void GPENCIL_OT_brush_copy(wmOperatorType *ot)
1269 {
1270         /* identifiers */
1271         ot->name = "Copy Brush";
1272         ot->idname = "GPENCIL_OT_brush_copy";
1273         ot->description = "Copy current Grease Pencil drawing brush";
1274
1275         /* callbacks */
1276         ot->exec = gp_brush_copy_exec;
1277         ot->poll = gp_active_brush_poll;
1278
1279         /* flags */
1280         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1281 }
1282
1283 /* ***************** Select Brush ************************ */
1284
1285 static int gp_brush_select_exec(bContext *C, wmOperator *op)
1286 {
1287         ToolSettings *ts = CTX_data_tool_settings(C);
1288
1289         /* if there's no existing container */
1290         if (ts == NULL) {
1291                 BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
1292                 return OPERATOR_CANCELLED;
1293         }
1294
1295         const int index = RNA_int_get(op->ptr, "index");
1296         bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, index);
1297         /* sanity checks */
1298         if (ELEM(NULL, brush)) {
1299                 return OPERATOR_CANCELLED;
1300         }
1301
1302         BKE_gpencil_brush_setactive(ts, brush);
1303
1304         /* notifiers */
1305         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1306
1307         return OPERATOR_FINISHED;
1308 }
1309
1310 void GPENCIL_OT_brush_select(wmOperatorType *ot)
1311 {
1312         /* identifiers */
1313         ot->name = "Select Brush";
1314         ot->idname = "GPENCIL_OT_brush_select";
1315         ot->description = "Select a Grease Pencil drawing brush";
1316
1317         /* callbacks */
1318         ot->exec = gp_brush_select_exec;
1319         ot->poll = gp_active_brush_poll;
1320
1321         /* flags */
1322         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1323
1324         /* properties */
1325         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
1326 }
1327
1328 /* ************************************************ */
1329 /* Palette Operators */
1330
1331 /* ******************* Add New Palette ************************ */
1332
1333 /* add new palette - wrapper around API */
1334 static int gp_palette_add_exec(bContext *C, wmOperator *op)
1335 {
1336         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
1337
1338         /* if there's no existing Grease-Pencil data there, add some */
1339         if (gpd_ptr == NULL) {
1340                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
1341                 return OPERATOR_CANCELLED;
1342         }
1343         if (*gpd_ptr == NULL)
1344                 *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
1345
1346         /* add new palette now */
1347         BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
1348
1349         /* notifiers */
1350         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1351
1352         return OPERATOR_FINISHED;
1353 }
1354
1355 void GPENCIL_OT_palette_add(wmOperatorType *ot)
1356 {
1357         /* identifiers */
1358         ot->name = "Add Palette";
1359         ot->idname = "GPENCIL_OT_palette_add";
1360         ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block";
1361
1362         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1363
1364         /* callbacks */
1365         ot->exec = gp_palette_add_exec;
1366         ot->poll = gp_add_poll;
1367 }
1368
1369 /* ******************* Remove Active Palette ************************* */
1370
1371 static int gp_palette_remove_exec(bContext *C, wmOperator *op)
1372 {
1373         bGPdata *gpd = ED_gpencil_data_get_active(C);
1374         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1375
1376         /* sanity checks */
1377         if (ELEM(NULL, gpd, palette))
1378                 return OPERATOR_CANCELLED;
1379
1380         if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) {
1381                 BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
1382                 return OPERATOR_CANCELLED;
1383         }
1384
1385
1386         /* make the palette before this the new active palette
1387          * - use the one after if this is the first
1388          * - if this is the only palette, this naturally becomes NULL
1389          */
1390         if (palette->prev)
1391                 BKE_gpencil_palette_setactive(gpd, palette->prev);
1392         else
1393                 BKE_gpencil_palette_setactive(gpd, palette->next);
1394
1395         /* delete the palette now... */
1396         BKE_gpencil_palette_delete(gpd, palette);
1397
1398         /* notifiers */
1399         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1400
1401         return OPERATOR_FINISHED;
1402 }
1403
1404 void GPENCIL_OT_palette_remove(wmOperatorType *ot)
1405 {
1406         /* identifiers */
1407         ot->name = "Remove palette";
1408         ot->idname = "GPENCIL_OT_palette_remove";
1409         ot->description = "Remove active Grease Pencil palette";
1410
1411         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1412
1413         /* callbacks */
1414         ot->exec = gp_palette_remove_exec;
1415         ot->poll = gp_active_palette_poll;
1416 }
1417
1418 /* ********************** Change Palette ***************************** */
1419
1420 static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
1421 {
1422         uiPopupMenu *pup;
1423         uiLayout *layout;
1424
1425         /* call the menu, which will call this operator again, hence the canceled */
1426         pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
1427         layout = UI_popup_menu_layout(pup);
1428         uiItemsEnumO(layout, "GPENCIL_OT_palette_change", "palette");
1429         UI_popup_menu_end(C, pup);
1430
1431         return OPERATOR_INTERFACE;
1432 }
1433
1434 static int gp_palette_change_exec(bContext *C, wmOperator *op)
1435 {
1436         bGPdata *gpd = CTX_data_gpencil_data(C);
1437         bGPDpalette *palette = NULL;
1438         int palette_num = RNA_enum_get(op->ptr, "palette");
1439
1440         /* Get palette or create new one */
1441         if (palette_num == -1) {
1442                 /* Create palette */
1443                 palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
1444         }
1445         else {
1446                 /* Try to get palette */
1447                 palette = BLI_findlink(&gpd->palettes, palette_num);
1448
1449                 if (palette == NULL) {
1450                         BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num);
1451                         return OPERATOR_CANCELLED;
1452                 }
1453         }
1454
1455         /* Set active palette */
1456         BKE_gpencil_palette_setactive(gpd, palette);
1457
1458         /* updates */
1459         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1460
1461         return OPERATOR_FINISHED;
1462 }
1463
1464 void GPENCIL_OT_palette_change(wmOperatorType *ot)
1465 {
1466         /* identifiers */
1467         ot->name = "Change Palette";
1468         ot->idname = "GPENCIL_OT_palette_change";
1469         ot->description = "Change active Grease Pencil palette";
1470
1471         /* callbacks */
1472         ot->invoke = gp_palette_change_invoke;
1473         ot->exec = gp_palette_change_exec;
1474         ot->poll = gp_active_palette_poll;
1475
1476         /* flags */
1477         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1478
1479         /* gp palette to use (dynamic enum) */
1480         ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", "");
1481         RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf);
1482 }
1483
1484 /* ******************* Lock and hide any color non used in current layer ************************** */
1485
1486 static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
1487 {
1488         bGPdata *gpd = ED_gpencil_data_get_active(C);
1489         bGPDpalette *palette;
1490
1491         /* sanity checks */
1492         if (ELEM(NULL, gpd))
1493                 return OPERATOR_CANCELLED;
1494
1495         palette = BKE_gpencil_palette_getactive(gpd);
1496         if (ELEM(NULL, palette))
1497                 return OPERATOR_CANCELLED;
1498
1499         /* first lock and hide all colors */
1500         for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1501                 palcolor->flag |= PC_COLOR_LOCKED;
1502                 palcolor->flag |= PC_COLOR_HIDE;
1503         }
1504
1505         /* loop all selected strokes and unlock any color used in active layer */
1506         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1507                 /* only editable and visible layers are considered */
1508                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) {
1509                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
1510                                 /* skip strokes that are invalid for current view */
1511                                 if (ED_gpencil_stroke_can_use(C, gps) == false)
1512                                         continue;
1513
1514                                 /* unlock/unhide color if not unlocked before */
1515                                 if (gps->palcolor != NULL) {
1516                                         gps->palcolor->flag &= ~PC_COLOR_LOCKED;
1517                                         gps->palcolor->flag &= ~PC_COLOR_HIDE;
1518                                 }
1519                         }
1520                 }
1521         }
1522         /* notifiers */
1523         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1524
1525         return OPERATOR_FINISHED;
1526 }
1527
1528 void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
1529 {
1530         /* identifiers */
1531         ot->name = "Disable Unused Layer Colors";
1532         ot->idname = "GPENCIL_OT_palette_lock_layer";
1533         ot->description = "Lock and hide any color not used in any layer";
1534
1535         /* api callbacks */
1536         ot->exec = gp_palette_lock_layer_exec;
1537         ot->poll = gp_active_layer_poll;
1538 }
1539
1540 /* ************************************************ */
1541 /* Palette Colors Operators */
1542
1543 /* ******************* Add New Palette ************************ */
1544
1545 /* add new palette - wrapper around API */
1546 static int gp_palettecolor_add_exec(bContext *C, wmOperator *op)
1547 {
1548         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
1549
1550         /* if there's no existing Grease-Pencil data there, add some */
1551         if (gpd_ptr == NULL) {
1552                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
1553                 return OPERATOR_CANCELLED;
1554         }
1555         if (*gpd_ptr == NULL)
1556                 *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
1557
1558         /* verify palette */
1559         bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr);
1560         if (palette == NULL)
1561                 palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
1562
1563         /* add new palette color now */
1564         BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
1565
1566         /* notifiers */
1567         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1568
1569         return OPERATOR_FINISHED;
1570 }
1571
1572 void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
1573 {
1574         /* identifiers */
1575         ot->name = "Add Palette Color";
1576         ot->idname = "GPENCIL_OT_palettecolor_add";
1577         ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block";
1578
1579         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1580
1581         /* callbacks */
1582         ot->exec = gp_palettecolor_add_exec;
1583         ot->poll = gp_add_poll;
1584 }
1585
1586 /* ******************* Remove Active Palette color ************************* */
1587
1588 static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op))
1589 {
1590         bGPdata *gpd = ED_gpencil_data_get_active(C);
1591         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1592         bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette);
1593
1594         /* sanity checks */
1595         if (ELEM(NULL, gpd, palette, color))
1596                 return OPERATOR_CANCELLED;
1597
1598         /* make the palette color before this the new active color
1599          * - use the one after if this is the first
1600          * - if this is the only color, this naturally becomes NULL
1601          */
1602         if (color->prev)
1603                 BKE_gpencil_palettecolor_setactive(palette, color->prev);
1604         else
1605                 BKE_gpencil_palettecolor_setactive(palette, color->next);
1606
1607         /* delete the strokes */
1608         BKE_gpencil_palettecolor_delete_strokes(gpd, color->info);
1609
1610         /* delete the palette color now... */
1611         BKE_gpencil_palettecolor_delete(palette, color);
1612
1613         /* notifiers */
1614         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1615
1616         return OPERATOR_FINISHED;
1617 }
1618
1619 void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot)
1620 {
1621         /* identifiers */
1622         ot->name = "Remove palette color";
1623         ot->idname = "GPENCIL_OT_palettecolor_remove";
1624         ot->description = "Remove active Grease Pencil palette color";
1625
1626         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1627
1628         /* callbacks */
1629         ot->exec = gp_palettecolor_remove_exec;
1630         ot->poll = gp_active_palettecolor_poll;
1631 }
1632
1633 /* ********************** Isolate palette color **************************** */
1634
1635 static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
1636 {
1637         bGPdata *gpd = ED_gpencil_data_get_active(C);
1638         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1639         bGPDpalettecolor *active_color = BKE_gpencil_palettecolor_getactive(palette);
1640         bGPDpalettecolor *palcolor;
1641
1642         int flags = PC_COLOR_LOCKED;
1643         bool isolate = false;
1644
1645         if (RNA_boolean_get(op->ptr, "affect_visibility"))
1646                 flags |= PC_COLOR_HIDE;
1647
1648         if (ELEM(NULL, gpd, active_color)) {
1649                 BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
1650                 return OPERATOR_CANCELLED;
1651         }
1652
1653         /* Test whether to isolate or clear all flags */
1654         for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1655                 /* Skip if this is the active one */
1656                 if (palcolor == active_color)
1657                         continue;
1658
1659                 /* If the flags aren't set, that means that the color is
1660                  * not alone, so we have some colors to isolate still
1661                  */
1662                 if ((palcolor->flag & flags) == 0) {
1663                         isolate = true;
1664                         break;
1665                 }
1666         }
1667
1668         /* Set/Clear flags as appropriate */
1669         if (isolate) {
1670                 /* Set flags on all "other" colors */
1671                 for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1672                         if (palcolor == active_color)
1673                                 continue;
1674                         else
1675                                 palcolor->flag |= flags;
1676                 }
1677         }
1678         else {
1679                 /* Clear flags - Restore everything else */
1680                 for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1681                         palcolor->flag &= ~flags;
1682                 }
1683         }
1684
1685         /* notifiers */
1686         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1687
1688         return OPERATOR_FINISHED;
1689 }
1690
1691 void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
1692 {
1693         /* identifiers */
1694         ot->name = "Isolate Palette Color";
1695         ot->idname = "GPENCIL_OT_palettecolor_isolate";
1696         ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
1697
1698         /* callbacks */
1699         ot->exec = gp_isolate_palettecolor_exec;
1700         ot->poll = gp_active_palettecolor_poll;
1701
1702         /* flags */
1703         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1704
1705         /* properties */
1706         RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
1707                         "the editability, also affect the visibility");
1708 }
1709
1710 /* *********************** Hide Palette colors ******************************** */
1711
1712 static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
1713 {
1714         bGPdata *gpd = ED_gpencil_data_get_active(C);
1715         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1716         bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
1717
1718         bool unselected = RNA_boolean_get(op->ptr, "unselected");
1719
1720         /* sanity checks */
1721         if (ELEM(NULL, gpd, palette, palcolor))
1722                 return OPERATOR_CANCELLED;
1723
1724         if (unselected) {
1725                 bGPDpalettecolor *color;
1726
1727                 /* hide unselected */
1728                 for (color = palette->colors.first; color; color = color->next) {
1729                         if (color != palcolor) {
1730                                 color->flag |= PC_COLOR_HIDE;
1731                         }
1732                 }
1733         }
1734         else {
1735                 /* hide selected/active */
1736                 palcolor->flag |= PC_COLOR_HIDE;
1737         }
1738
1739         /* notifiers */
1740         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1741
1742         return OPERATOR_FINISHED;
1743 }
1744
1745 void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
1746 {
1747         /* identifiers */
1748         ot->name = "Hide Color(s)";
1749         ot->idname = "GPENCIL_OT_palettecolor_hide";
1750         ot->description = "Hide selected/unselected Grease Pencil colors";
1751
1752         /* callbacks */
1753         ot->exec = gp_palettecolor_hide_exec;
1754         ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */
1755
1756         /* flags */
1757         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1758
1759         /* props */
1760         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
1761 }
1762
1763 /* ********************** Show All Colors ***************************** */
1764
1765 /* poll callback for showing colors */
1766 static int gp_palettecolor_reveal_poll(bContext *C)
1767 {
1768         return ED_gpencil_data_get_active(C) != NULL;
1769 }
1770
1771 static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op))
1772 {
1773         bGPdata *gpd = ED_gpencil_data_get_active(C);
1774         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1775         bGPDpalettecolor *palcolor;
1776
1777         /* sanity checks */
1778         if (ELEM(NULL, gpd, palette))
1779                 return OPERATOR_CANCELLED;
1780
1781         /* make all colors visible */
1782         for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1783                 palcolor->flag &= ~PC_COLOR_HIDE;
1784         }
1785
1786         /* notifiers */
1787         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1788
1789         return OPERATOR_FINISHED;
1790 }
1791
1792 void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
1793 {
1794         /* identifiers */
1795         ot->name = "Show All Colors";
1796         ot->idname = "GPENCIL_OT_palettecolor_reveal";
1797         ot->description = "Unhide all hidden Grease Pencil palette colors";
1798
1799         /* callbacks */
1800         ot->exec = gp_palettecolor_reveal_exec;
1801         ot->poll = gp_palettecolor_reveal_poll;
1802
1803         /* flags */
1804         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1805 }
1806
1807 /* ***************** Lock/Unlock All Palette colors ************************ */
1808
1809 static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
1810 {
1811         bGPdata *gpd = ED_gpencil_data_get_active(C);
1812         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1813         bGPDpalettecolor *palcolor;
1814
1815         /* sanity checks */
1816         if (ELEM(NULL, gpd, palette))
1817                 return OPERATOR_CANCELLED;
1818
1819         /* make all layers non-editable */
1820         for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1821                 palcolor->flag |= PC_COLOR_LOCKED;
1822         }
1823
1824         /* notifiers */
1825         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1826
1827         return OPERATOR_FINISHED;
1828 }
1829
1830 void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
1831 {
1832         /* identifiers */
1833         ot->name = "Lock All Colors";
1834         ot->idname = "GPENCIL_OT_palettecolor_lock_all";
1835         ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
1836
1837         /* callbacks */
1838         ot->exec = gp_palettecolor_lock_all_exec;
1839         ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
1840
1841         /* flags */
1842         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1843 }
1844
1845 /* -------------------------- */
1846
1847 static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
1848 {
1849         bGPdata *gpd = ED_gpencil_data_get_active(C);
1850         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1851         bGPDpalettecolor *palcolor;
1852
1853         /* sanity checks */
1854         if (ELEM(NULL, gpd, palette))
1855                 return OPERATOR_CANCELLED;
1856
1857         /* make all layers editable again*/
1858         for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
1859                 palcolor->flag &= ~PC_COLOR_LOCKED;
1860         }
1861
1862         /* notifiers */
1863         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1864
1865         return OPERATOR_FINISHED;
1866 }
1867
1868 void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
1869 {
1870         /* identifiers */
1871         ot->name = "Unlock All Colors";
1872         ot->idname = "GPENCIL_OT_palettecolor_unlock_all";
1873         ot->description = "Unlock all Grease Pencil colors so that they can be edited";
1874
1875         /* callbacks */
1876         ot->exec = gp_palettecolor_unlock_all_exec;
1877         ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
1878
1879         /* flags */
1880         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1881 }
1882
1883 /* ******************* Move Color Up/Down ************************** */
1884
1885 enum {
1886         GP_COLOR_MOVE_UP = -1,
1887         GP_COLOR_MOVE_DOWN = 1
1888 };
1889
1890 static int gp_palettecolor_move_exec(bContext *C, wmOperator *op)
1891 {
1892         bGPdata *gpd = ED_gpencil_data_get_active(C);
1893         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1894         bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
1895
1896         int direction = RNA_enum_get(op->ptr, "direction");
1897
1898         /* sanity checks */
1899         if (ELEM(NULL, gpd, palette, palcolor))
1900                 return OPERATOR_CANCELLED;
1901
1902         /* up or down? */
1903         if (direction == GP_COLOR_MOVE_UP) {
1904                 /* up */
1905                 BLI_remlink(&palette->colors, palcolor);
1906                 BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor);
1907         }
1908         else if (direction == GP_COLOR_MOVE_DOWN) {
1909                 /* down */
1910                 BLI_remlink(&palette->colors, palcolor);
1911                 BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor);
1912         }
1913         else {
1914                 BLI_assert(0);
1915         }
1916
1917         /* notifiers */
1918         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1919
1920         return OPERATOR_FINISHED;
1921 }
1922
1923 void GPENCIL_OT_palettecolor_move(wmOperatorType *ot)
1924 {
1925         static const EnumPropertyItem slot_move[] = {
1926                 {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""},
1927                 {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""},
1928                 {0, NULL, 0, NULL, NULL}
1929         };
1930
1931         /* identifiers */
1932         ot->name = "Move Palette color";
1933         ot->idname = "GPENCIL_OT_palettecolor_move";
1934         ot->description = "Move the active Grease Pencil palette color up/down in the list";
1935
1936         /* api callbacks */
1937         ot->exec = gp_palettecolor_move_exec;
1938         ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
1939
1940         /* flags */
1941         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1942
1943         ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", "");
1944 }
1945
1946 /* ***************** Select all strokes using Palette color ************************ */
1947
1948 static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
1949 {
1950         bGPdata *gpd = ED_gpencil_data_get_active(C);
1951         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
1952         bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
1953
1954         /* sanity checks */
1955         if (ELEM(NULL, gpd, palette, palcolor))
1956                 return OPERATOR_CANCELLED;
1957
1958         /* read all strokes and select*/
1959         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1960                 /* only editable and visible layers are considered */
1961                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
1962                         /* verify something to do */
1963                         for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
1964                                 /* skip strokes that are invalid for current view */
1965                                 if (ED_gpencil_stroke_can_use(C, gps) == false)
1966                                         continue;
1967                                 /* check if the color is editable */
1968                                 if (ED_gpencil_stroke_color_use(gpl, gps) == false)
1969                                         continue;
1970
1971                                 /* select */
1972                                 if (strcmp(palcolor->info, gps->colorname) == 0) {
1973                                         bGPDspoint *pt;
1974                                         int i;
1975
1976                                         gps->flag |= GP_STROKE_SELECT;
1977                                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1978                                                 pt->flag |= GP_SPOINT_SELECT;
1979                                         }
1980                                 }
1981                         }
1982                 }
1983         }
1984         /* notifiers */
1985         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1986
1987         return OPERATOR_FINISHED;
1988 }
1989
1990 void GPENCIL_OT_palettecolor_select(wmOperatorType *ot)
1991 {
1992         /* identifiers */
1993         ot->name = "Select Color";
1994         ot->idname = "GPENCIL_OT_palettecolor_select";
1995         ot->description = "Select all Grease Pencil strokes using current color";
1996
1997         /* callbacks */
1998         ot->exec = gp_palettecolor_select_exec;
1999         ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
2000
2001         /* flags */
2002         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2003 }
2004
2005 /* ***************** Copy Palette color ************************ */
2006
2007 static int gp_palettecolor_copy_exec(bContext *C, wmOperator *UNUSED(op))
2008 {
2009         bGPdata *gpd = ED_gpencil_data_get_active(C);
2010         bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
2011         bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
2012         bGPDpalettecolor *newcolor;
2013
2014         /* sanity checks */
2015         if (ELEM(NULL, gpd, palette, palcolor))
2016                 return OPERATOR_CANCELLED;
2017
2018         /* create a new color and duplicate data */
2019         newcolor = BKE_gpencil_palettecolor_addnew(palette, palcolor->info, true);
2020         copy_v4_v4(newcolor->color, palcolor->color);
2021         copy_v4_v4(newcolor->fill, palcolor->fill);
2022         newcolor->flag = palcolor->flag;
2023
2024         /* notifiers */
2025         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2026
2027         return OPERATOR_FINISHED;
2028 }
2029
2030 void GPENCIL_OT_palettecolor_copy(wmOperatorType *ot)
2031 {
2032         /* identifiers */
2033         ot->name = "Copy Color";
2034         ot->idname = "GPENCIL_OT_palettecolor_copy";
2035         ot->description = "Copy current Grease Pencil palette color";
2036
2037         /* callbacks */
2038         ot->exec = gp_palettecolor_copy_exec;
2039         ot->poll = gp_active_palettecolor_poll;
2040
2041         /* flags */
2042         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2043 }