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