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