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