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