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