81da4ab8bc96f3932290047ad99b0221bf59ac7c
[blender.git] / source / blender / editors / gpencil / gpencil_data.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008, Blender Foundation
17  * This is a new part of Blender
18  * Operators for dealing with GP datablocks and layers
19  */
20
21 /** \file
22  * \ingroup edgpencil
23  */
24
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <math.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36 #include "BLI_ghash.h"
37 #include "BLI_math.h"
38 #include "BLI_string_utils.h"
39
40 #include "BLT_translation.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_brush_types.h"
44 #include "DNA_gpencil_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_object_types.h"
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
53 #include "BKE_animsys.h"
54 #include "BKE_brush.h"
55 #include "BKE_context.h"
56 #include "BKE_deform.h"
57 #include "BKE_fcurve.h"
58 #include "BKE_gpencil.h"
59 #include "BKE_gpencil_modifier.h"
60 #include "BKE_library.h"
61 #include "BKE_main.h"
62 #include "BKE_material.h"
63 #include "BKE_modifier.h"
64 #include "BKE_object.h"
65 #include "BKE_paint.h"
66 #include "BKE_report.h"
67 #include "BKE_scene.h"
68
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77 #include "RNA_enum_types.h"
78
79 #include "ED_object.h"
80 #include "ED_gpencil.h"
81
82 #include "DEG_depsgraph.h"
83 #include "DEG_depsgraph_build.h"
84 #include "DEG_depsgraph_query.h"
85
86 #include "gpencil_intern.h"
87
88 /* ************************************************ */
89 /* Datablock Operators */
90
91 /* ******************* Add New Data ************************ */
92 static bool gp_data_add_poll(bContext *C)
93 {
94         Object *obact = CTX_data_active_object(C);
95         if (obact && obact->type == OB_GPENCIL) {
96                 if (obact->mode != OB_MODE_OBJECT) {
97                         return false;
98                 }
99         }
100
101         /* the base line we have is that we have somewhere to add Grease Pencil data */
102         return ED_gpencil_data_get_pointers(C, NULL) != NULL;
103 }
104
105 /* add new datablock - wrapper around API */
106 static int gp_data_add_exec(bContext *C, wmOperator *op)
107 {
108         PointerRNA gpd_owner = {{NULL}};
109         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
110         bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
111
112         if (gpd_ptr == NULL) {
113                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
114                 return OPERATOR_CANCELLED;
115         }
116         else {
117                 /* decrement user count and add new datablock */
118                 /* TODO: if a datablock exists,
119                  * we should make a copy of it instead of starting fresh (as in other areas) */
120                 Main *bmain = CTX_data_main(C);
121
122                 /* decrement user count of old GP datablock */
123                 if (*gpd_ptr) {
124                         bGPdata *gpd = (*gpd_ptr);
125                         id_us_min(&gpd->id);
126                 }
127
128                 /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */
129                 if (is_annotation) {
130                         bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
131                         *gpd_ptr = gpd;
132
133                         /* tag for annotations */
134                         gpd->flag |= GP_DATA_ANNOTATIONS;
135
136                         /* add new layer (i.e. a "note") */
137                         BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
138                 }
139                 else {
140                         /* GP Object Case - This shouldn't happen! */
141                         *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
142
143                         /* add default sets of colors and brushes */
144                         Object *ob = CTX_data_active_object(C);
145                         ED_gpencil_add_defaults(C, ob);
146
147                         /* add new layer */
148                         BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
149                 }
150         }
151
152         /* notifiers */
153         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
154
155         return OPERATOR_FINISHED;
156 }
157
158 void GPENCIL_OT_data_add(wmOperatorType *ot)
159 {
160         /* identifiers */
161         ot->name = "Grease Pencil Add New";
162         ot->idname = "GPENCIL_OT_data_add";
163         ot->description = "Add new Grease Pencil data-block";
164         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
165
166         /* callbacks */
167         ot->exec = gp_data_add_exec;
168         ot->poll = gp_data_add_poll;
169 }
170
171 /* ******************* Unlink Data ************************ */
172
173 /* poll callback for adding data/layers - special */
174 static bool gp_data_unlink_poll(bContext *C)
175 {
176         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
177
178         /* only unlink annotation datablocks */
179         if ((gpd_ptr != NULL) && (*gpd_ptr != NULL)) {
180                 bGPdata *gpd = (*gpd_ptr);
181                 if ((gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
182                         return false;
183                 }
184         }
185         /* if we have access to some active data, make sure there's a datablock before enabling this */
186         return (gpd_ptr && *gpd_ptr);
187 }
188
189
190 /* unlink datablock - wrapper around API */
191 static int gp_data_unlink_exec(bContext *C, wmOperator *op)
192 {
193         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
194
195         if (gpd_ptr == NULL) {
196                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
197                 return OPERATOR_CANCELLED;
198         }
199         else {
200                 /* just unlink datablock now, decreasing its user count */
201                 bGPdata *gpd = (*gpd_ptr);
202
203                 id_us_min(&gpd->id);
204                 *gpd_ptr = NULL;
205         }
206
207         /* notifiers */
208         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
209
210         return OPERATOR_FINISHED;
211 }
212
213 void GPENCIL_OT_data_unlink(wmOperatorType *ot)
214 {
215         /* identifiers */
216         ot->name = "Annotation Unlink";
217         ot->idname = "GPENCIL_OT_data_unlink";
218         ot->description = "Unlink active Annotation data-block";
219         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
220
221         /* callbacks */
222         ot->exec = gp_data_unlink_exec;
223         ot->poll = gp_data_unlink_poll;
224 }
225
226
227 /* ************************************************ */
228 /* Layer Operators */
229
230 /* ******************* Add New Layer ************************ */
231
232 /* add new layer - wrapper around API */
233 static int gp_layer_add_exec(bContext *C, wmOperator *op)
234 {
235         PointerRNA gpd_owner = {{NULL}};
236         bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
237         bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
238
239         /* if there's no existing Grease-Pencil data there, add some */
240         if (gpd_ptr == NULL) {
241                 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
242                 return OPERATOR_CANCELLED;
243         }
244
245         if (*gpd_ptr == NULL) {
246                 Main *bmain = CTX_data_main(C);
247                 if (is_annotation) {
248                         /* Annotations */
249                         *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
250
251                         /* mark as annotation */
252                         (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
253                 }
254                 else {
255                         /* GP Object */
256                         /* NOTE: This shouldn't actually happen in practice */
257                         *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
258
259                         /* add default sets of colors and brushes */
260                         Object *ob = CTX_data_active_object(C);
261                         ED_gpencil_add_defaults(C, ob);
262                 }
263         }
264
265         /* add new layer now */
266         if (is_annotation) {
267                 BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
268         }
269         else {
270                 BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
271         }
272
273         /* notifiers */
274         bGPdata *gpd = *gpd_ptr;
275         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
276         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
277
278         return OPERATOR_FINISHED;
279 }
280
281 void GPENCIL_OT_layer_add(wmOperatorType *ot)
282 {
283         /* identifiers */
284         ot->name = "Add New Layer";
285         ot->idname = "GPENCIL_OT_layer_add";
286         ot->description = "Add new layer or note for the active data-block";
287
288         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
289
290         /* callbacks */
291         ot->exec = gp_layer_add_exec;
292         ot->poll = gp_add_poll;
293 }
294
295 /* ******************* Remove Active Layer ************************* */
296
297 static int gp_layer_remove_exec(bContext *C, wmOperator *op)
298 {
299         bGPdata *gpd = ED_gpencil_data_get_active(C);
300         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
301
302         /* sanity checks */
303         if (ELEM(NULL, gpd, gpl))
304                 return OPERATOR_CANCELLED;
305
306         if (gpl->flag & GP_LAYER_LOCKED) {
307                 BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
308                 return OPERATOR_CANCELLED;
309         }
310
311         /* make the layer before this the new active layer
312          * - use the one after if this is the first
313          * - if this is the only layer, this naturally becomes NULL
314          */
315         if (gpl->prev)
316                 BKE_gpencil_layer_setactive(gpd, gpl->prev);
317         else
318                 BKE_gpencil_layer_setactive(gpd, gpl->next);
319
320         /* delete the layer now... */
321         BKE_gpencil_layer_delete(gpd, gpl);
322
323         /* notifiers */
324         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
325         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
326
327         return OPERATOR_FINISHED;
328 }
329
330 void GPENCIL_OT_layer_remove(wmOperatorType *ot)
331 {
332         /* identifiers */
333         ot->name = "Remove Layer";
334         ot->idname = "GPENCIL_OT_layer_remove";
335         ot->description = "Remove active Grease Pencil layer";
336
337         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
338
339         /* callbacks */
340         ot->exec = gp_layer_remove_exec;
341         ot->poll = gp_active_layer_poll;
342 }
343
344 /* ******************* Move Layer Up/Down ************************** */
345
346 enum {
347         GP_LAYER_MOVE_UP   = -1,
348         GP_LAYER_MOVE_DOWN = 1,
349 };
350
351 static int gp_layer_move_exec(bContext *C, wmOperator *op)
352 {
353         bGPdata *gpd = ED_gpencil_data_get_active(C);
354         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
355
356         const int direction = RNA_enum_get(op->ptr, "type") * -1;
357
358         /* sanity checks */
359         if (ELEM(NULL, gpd, gpl))
360                 return OPERATOR_CANCELLED;
361
362         BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
363         if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
364                 DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
365                 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
366         }
367
368         return OPERATOR_FINISHED;
369 }
370
371 void GPENCIL_OT_layer_move(wmOperatorType *ot)
372 {
373         static const EnumPropertyItem slot_move[] = {
374                 {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
375                 {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
376                 {0, NULL, 0, NULL, NULL},
377         };
378
379         /* identifiers */
380         ot->name = "Move Grease Pencil Layer";
381         ot->idname = "GPENCIL_OT_layer_move";
382         ot->description = "Move the active Grease Pencil layer up/down in the list";
383
384         /* api callbacks */
385         ot->exec = gp_layer_move_exec;
386         ot->poll = gp_active_layer_poll;
387
388         /* flags */
389         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
390
391         ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
392 }
393
394 /* ********************* Duplicate Layer ************************** */
395
396 static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
397 {
398         bGPdata *gpd = ED_gpencil_data_get_active(C);
399         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
400         bGPDlayer *new_layer;
401
402         /* sanity checks */
403         if (ELEM(NULL, gpd, gpl))
404                 return OPERATOR_CANCELLED;
405
406         /* make copy of layer, and add it immediately after the existing layer */
407         new_layer = BKE_gpencil_layer_duplicate(gpl);
408         BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
409
410         /* ensure new layer has a unique name, and is now the active layer */
411         BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
412         BKE_gpencil_layer_setactive(gpd, new_layer);
413
414         /* notifiers */
415         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
416         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
417
418         return OPERATOR_FINISHED;
419 }
420
421 void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
422 {
423         /* identifiers */
424         ot->name = "Duplicate Layer";
425         ot->idname = "GPENCIL_OT_layer_duplicate";
426         ot->description = "Make a copy of the active Grease Pencil layer";
427
428         /* callbacks */
429         ot->exec = gp_layer_copy_exec;
430         ot->poll = gp_active_layer_poll;
431
432         /* flags */
433         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
434 }
435
436 /* ********************* Duplicate Layer in a new object ************************** */
437 enum {
438         GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
439         GP_LAYER_COPY_OBJECT_ACT_FRAME = 1,
440 };
441
442 static bool gp_layer_duplicate_object_poll(bContext *C)
443 {
444         ViewLayer *view_layer = CTX_data_view_layer(C);
445         Object *ob = CTX_data_active_object(C);
446         if ((ob == NULL) || (ob->type != OB_GPENCIL))
447                 return false;
448
449         bGPdata *gpd = (bGPdata *)ob->data;
450         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
451
452         if (gpl == NULL)
453                 return false;
454
455         /* check there are more grease pencil objects */
456         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
457                 if ((base->object != ob) && (base->object->type == OB_GPENCIL))
458                         return true;
459         }
460
461         return false;
462 }
463
464 static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
465 {
466         Main *bmain = CTX_data_main(C);
467         Scene *scene = CTX_data_scene(C);
468         char name[MAX_ID_NAME - 2];
469         RNA_string_get(op->ptr, "object", name);
470
471         if (name[0] == '\0') {
472                 return OPERATOR_CANCELLED;
473         }
474
475         Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
476
477         int mode = RNA_enum_get(op->ptr, "mode");
478
479         Object *ob_src = CTX_data_active_object(C);
480         bGPdata *gpd_src = (bGPdata *)ob_src->data;
481         bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
482
483         /* sanity checks */
484         if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
485                 return OPERATOR_CANCELLED;
486         }
487         /* cannot copy itself and check destination type */
488         if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
489                 return OPERATOR_CANCELLED;
490         }
491
492         bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
493
494         /* make copy of layer */
495         bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
496         gpl_dst->prev = gpl_dst->next = NULL;
497         BLI_addtail(&gpd_dst->layers, gpl_dst);
498         BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info));
499
500         /* copy frames */
501         BLI_listbase_clear(&gpl_dst->frames);
502         for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
503
504                 if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
505                         continue;
506                 }
507
508                 /* make a copy of source frame */
509                 bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
510                 gpf_dst->prev = gpf_dst->next = NULL;
511                 BLI_addtail(&gpl_dst->frames, gpf_dst);
512
513                 /* copy strokes */
514                 BLI_listbase_clear(&gpf_dst->strokes);
515                 for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
516
517                         /* make copy of source stroke */
518                         bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
519
520                         /* check if material is in destination object,
521                          * otherwise add the slot with the material
522                          */
523                         Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
524                         int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
525
526                         /* reasign the stroke material to the right slot in destination object */
527                         gps_dst->mat_nr = idx;
528
529                         /* add new stroke to frame */
530                         BLI_addtail(&gpf_dst->strokes, gps_dst);
531                 }
532         }
533
534         /* notifiers */
535         DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
536         DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE);
537         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
538
539         return OPERATOR_FINISHED;
540 }
541
542 void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
543 {
544         static const EnumPropertyItem copy_mode[] = {
545                 {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
546                 {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
547                 {0, NULL, 0, NULL, NULL},
548         };
549
550         /* identifiers */
551         ot->name = "Duplicate Layer to new Object";
552         ot->idname = "GPENCIL_OT_layer_duplicate_object";
553         ot->description = "Make a copy of the active Grease Pencil layer to new object";
554
555         /* callbacks */
556         ot->exec = gp_layer_duplicate_object_exec;
557         ot->poll = gp_layer_duplicate_object_poll;
558
559         /* flags */
560         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
561
562         ot->prop = RNA_def_string(ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
563         RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
564
565         RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
566 }
567
568 /* ********************* Duplicate Frame ************************** */
569 enum {
570         GP_FRAME_DUP_ACTIVE = 0,
571         GP_FRAME_DUP_ALL = 1,
572 };
573
574 static int gp_frame_duplicate_exec(bContext *C, wmOperator *op)
575 {
576         bGPdata *gpd = ED_gpencil_data_get_active(C);
577         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
578         Depsgraph *depsgraph = CTX_data_depsgraph(C);
579         int cfra_eval = (int)DEG_get_ctime(depsgraph);
580
581         int mode = RNA_enum_get(op->ptr, "mode");
582
583         /* sanity checks */
584         if (ELEM(NULL, gpd, gpl))
585                 return OPERATOR_CANCELLED;
586
587         if (mode == 0) {
588                 BKE_gpencil_frame_addcopy(gpl, cfra_eval);
589         }
590         else {
591                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
592                         if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
593                                 BKE_gpencil_frame_addcopy(gpl, cfra_eval);
594                         }
595                 }
596
597         }
598         /* notifiers */
599         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
600         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
601
602         return OPERATOR_FINISHED;
603 }
604
605 void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
606 {
607         static const EnumPropertyItem duplicate_mode[] = {
608                 {GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only"},
609                 {GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers"},
610                 {0, NULL, 0, NULL, NULL},
611         };
612
613         /* identifiers */
614         ot->name = "Duplicate Frame";
615         ot->idname = "GPENCIL_OT_frame_duplicate";
616         ot->description = "Make a copy of the active Grease Pencil Frame";
617
618         /* callbacks */
619         ot->exec = gp_frame_duplicate_exec;
620         ot->poll = gp_active_layer_poll;
621
622         /* flags */
623         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
624
625         ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
626 }
627
628 /* ********************* Clean Fill Boundaries on Frame ************************** */
629 enum {
630         GP_FRAME_CLEAN_FILL_ACTIVE = 0,
631         GP_FRAME_CLEAN_FILL_ALL = 1,
632 };
633
634 static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
635 {
636         bool changed = false;
637         bGPdata *gpd = ED_gpencil_data_get_active(C);
638         int mode = RNA_enum_get(op->ptr, "mode");
639
640         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
641         {
642                 bGPDframe *init_gpf = gpl->actframe;
643                 if (mode == GP_FRAME_CLEAN_FILL_ALL) {
644                         init_gpf = gpl->frames.first;
645                 }
646
647                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
648                         if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
649                                 bGPDstroke *gps, *gpsn;
650
651                                 if (gpf == NULL)
652                                         continue;
653
654                                 /* simply delete strokes which are no fill */
655                                 for (gps = gpf->strokes.first; gps; gps = gpsn) {
656                                         gpsn = gps->next;
657
658                                         /* skip strokes that are invalid for current view */
659                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
660                                                 continue;
661
662                                         /* free stroke */
663                                         if (gps->flag & GP_STROKE_NOFILL) {
664                                                 /* free stroke memory arrays, then stroke itself */
665                                                 if (gps->points) {
666                                                         MEM_freeN(gps->points);
667                                                 }
668                                                 if (gps->dvert) {
669                                                         BKE_gpencil_free_stroke_weights(gps);
670                                                         MEM_freeN(gps->dvert);
671                                                 }
672                                                 MEM_SAFE_FREE(gps->triangles);
673                                                 BLI_freelinkN(&gpf->strokes, gps);
674
675                                                 changed = true;
676                                         }
677                                 }
678                         }
679                 }
680         }
681         CTX_DATA_END;
682
683         /* notifiers */
684         if (changed) {
685                 DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
686                 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
687         }
688
689         return OPERATOR_FINISHED;
690 }
691
692 void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
693 {
694         static const EnumPropertyItem duplicate_mode[] = {
695                 {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
696                 {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
697                 {0, NULL, 0, NULL, NULL},
698         };
699
700         /* identifiers */
701         ot->name = "Clean Fill Boundaries";
702         ot->idname = "GPENCIL_OT_frame_clean_fill";
703         ot->description = "Remove 'no fill' boundary strokes";
704
705         /* callbacks */
706         ot->exec = gp_frame_clean_fill_exec;
707         ot->poll = gp_active_layer_poll;
708
709         /* flags */
710         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
711
712         ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
713 }
714
715 /* ********************* Clean Loose Boundaries on Frame ************************** */
716 static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
717 {
718         bool changed = false;
719         bGPdata *gpd = ED_gpencil_data_get_active(C);
720         int limit = RNA_int_get(op->ptr, "limit");
721         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
722
723         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
724         {
725                 bGPDframe *init_gpf = gpl->actframe;
726                 bGPDstroke *gps = NULL;
727                 bGPDstroke *gpsn = NULL;
728                 if (is_multiedit) {
729                         init_gpf = gpl->frames.first;
730                 }
731
732                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
733                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
734                                 if (gpf == NULL)
735                                         continue;
736
737                                 /* simply delete strokes which are no loose */
738                                 for (gps = gpf->strokes.first; gps; gps = gpsn) {
739                                         gpsn = gps->next;
740
741                                         /* skip strokes that are invalid for current view */
742                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
743                                                 continue;
744
745                                         /* free stroke */
746                                         if (gps->totpoints <= limit) {
747                                                 /* free stroke memory arrays, then stroke itself */
748                                                 if (gps->points) {
749                                                         MEM_freeN(gps->points);
750                                                 }
751                                                 if (gps->dvert) {
752                                                         BKE_gpencil_free_stroke_weights(gps);
753                                                         MEM_freeN(gps->dvert);
754                                                 }
755                                                 MEM_SAFE_FREE(gps->triangles);
756                                                 BLI_freelinkN(&gpf->strokes, gps);
757
758                                                 changed = true;
759                                         }
760                                 }
761                         }
762
763                         /* if not multiedit, exit loop*/
764                         if (!is_multiedit) {
765                                 break;
766                         }
767                 }
768         }
769         CTX_DATA_END;
770
771         /* notifiers */
772         if (changed) {
773                 DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
774                 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
775         }
776
777         return OPERATOR_FINISHED;
778 }
779
780 void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
781 {
782         /* identifiers */
783         ot->name = "Clean Loose points";
784         ot->idname = "GPENCIL_OT_frame_clean_loose";
785         ot->description = "Remove loose points";
786
787         /* callbacks */
788         ot->exec = gp_frame_clean_loose_exec;
789         ot->poll = gp_active_layer_poll;
790
791         /* flags */
792         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
793
794         RNA_def_int(ot->srna, "limit", 1, 1, INT_MAX, "Limit", "Number of points to consider stroke as loose", 1, INT_MAX);
795 }
796
797 /* *********************** Hide Layers ******************************** */
798
799 static int gp_hide_exec(bContext *C, wmOperator *op)
800 {
801         bGPdata *gpd = ED_gpencil_data_get_active(C);
802         bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
803         bool unselected = RNA_boolean_get(op->ptr, "unselected");
804
805         /* sanity checks */
806         if (ELEM(NULL, gpd, layer))
807                 return OPERATOR_CANCELLED;
808
809         if (unselected) {
810                 bGPDlayer *gpl;
811
812                 /* hide unselected */
813                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
814                         if (gpl != layer) {
815                                 gpl->flag |= GP_LAYER_HIDE;
816                         }
817                 }
818         }
819         else {
820                 /* hide selected/active */
821                 layer->flag |= GP_LAYER_HIDE;
822         }
823
824         /* notifiers */
825         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
826         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
827
828         return OPERATOR_FINISHED;
829 }
830
831 void GPENCIL_OT_hide(wmOperatorType *ot)
832 {
833         /* identifiers */
834         ot->name = "Hide Layer(s)";
835         ot->idname = "GPENCIL_OT_hide";
836         ot->description = "Hide selected/unselected Grease Pencil layers";
837
838         /* callbacks */
839         ot->exec = gp_hide_exec;
840         ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
841
842         /* flags */
843         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
844
845         /* props */
846         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
847 }
848
849 /* ********************** Show All Layers ***************************** */
850
851 /* poll callback for showing layers */
852 static bool gp_reveal_poll(bContext *C)
853 {
854         return ED_gpencil_data_get_active(C) != NULL;
855 }
856
857 static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select)
858 {
859         bGPDstroke *gps;
860         for (gps = frame->strokes.first; gps; gps = gps->next) {
861
862                 /* only deselect strokes that are valid in this view */
863                 if (ED_gpencil_stroke_can_use(C, gps)) {
864
865                         /* (de)select points */
866                         int i;
867                         bGPDspoint *pt;
868                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
869                                 SET_FLAG_FROM_TEST(pt->flag, select, GP_SPOINT_SELECT);
870                         }
871
872                         /* (de)select stroke */
873                         SET_FLAG_FROM_TEST(gps->flag, select, GP_STROKE_SELECT);
874                 }
875         }
876 }
877
878 static int gp_reveal_exec(bContext *C, wmOperator *op)
879 {
880         bGPdata *gpd = ED_gpencil_data_get_active(C);
881         bGPDlayer *gpl;
882         const bool select = RNA_boolean_get(op->ptr, "select");
883
884         /* sanity checks */
885         if (gpd == NULL)
886                 return OPERATOR_CANCELLED;
887
888         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
889
890                 if (gpl->flag & GP_LAYER_HIDE) {
891                         gpl->flag &= ~GP_LAYER_HIDE;
892
893                         /* select or deselect if requested, only on hidden layers */
894                         if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
895                                 if (select) {
896                                         /* select all strokes on active frame only (same as select all operator) */
897                                         if (gpl->actframe) {
898                                                 gp_reveal_select_frame(C, gpl->actframe, true);
899                                         }
900                                 }
901                                 else {
902                                         /* deselect strokes on all frames (same as deselect all operator) */
903                                         bGPDframe *gpf;
904                                         for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
905                                                 gp_reveal_select_frame(C, gpf, false);
906                                         }
907                                 }
908                         }
909                 }
910         }
911
912         /* notifiers */
913         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
914         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
915
916         return OPERATOR_FINISHED;
917 }
918
919 void GPENCIL_OT_reveal(wmOperatorType *ot)
920 {
921         /* identifiers */
922         ot->name = "Show All Layers";
923         ot->idname = "GPENCIL_OT_reveal";
924         ot->description = "Show all Grease Pencil layers";
925
926         /* callbacks */
927         ot->exec = gp_reveal_exec;
928         ot->poll = gp_reveal_poll;
929
930         /* flags */
931         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
932
933         /* props */
934         RNA_def_boolean(ot->srna, "select", true, "Select", "");
935 }
936
937 /* ***************** Lock/Unlock All Layers ************************ */
938
939 static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
940 {
941         bGPdata *gpd = ED_gpencil_data_get_active(C);
942         bGPDlayer *gpl;
943
944         /* sanity checks */
945         if (gpd == NULL)
946                 return OPERATOR_CANCELLED;
947
948         /* make all layers non-editable */
949         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
950                 gpl->flag |= GP_LAYER_LOCKED;
951         }
952
953         /* notifiers */
954         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
955         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
956
957         return OPERATOR_FINISHED;
958 }
959
960 void GPENCIL_OT_lock_all(wmOperatorType *ot)
961 {
962         /* identifiers */
963         ot->name = "Lock All Layers";
964         ot->idname = "GPENCIL_OT_lock_all";
965         ot->description = "Lock all Grease Pencil layers to prevent them from being accidentally modified";
966
967         /* callbacks */
968         ot->exec = gp_lock_all_exec;
969         ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
970
971         /* flags */
972         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
973 }
974
975 /* -------------------------- */
976
977 static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
978 {
979         bGPdata *gpd = ED_gpencil_data_get_active(C);
980         bGPDlayer *gpl;
981
982         /* sanity checks */
983         if (gpd == NULL)
984                 return OPERATOR_CANCELLED;
985
986         /* make all layers editable again */
987         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
988                 gpl->flag &= ~GP_LAYER_LOCKED;
989         }
990
991         /* notifiers */
992         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
993         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
994
995         return OPERATOR_FINISHED;
996 }
997
998 void GPENCIL_OT_unlock_all(wmOperatorType *ot)
999 {
1000         /* identifiers */
1001         ot->name = "Unlock All Layers";
1002         ot->idname = "GPENCIL_OT_unlock_all";
1003         ot->description = "Unlock all Grease Pencil layers so that they can be edited";
1004
1005         /* callbacks */
1006         ot->exec = gp_unlock_all_exec;
1007         ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
1008
1009         /* flags */
1010         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1011 }
1012
1013 /* ********************** Isolate Layer **************************** */
1014
1015 static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
1016 {
1017         bGPdata *gpd = ED_gpencil_data_get_active(C);
1018         bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
1019         bGPDlayer *gpl;
1020         int flags = GP_LAYER_LOCKED;
1021         bool isolate = false;
1022
1023         if (RNA_boolean_get(op->ptr, "affect_visibility"))
1024                 flags |= GP_LAYER_HIDE;
1025
1026         if (ELEM(NULL, gpd, layer)) {
1027                 BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
1028                 return OPERATOR_CANCELLED;
1029         }
1030
1031         /* Test whether to isolate or clear all flags */
1032         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1033                 /* Skip if this is the active layer */
1034                 if (gpl == layer)
1035                         continue;
1036
1037                 /* If the flags aren't set, that means that the layer is
1038                  * not alone, so we have some layers to isolate still
1039                  */
1040                 if ((gpl->flag & flags) == 0) {
1041                         isolate = true;
1042                         break;
1043                 }
1044         }
1045
1046         /* Set/Clear flags as appropriate */
1047         /* TODO: Include onionskinning on this list? */
1048         if (isolate) {
1049                 /* Set flags on all "other" layers */
1050                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1051                         if (gpl == layer)
1052                                 continue;
1053                         else
1054                                 gpl->flag |= flags;
1055                 }
1056         }
1057         else {
1058                 /* Clear flags - Restore everything else */
1059                 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1060                         gpl->flag &= ~flags;
1061                 }
1062         }
1063
1064         /* notifiers */
1065         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1066         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1067
1068         return OPERATOR_FINISHED;
1069 }
1070
1071 void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
1072 {
1073         /* identifiers */
1074         ot->name = "Isolate Layer";
1075         ot->idname = "GPENCIL_OT_layer_isolate";
1076         ot->description = "Toggle whether the active layer is the only one that can be edited and/or visible";
1077
1078         /* callbacks */
1079         ot->exec = gp_isolate_layer_exec;
1080         ot->poll = gp_active_layer_poll;
1081
1082         /* flags */
1083         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1084
1085         /* properties */
1086         RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility",
1087                         "In addition to toggling the editability, also affect the visibility");
1088 }
1089
1090 /* ********************** Merge Layer with the next layer **************************** */
1091
1092 static int gp_merge_layer_exec(bContext *C, wmOperator *op)
1093 {
1094         bGPdata *gpd = ED_gpencil_data_get_active(C);
1095         bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd);
1096         bGPDlayer *gpl_current = gpl_next->prev;
1097
1098         if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
1099                 BKE_report(op->reports, RPT_ERROR, "No layers to merge");
1100                 return OPERATOR_CANCELLED;
1101         }
1102
1103         /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
1104         GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
1105         for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
1106                 BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
1107         }
1108
1109         /* read all frames from next layer and add any missing in current layer */
1110         for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
1111                 /* try to find frame in current layer */
1112                 bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
1113                 if (!frame) {
1114                         bGPDframe *actframe = BKE_gpencil_layer_getframe(gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
1115                         frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
1116                         /* duplicate strokes of current active frame */
1117                         if (actframe) {
1118                                 BKE_gpencil_frame_copy_strokes(actframe, frame);
1119                         }
1120                 }
1121                 /* add to tail all strokes */
1122                 BLI_movelisttolist(&frame->strokes, &gpf->strokes);
1123         }
1124
1125         /* Now delete next layer */
1126         BKE_gpencil_layer_delete(gpd, gpl_next);
1127         BLI_ghash_free(gh_frames_cur, NULL, NULL);
1128
1129         /* notifiers */
1130         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1131         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1132
1133         return OPERATOR_FINISHED;
1134 }
1135
1136 void GPENCIL_OT_layer_merge(wmOperatorType *ot)
1137 {
1138         /* identifiers */
1139         ot->name = "Merge Down";
1140         ot->idname = "GPENCIL_OT_layer_merge";
1141         ot->description = "Merge the current layer with the layer below";
1142
1143         /* callbacks */
1144         ot->exec = gp_merge_layer_exec;
1145         ot->poll = gp_active_layer_poll;
1146
1147         /* flags */
1148         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1149 }
1150
1151 /* ********************** Change Layer ***************************** */
1152
1153 static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
1154 {
1155         uiPopupMenu *pup;
1156         uiLayout *layout;
1157
1158         /* call the menu, which will call this operator again, hence the canceled */
1159         pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
1160         layout = UI_popup_menu_layout(pup);
1161         uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
1162         UI_popup_menu_end(C, pup);
1163
1164         return OPERATOR_INTERFACE;
1165 }
1166
1167 static int gp_layer_change_exec(bContext *C, wmOperator *op)
1168 {
1169         bGPdata *gpd = CTX_data_gpencil_data(C);
1170         bGPDlayer *gpl = NULL;
1171         int layer_num = RNA_enum_get(op->ptr, "layer");
1172
1173         /* Get layer or create new one */
1174         if (layer_num == -1) {
1175                 /* Create layer */
1176                 gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
1177         }
1178         else {
1179                 /* Try to get layer */
1180                 gpl = BLI_findlink(&gpd->layers, layer_num);
1181
1182                 if (gpl == NULL) {
1183                         BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
1184                         return OPERATOR_CANCELLED;
1185                 }
1186         }
1187
1188         /* Set active layer */
1189         BKE_gpencil_layer_setactive(gpd, gpl);
1190
1191         /* updates */
1192         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1193         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1194
1195         return OPERATOR_FINISHED;
1196 }
1197
1198 void GPENCIL_OT_layer_change(wmOperatorType *ot)
1199 {
1200         /* identifiers */
1201         ot->name = "Change Layer";
1202         ot->idname = "GPENCIL_OT_layer_change";
1203         ot->description = "Change active Grease Pencil layer";
1204
1205         /* callbacks */
1206         ot->invoke = gp_layer_change_invoke;
1207         ot->exec = gp_layer_change_exec;
1208         ot->poll = gp_active_layer_poll;
1209
1210         /* flags */
1211         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1212
1213         /* gp layer to use (dynamic enum) */
1214         ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
1215         RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
1216 }
1217
1218 /* ************************************************ */
1219
1220 /* ******************* Arrange Stroke Up/Down in drawing order ************************** */
1221
1222 enum {
1223         GP_STROKE_MOVE_UP = -1,
1224         GP_STROKE_MOVE_DOWN = 1,
1225         GP_STROKE_MOVE_TOP = 2,
1226         GP_STROKE_MOVE_BOTTOM = 3,
1227 };
1228
1229 static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
1230 {
1231         Object *ob = CTX_data_active_object(C);
1232         bGPdata *gpd = ED_gpencil_data_get_active(C);
1233         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
1234         bGPDstroke *gps;
1235
1236         /* sanity checks */
1237         if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
1238                 return OPERATOR_CANCELLED;
1239         }
1240
1241         const int direction = RNA_enum_get(op->ptr, "direction");
1242
1243         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1244                 /* temp listbase to store selected strokes by layer */
1245                 ListBase selected = { NULL };
1246                 bGPDframe *gpf = gpl->actframe;
1247                 if (gpl->flag & GP_LAYER_LOCKED) {
1248                         continue;
1249                 }
1250
1251                 if (gpf == NULL) {
1252                         continue;
1253                 }
1254                 bool gpf_lock = false;
1255                 /* verify if any selected stroke is in the extreme of the stack and select to move */
1256                 for (gps = gpf->strokes.first; gps; gps = gps->next) {
1257                         /* only if selected */
1258                         if (gps->flag & GP_STROKE_SELECT) {
1259                                 /* skip strokes that are invalid for current view */
1260                                 if (ED_gpencil_stroke_can_use(C, gps) == false) {
1261                                         continue;
1262                                 }
1263                                 /* check if the color is editable */
1264                                 if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
1265                                         continue;
1266                                 }
1267                                 /* some stroke is already at front*/
1268                                 if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
1269                                         if (gps == gpf->strokes.last) {
1270                                                 gpf_lock = true;
1271                                                 continue;
1272                                         }
1273                                 }
1274                                 /* some stroke is already at botom */
1275                                 if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
1276                                         if (gps == gpf->strokes.first) {
1277                                                 gpf_lock = true;
1278                                                 continue;
1279                                         }
1280                                 }
1281                                 /* add to list (if not locked) */
1282                                 if (!gpf_lock) {
1283                                         BLI_addtail(&selected, BLI_genericNodeN(gps));
1284                                 }
1285                         }
1286                 }
1287                 /* Now do the movement of the stroke */
1288                 if (!gpf_lock) {
1289                         switch (direction) {
1290                                 /* Bring to Front */
1291                                 case GP_STROKE_MOVE_TOP:
1292                                         for (LinkData *link = selected.first; link; link = link->next) {
1293                                                 gps = link->data;
1294                                                 BLI_remlink(&gpf->strokes, gps);
1295                                                 BLI_addtail(&gpf->strokes, gps);
1296                                         }
1297                                         break;
1298                                 /* Bring Forward */
1299                                 case GP_STROKE_MOVE_UP:
1300                                         for (LinkData *link = selected.last; link; link = link->prev) {
1301                                                 gps = link->data;
1302                                                 BLI_listbase_link_move(&gpf->strokes, gps, 1);
1303                                         }
1304                                         break;
1305                                 /* Send Backward */
1306                                 case GP_STROKE_MOVE_DOWN:
1307                                         for (LinkData *link = selected.first; link; link = link->next) {
1308                                                 gps = link->data;
1309                                                 BLI_listbase_link_move(&gpf->strokes, gps, -1);
1310                                         }
1311                                         break;
1312                                 /* Send to Back */
1313                                 case GP_STROKE_MOVE_BOTTOM:
1314                                         for (LinkData *link = selected.last; link; link = link->prev) {
1315                                                 gps = link->data;
1316                                                 BLI_remlink(&gpf->strokes, gps);
1317                                                 BLI_addhead(&gpf->strokes, gps);
1318                                         }
1319                                         break;
1320                                 default:
1321                                         BLI_assert(0);
1322                                         break;
1323                         }
1324                 }
1325                 BLI_freelistN(&selected);
1326         }
1327
1328         /* notifiers */
1329         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1330         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1331
1332         return OPERATOR_FINISHED;
1333 }
1334
1335 void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
1336 {
1337         static const EnumPropertyItem slot_move[] = {
1338                 {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
1339                 {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
1340                 {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
1341                 {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
1342                 {0, NULL, 0, NULL, NULL }
1343         };
1344
1345         /* identifiers */
1346         ot->name = "Arrange Stroke";
1347         ot->idname = "GPENCIL_OT_stroke_arrange";
1348         ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
1349
1350         /* callbacks */
1351         ot->exec = gp_stroke_arrange_exec;
1352         ot->poll = gp_active_layer_poll;
1353
1354         /* flags */
1355         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1356
1357         /* properties */
1358         ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
1359 }
1360
1361 /* ******************* Move Stroke to new color ************************** */
1362
1363 static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
1364 {
1365         Main *bmain = CTX_data_main(C);
1366         Material *ma = NULL;
1367         char name[MAX_ID_NAME - 2];
1368         RNA_string_get(op->ptr, "material", name);
1369
1370         bGPdata *gpd = ED_gpencil_data_get_active(C);
1371         Object *ob = CTX_data_active_object(C);
1372         if (name[0] == '\0') {
1373                 ma = give_current_material(ob, ob->actcol);
1374         }
1375         else {
1376                 ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
1377                 if (ma == NULL) {
1378                         return OPERATOR_CANCELLED;
1379                 }
1380         }
1381         /* try to find slot */
1382         int idx = BKE_gpencil_object_material_get_index(ob, ma);
1383         if (idx < 0) {
1384                 return OPERATOR_CANCELLED;
1385         }
1386
1387         /* sanity checks */
1388         if (ELEM(NULL, gpd)) {
1389                 return OPERATOR_CANCELLED;
1390         }
1391
1392         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1393         if (ELEM(NULL, ma)) {
1394                 return OPERATOR_CANCELLED;
1395         }
1396
1397         /* loop all strokes */
1398         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
1399         {
1400                 bGPDframe *init_gpf = gpl->actframe;
1401                 if (is_multiedit) {
1402                         init_gpf = gpl->frames.first;
1403                 }
1404
1405                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
1406                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
1407                                 if (gpf == NULL)
1408                                         continue;
1409
1410                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
1411                                         /* only if selected */
1412                                         if (gps->flag & GP_STROKE_SELECT) {
1413                                                 /* skip strokes that are invalid for current view */
1414                                                 if (ED_gpencil_stroke_can_use(C, gps) == false)
1415                                                         continue;
1416                                                 /* check if the color is editable */
1417                                                 if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
1418                                                         continue;
1419
1420                                                 /* assign new color */
1421                                                 gps->mat_nr = idx;
1422                                         }
1423                                 }
1424                         }
1425                         /* if not multiedit, exit loop*/
1426                         if (!is_multiedit) {
1427                                 break;
1428                         }
1429
1430                 }
1431         }
1432         CTX_DATA_END;
1433
1434         /* notifiers */
1435         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1436         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1437
1438         return OPERATOR_FINISHED;
1439 }
1440
1441 void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
1442 {
1443         /* identifiers */
1444         ot->name = "Change Stroke Color";
1445         ot->idname = "GPENCIL_OT_stroke_change_color";
1446         ot->description = "Move selected strokes to active material";
1447
1448         /* callbacks */
1449         ot->exec = gp_stroke_change_color_exec;
1450         ot->poll = gp_active_layer_poll;
1451
1452         /* flags */
1453         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1454
1455         RNA_def_string(ot->srna, "material", NULL, MAX_ID_NAME - 2, "Material", "Name of the material");
1456
1457 }
1458
1459 /* ******************* Lock color of non selected Strokes colors ************************** */
1460
1461 static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
1462 {
1463         bGPdata *gpd = ED_gpencil_data_get_active(C);
1464
1465         Object *ob = CTX_data_active_object(C);
1466
1467         short *totcol = give_totcolp(ob);
1468
1469         /* sanity checks */
1470         if (ELEM(NULL, gpd))
1471                 return OPERATOR_CANCELLED;
1472
1473         /* first lock all colors */
1474         for (short i = 0; i < *totcol; i++) {
1475                 Material *tmp_ma = give_current_material(ob, i + 1);
1476                 tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
1477                 DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
1478         }
1479
1480         /* loop all selected strokes and unlock any color */
1481         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
1482                 /* only editable and visible layers are considered */
1483                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
1484                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
1485                                 /* only if selected */
1486                                 if (gps->flag & GP_STROKE_SELECT) {
1487                                         /* skip strokes that are invalid for current view */
1488                                         if (ED_gpencil_stroke_can_use(C, gps) == false) {
1489                                                 continue;
1490                                         }
1491                                         /* unlock color */
1492                                         Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
1493
1494                                         tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
1495                                         DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
1496                                 }
1497                         }
1498                 }
1499         }
1500         /* updates */
1501         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
1502
1503         /* copy on write tag is needed, or else no refresh happens */
1504         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
1505
1506         /* notifiers */
1507         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1508         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1509
1510         return OPERATOR_FINISHED;
1511 }
1512
1513 void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
1514 {
1515         /* identifiers */
1516         ot->name = "Lock Unused Colors";
1517         ot->idname = "GPENCIL_OT_stroke_lock_color";
1518         ot->description = "Lock any color not used in any selected stroke";
1519
1520         /* api callbacks */
1521         ot->exec = gp_stroke_lock_color_exec;
1522         ot->poll = gp_active_layer_poll;
1523
1524         /* flags */
1525         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1526 }
1527
1528 /* ************************************************ */
1529 /* Drawing Brushes Operators */
1530
1531 /* ******************* Brush create presets ************************** */
1532 static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
1533 {
1534         BKE_brush_gpencil_presets(C);
1535
1536         /* notifiers */
1537         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
1538
1539         return OPERATOR_FINISHED;
1540 }
1541
1542 void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
1543 {
1544         /* identifiers */
1545         ot->name = "Create Preset Brushes";
1546         ot->idname = "GPENCIL_OT_brush_presets_create";
1547         ot->description = "Create a set of predefined Grease Pencil drawing brushes";
1548
1549         /* api callbacks */
1550         ot->exec = gp_brush_presets_create_exec;
1551
1552         /* flags */
1553         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1554
1555 }
1556
1557 /*********************** Vertex Groups ***********************************/
1558
1559 static bool gpencil_vertex_group_poll(bContext *C)
1560 {
1561         Object *ob = CTX_data_active_object(C);
1562
1563         if ((ob) && (ob->type == OB_GPENCIL)) {
1564                 if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
1565                         if (ELEM(ob->mode,
1566                                  OB_MODE_EDIT_GPENCIL,
1567                                  OB_MODE_SCULPT_GPENCIL))
1568                         {
1569                                 return true;
1570                         }
1571                 }
1572         }
1573
1574         return false;
1575 }
1576
1577 static bool gpencil_vertex_group_weight_poll(bContext *C)
1578 {
1579         Object *ob = CTX_data_active_object(C);
1580
1581         if ((ob) && (ob->type == OB_GPENCIL)) {
1582                 if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
1583                         if (ob->mode == OB_MODE_WEIGHT_GPENCIL) {
1584                                 return true;
1585                         }
1586                 }
1587         }
1588
1589         return false;
1590 }
1591
1592 static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
1593 {
1594         ToolSettings *ts = CTX_data_tool_settings(C);
1595         Object *ob = CTX_data_active_object(C);
1596
1597         /* sanity checks */
1598         if (ELEM(NULL, ts, ob, ob->data))
1599                 return OPERATOR_CANCELLED;
1600
1601         ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight);
1602
1603         /* notifiers */
1604         bGPdata *gpd = ob->data;
1605         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1606         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1607
1608         return OPERATOR_FINISHED;
1609 }
1610
1611 void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot)
1612 {
1613         /* identifiers */
1614         ot->name = "Assign to Vertex Group";
1615         ot->idname = "GPENCIL_OT_vertex_group_assign";
1616         ot->description = "Assign the selected vertices to the active vertex group";
1617
1618         /* api callbacks */
1619         ot->poll = gpencil_vertex_group_poll;
1620         ot->exec = gpencil_vertex_group_assign_exec;
1621
1622         /* flags */
1623         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1624 }
1625
1626 /* remove point from vertex group */
1627 static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
1628 {
1629         Object *ob = CTX_data_active_object(C);
1630
1631         /* sanity checks */
1632         if (ELEM(NULL, ob, ob->data))
1633                 return OPERATOR_CANCELLED;
1634
1635         ED_gpencil_vgroup_remove(C, ob);
1636
1637         /* notifiers */
1638         bGPdata *gpd = ob->data;
1639         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1640         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1641
1642         return OPERATOR_FINISHED;
1643 }
1644
1645 void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot)
1646 {
1647         /* identifiers */
1648         ot->name = "Remove from Vertex Group";
1649         ot->idname = "GPENCIL_OT_vertex_group_remove_from";
1650         ot->description = "Remove the selected vertices from active or all vertex group(s)";
1651
1652         /* api callbacks */
1653         ot->poll = gpencil_vertex_group_poll;
1654         ot->exec = gpencil_vertex_group_remove_from_exec;
1655
1656         /* flags */
1657         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1658
1659 }
1660
1661 static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
1662 {
1663         Object *ob = CTX_data_active_object(C);
1664
1665         /* sanity checks */
1666         if (ELEM(NULL, ob, ob->data))
1667                 return OPERATOR_CANCELLED;
1668
1669         ED_gpencil_vgroup_select(C, ob);
1670
1671         /* notifiers */
1672         bGPdata *gpd = ob->data;
1673         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1674         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1675
1676         return OPERATOR_FINISHED;
1677 }
1678
1679 void GPENCIL_OT_vertex_group_select(wmOperatorType *ot)
1680 {
1681         /* identifiers */
1682         ot->name = "Select Vertex Group";
1683         ot->idname = "GPENCIL_OT_vertex_group_select";
1684         ot->description = "Select all the vertices assigned to the active vertex group";
1685
1686         /* api callbacks */
1687         ot->poll = gpencil_vertex_group_poll;
1688         ot->exec = gpencil_vertex_group_select_exec;
1689
1690         /* flags */
1691         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1692 }
1693
1694 static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
1695 {
1696         Object *ob = CTX_data_active_object(C);
1697
1698         /* sanity checks */
1699         if (ELEM(NULL, ob, ob->data))
1700                 return OPERATOR_CANCELLED;
1701
1702         ED_gpencil_vgroup_deselect(C, ob);
1703
1704         /* notifiers */
1705         bGPdata *gpd = ob->data;
1706         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1707         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1708
1709         return OPERATOR_FINISHED;
1710 }
1711
1712 void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot)
1713 {
1714         /* identifiers */
1715         ot->name = "Deselect Vertex Group";
1716         ot->idname = "GPENCIL_OT_vertex_group_deselect";
1717         ot->description = "Deselect all selected vertices assigned to the active vertex group";
1718
1719         /* api callbacks */
1720         ot->poll = gpencil_vertex_group_poll;
1721         ot->exec = gpencil_vertex_group_deselect_exec;
1722
1723         /* flags */
1724         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1725 }
1726
1727 /* invert */
1728 static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *UNUSED(op))
1729 {
1730         ToolSettings *ts = CTX_data_tool_settings(C);
1731         Object *ob = CTX_data_active_object(C);
1732
1733         /* sanity checks */
1734         if (ELEM(NULL, ts, ob, ob->data))
1735                 return OPERATOR_CANCELLED;
1736
1737         MDeformVert *dvert;
1738         const int def_nr = ob->actdef - 1;
1739         if (!BLI_findlink(&ob->defbase, def_nr))
1740                 return OPERATOR_CANCELLED;
1741
1742         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1743         {
1744                 for (int i = 0; i < gps->totpoints; i++) {
1745                         dvert = &gps->dvert[i];
1746                         MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1747                         if (dw == NULL) {
1748                                 defvert_add_index_notest(dvert, def_nr, 1.0f);
1749                         }
1750                         else if (dw->weight == 1.0f) {
1751                                 defvert_remove_group(dvert, dw);
1752                         }
1753                         else {
1754                                 dw->weight = 1.0f - dw->weight;
1755                         }
1756                 }
1757         }
1758         CTX_DATA_END;
1759
1760         /* notifiers */
1761         bGPdata *gpd = ob->data;
1762         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1763         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1764
1765         return OPERATOR_FINISHED;
1766 }
1767
1768 void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
1769 {
1770         /* identifiers */
1771         ot->name = "Invert Vertex Group";
1772         ot->idname = "GPENCIL_OT_vertex_group_invert";
1773         ot->description = "Invert weights to the active vertex group";
1774
1775         /* api callbacks */
1776         ot->poll = gpencil_vertex_group_weight_poll;
1777         ot->exec = gpencil_vertex_group_invert_exec;
1778
1779         /* flags */
1780         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1781 }
1782
1783 /* smooth */
1784 static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
1785 {
1786         const float fac = RNA_float_get(op->ptr, "factor");
1787         const int repeat = RNA_int_get(op->ptr, "repeat");
1788
1789         ToolSettings *ts = CTX_data_tool_settings(C);
1790         Object *ob = CTX_data_active_object(C);
1791
1792         /* sanity checks */
1793         if (ELEM(NULL, ts, ob, ob->data))
1794                 return OPERATOR_CANCELLED;
1795
1796         bGPDspoint *pta, *ptb, *ptc;
1797         MDeformVert *dverta, *dvertb;
1798
1799         const int def_nr = ob->actdef - 1;
1800         if (!BLI_findlink(&ob->defbase, def_nr))
1801                 return OPERATOR_CANCELLED;
1802
1803         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1804         {
1805                 if (gps->dvert == NULL) {
1806                         continue;
1807                 }
1808
1809                 for (int s = 0; s < repeat; s++) {
1810                         for (int i = 0; i < gps->totpoints; i++) {
1811                                 /* previous point */
1812                                 if (i > 0) {
1813                                         pta = &gps->points[i - 1];
1814                                         dverta = &gps->dvert[i - 1];
1815                                 }
1816                                 else {
1817                                         pta = &gps->points[i];
1818                                         dverta = &gps->dvert[i];
1819                                 }
1820                                 /* current */
1821                                 ptb = &gps->points[i];
1822                                 dvertb = &gps->dvert[i];
1823                                 /* next point */
1824                                 if (i + 1 < gps->totpoints) {
1825                                         ptc = &gps->points[i + 1];
1826                                 }
1827                                 else {
1828                                         ptc = &gps->points[i];
1829                                 }
1830
1831                                 float wa = defvert_find_weight(dverta, def_nr);
1832                                 float wb = defvert_find_weight(dvertb, def_nr);
1833
1834                                 /* the optimal value is the corresponding to the interpolation of the weight
1835                                  * at the distance of point b
1836                                  */
1837                                 const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
1838                                 const float optimal = interpf(wa, wb, opfac);
1839                                 /* Based on influence factor, blend between original and optimal */
1840                                 MDeformWeight *dw = defvert_verify_index(dvertb, def_nr);
1841                                 if (dw) {
1842                                         dw->weight = interpf(wb, optimal, fac);
1843                                         CLAMP(dw->weight, 0.0, 1.0f);
1844                                 }
1845                         }
1846                 }
1847         }
1848         CTX_DATA_END;
1849
1850         /* notifiers */
1851         bGPdata *gpd = ob->data;
1852         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1853         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1854
1855         return OPERATOR_FINISHED;
1856 }
1857
1858 void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
1859 {
1860         /* identifiers */
1861         ot->name = "Smooth Vertex Group";
1862         ot->idname = "GPENCIL_OT_vertex_group_smooth";
1863         ot->description = "Smooth weights to the active vertex group";
1864
1865         /* api callbacks */
1866         ot->poll = gpencil_vertex_group_weight_poll;
1867         ot->exec = gpencil_vertex_group_smooth_exec;
1868
1869         /* flags */
1870         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1871
1872         RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
1873         RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
1874 }
1875
1876 /* normalize */
1877 static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
1878 {
1879         ToolSettings *ts = CTX_data_tool_settings(C);
1880         Object *ob = CTX_data_active_object(C);
1881
1882         /* sanity checks */
1883         if (ELEM(NULL, ts, ob, ob->data))
1884                 return OPERATOR_CANCELLED;
1885
1886         MDeformVert *dvert;
1887         const int def_nr = ob->actdef - 1;
1888         if (!BLI_findlink(&ob->defbase, def_nr))
1889                 return OPERATOR_CANCELLED;
1890
1891         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1892         {
1893                 /* look for max value */
1894                 float maxvalue = 0.0f;
1895                 for (int i = 0; i < gps->totpoints; i++) {
1896                         dvert = &gps->dvert[i];
1897                         MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1898                         if ((dw != NULL) &&     (dw->weight > maxvalue)) {
1899                                 maxvalue = dw->weight;
1900                         }
1901                 }
1902
1903                 /* normalize weights */
1904                 if (maxvalue > 0.0f) {
1905                         for (int i = 0; i < gps->totpoints; i++) {
1906                                 dvert = &gps->dvert[i];
1907                                 MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1908                                 if (dw != NULL) {
1909                                         dw->weight = dw->weight / maxvalue;
1910                                 }
1911                         }
1912                 }
1913         }
1914         CTX_DATA_END;
1915
1916         /* notifiers */
1917         bGPdata *gpd = ob->data;
1918         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1919         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1920
1921         return OPERATOR_FINISHED;
1922 }
1923
1924 void GPENCIL_OT_vertex_group_normalize(wmOperatorType *ot)
1925 {
1926         /* identifiers */
1927         ot->name = "Normalize Vertex Group";
1928         ot->idname = "GPENCIL_OT_vertex_group_normalize";
1929         ot->description = "Normalize weights to the active vertex group";
1930
1931         /* api callbacks */
1932         ot->poll = gpencil_vertex_group_weight_poll;
1933         ot->exec = gpencil_vertex_group_normalize_exec;
1934
1935         /* flags */
1936         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1937 }
1938
1939 /****************************** Join ***********************************/
1940
1941 /* userdata for joined_gpencil_fix_animdata_cb() */
1942 typedef struct tJoinGPencil_AdtFixData {
1943         bGPdata *src_gpd;
1944         bGPdata *tar_gpd;
1945
1946         GHash *names_map;
1947 } tJoinGPencil_AdtFixData;
1948
1949 /* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */
1950 static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
1951 {
1952         tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
1953         ID *src_id = &afd->src_gpd->id;
1954         ID *dst_id = &afd->tar_gpd->id;
1955
1956         GHashIterator gh_iter;
1957
1958         /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
1959         if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
1960                 GHASH_ITER(gh_iter, afd->names_map) {
1961                         const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
1962                         const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
1963
1964                         /* only remap if changed;
1965                          * this still means there will be some waste if there aren't many drivers/keys */
1966                         if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
1967                                 fcu->rna_path = BKE_animsys_fix_rna_path_rename(
1968                                         id, fcu->rna_path, "layers",
1969                                         old_name, new_name, 0, 0, false);
1970
1971                                 /* we don't want to apply a second remapping on this F-Curve now,
1972                                  * so stop trying to fix names names
1973                                  */
1974                                 break;
1975                         }
1976                 }
1977         }
1978
1979         /* Fix driver targets */
1980         if (fcu->driver) {
1981                 /* Fix driver references to invalid ID's */
1982                 for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
1983                         /* only change the used targets, since the others will need fixing manually anyway */
1984                         DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
1985                         {
1986                                 /* change the ID's used... */
1987                                 if (dtar->id == src_id) {
1988                                         dtar->id = dst_id;
1989
1990                                         /* also check on the subtarget...
1991                                          * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
1992                                          *      little twists so that we know that it isn't going to clobber the wrong data
1993                                          */
1994                                         if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
1995                                                 GHASH_ITER(gh_iter, afd->names_map) {
1996                                                         const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
1997                                                         const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
1998
1999                                                         /* only remap if changed */
2000                                                         if (!STREQ(old_name, new_name)) {
2001                                                                 if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
2002                                                                         /* Fix up path */
2003                                                                         dtar->rna_path = BKE_animsys_fix_rna_path_rename(
2004                                                                                 id, dtar->rna_path, "layers",
2005                                                                                 old_name, new_name, 0, 0, false);
2006                                                                         break; /* no need to try any more names for layer path */
2007                                                                 }
2008                                                         }
2009                                                 }
2010                                         }
2011                                 }
2012                         }
2013                         DRIVER_TARGETS_LOOPER_END;
2014                 }
2015         }
2016 }
2017
2018 /* join objects called from OBJECT_OT_join */
2019 int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
2020 {
2021         Main *bmain = CTX_data_main(C);
2022         Scene *scene = CTX_data_scene(C);
2023         Depsgraph *depsgraph = CTX_data_depsgraph(C);
2024         Object  *ob_active = CTX_data_active_object(C);
2025         bGPdata *gpd_dst = NULL;
2026         bool ok = false;
2027
2028         /* Ensure we're in right mode and that the active object is correct */
2029         if (!ob_active || ob_active->type != OB_GPENCIL)
2030                 return OPERATOR_CANCELLED;
2031
2032         bGPdata *gpd = (bGPdata *)ob_active->data;
2033         if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
2034                 return OPERATOR_CANCELLED;
2035         }
2036
2037         /* Ensure all rotations are applied before */
2038         // XXX: Why don't we apply them here instead of warning?
2039         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2040         {
2041                 if (ob_iter->type == OB_GPENCIL) {
2042                         if ((ob_iter->rot[0] != 0) ||
2043                             (ob_iter->rot[1] != 0) ||
2044                             (ob_iter->rot[2] != 0))
2045                         {
2046                                 BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
2047                                 return OPERATOR_CANCELLED;
2048                         }
2049                 }
2050         }
2051         CTX_DATA_END;
2052
2053         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2054         {
2055                 if (ob_iter == ob_active) {
2056                         ok = true;
2057                         break;
2058                 }
2059         }
2060         CTX_DATA_END;
2061
2062         /* that way the active object is always selected */
2063         if (ok == false) {
2064                 BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
2065                 return OPERATOR_CANCELLED;
2066         }
2067
2068         gpd_dst = ob_active->data;
2069         Object *ob_dst = ob_active;
2070
2071         /* loop and join all data */
2072         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2073         {
2074                 if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
2075                         /* we assume that each datablock is not already used in active object */
2076                         if (ob_active->data != ob_iter->data) {
2077                                 Object *ob_src = ob_iter;
2078                                 bGPdata *gpd_src = ob_iter->data;
2079
2080                                 /* Apply all GP modifiers before */
2081                                 for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
2082                                         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
2083                                         if (mti->bakeModifier) {
2084                                                 mti->bakeModifier(bmain, depsgraph, md, ob_iter);
2085                                         }
2086                                 }
2087
2088                                 /* copy vertex groups to the base one's */
2089                                 int old_idx = 0;
2090                                 for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
2091                                         bDeformGroup *vgroup = MEM_dupallocN(dg);
2092                                         int idx = BLI_listbase_count(&ob_active->defbase);
2093                                         defgroup_unique_name(vgroup, ob_active);
2094                                         BLI_addtail(&ob_active->defbase, vgroup);
2095                                         /* update vertex groups in strokes in original data */
2096                                         for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
2097                                                 for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
2098                                                         for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2099                                                                 MDeformVert *dvert;
2100                                                                 int i;
2101                                                                 for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
2102                                                                         if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
2103                                                                                 dvert->dw->def_nr = idx;
2104                                                                         }
2105                                                                 }
2106                                                         }
2107                                                 }
2108                                         }
2109                                         old_idx++;
2110                                 }
2111                                 if (ob_active->defbase.first && ob_active->actdef == 0) {
2112                                         ob_active->actdef = 1;
2113                                 }
2114
2115                                 /* add missing materials reading source materials and checking in destination object */
2116                                 short *totcol = give_totcolp(ob_src);
2117
2118                                 for (short i = 0; i < *totcol; i++) {
2119                                         Material *tmp_ma = give_current_material(ob_src, i + 1);
2120                                         BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
2121                                 }
2122
2123                                 /* duplicate bGPDlayers  */
2124                                 tJoinGPencil_AdtFixData afd = {0};
2125                                 afd.src_gpd = gpd_src;
2126                                 afd.tar_gpd = gpd_dst;
2127                                 afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
2128
2129                                 float imat[3][3], bmat[3][3];
2130                                 float offset_global[3];
2131                                 float offset_local[3];
2132
2133                                 sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
2134                                 copy_m3_m4(bmat, ob_active->obmat);
2135                                 invert_m3_m3(imat, bmat);
2136                                 mul_m3_v3(imat, offset_global);
2137                                 mul_v3_m3v3(offset_local, imat, offset_global);
2138
2139
2140                                 for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
2141                                         bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
2142                                         float diff_mat[4][4];
2143                                         float inverse_diff_mat[4][4];
2144
2145                                         /* recalculate all stroke points */
2146                                         ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
2147                                         invert_m4_m4(inverse_diff_mat, diff_mat);
2148
2149                                         Material *ma_src = NULL;
2150                                         for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
2151                                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2152
2153                                                         /* reasign material. Look old material and try to find in dst */
2154                                                         ma_src = give_current_material(ob_src, gps->mat_nr + 1);
2155                                                         gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
2156
2157                                                         bGPDspoint *pt;
2158                                                         int i;
2159                                                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2160                                                                 float mpt[3];
2161                                                                 mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
2162                                                                 sub_v3_v3(mpt, offset_local);
2163                                                                 mul_v3_m4v3(&pt->x, diff_mat, mpt);
2164                                                         }
2165                                                 }
2166                                         }
2167
2168                                         /* be sure name is unique in new object */
2169                                         BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info));
2170                                         BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
2171
2172                                         /* add to destination datablock */
2173                                         BLI_addtail(&gpd_dst->layers, gpl_new);
2174                                 }
2175
2176                                 /* Fix all the animation data */
2177                                 BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
2178                                 BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
2179
2180                                 /* Only copy over animdata now, after all the remapping has been done,
2181                                  * so that we don't have to worry about ambiguities re which datablock
2182                                  * a layer came from!
2183                                  */
2184                                 if (ob_iter->adt) {
2185                                         if (ob_active->adt == NULL) {
2186                                                 /* no animdata, so just use a copy of the whole thing */
2187                                                 ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
2188                                         }
2189                                         else {
2190                                                 /* merge in data - we'll fix the drivers manually */
2191                                                 BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
2192                                         }
2193                                 }
2194
2195                                 if (gpd_src->adt) {
2196                                         if (gpd_dst->adt == NULL) {
2197                                                 /* no animdata, so just use a copy of the whole thing */
2198                                                 gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
2199                                         }
2200                                         else {
2201                                                 /* merge in data - we'll fix the drivers manually */
2202                                                 BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
2203                                         }
2204                                 }
2205                                 DEG_id_tag_update(&gpd_src->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
2206                         }
2207
2208                         /* Free the old object */
2209                         ED_object_base_free_and_unlink(bmain, scene, ob_iter);
2210                 }
2211         }
2212         CTX_DATA_END;
2213
2214         DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
2215         DEG_relations_tag_update(bmain);  /* because we removed object(s) */
2216
2217         WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
2218
2219         return OPERATOR_FINISHED;
2220 }
2221
2222 /* Color Handle operator */
2223 static bool gpencil_active_color_poll(bContext *C)
2224 {
2225         Object *ob = CTX_data_active_object(C);
2226         if (ob && ob->data && (ob->type == OB_GPENCIL)) {
2227                 short *totcolp = give_totcolp(ob);
2228                 return *totcolp > 0;
2229         }
2230         return false;
2231 }
2232
2233
2234 /* ******************* Lock and hide any color non used in current layer ************************** */
2235 static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
2236 {
2237         bGPdata *gpd = ED_gpencil_data_get_active(C);
2238         Object *ob = CTX_data_active_object(C);
2239         MaterialGPencilStyle *gp_style = NULL;
2240
2241         /* sanity checks */
2242         if (ELEM(NULL, gpd))
2243                 return OPERATOR_CANCELLED;
2244
2245         /* first lock and hide all colors */
2246         Material *ma = NULL;
2247         short *totcol = give_totcolp(ob);
2248         if (totcol == 0)
2249                 return OPERATOR_CANCELLED;
2250
2251         for (short i = 0; i < *totcol; i++) {
2252                 ma = give_current_material(ob, i + 1);
2253                 gp_style = ma->gp_style;
2254                 gp_style->flag |= GP_STYLE_COLOR_LOCKED;
2255                 gp_style->flag |= GP_STYLE_COLOR_HIDE;
2256                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2257         }
2258
2259         /* loop all selected strokes and unlock any color used in active layer */
2260         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
2261                 /* only editable and visible layers are considered */
2262                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) {
2263                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
2264                                 /* skip strokes that are invalid for current view */
2265                                 if (ED_gpencil_stroke_can_use(C, gps) == false)
2266                                         continue;
2267
2268                                 ma = give_current_material(ob, gps->mat_nr + 1);
2269                                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2270
2271                                 gp_style = ma->gp_style;
2272                                 /* unlock/unhide color if not unlocked before */
2273                                 if (gp_style != NULL) {
2274                                         gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
2275                                         gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
2276                                 }
2277                         }
2278                 }
2279         }
2280         /* updates */
2281         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2282
2283         /* copy on write tag is needed, or else no refresh happens */
2284         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2285
2286         /* notifiers */
2287         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
2288         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2289
2290         return OPERATOR_FINISHED;
2291 }
2292
2293 void GPENCIL_OT_lock_layer(wmOperatorType *ot)
2294 {
2295         /* identifiers */
2296         ot->name = "Disable Unused Layer Colors";
2297         ot->idname = "GPENCIL_OT_lock_layer";
2298         ot->description = "Lock and hide any color not used in any layer";
2299
2300         /* api callbacks */
2301         ot->exec = gpencil_lock_layer_exec;
2302         ot->poll = gp_active_layer_poll;
2303 }
2304
2305 /* ********************** Isolate gpencil_ color **************************** */
2306
2307 static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
2308 {
2309         bGPdata *gpd = ED_gpencil_data_get_active(C);
2310         Object *ob = CTX_data_active_object(C);
2311         Material *active_ma = give_current_material(ob, ob->actcol);
2312         MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
2313         MaterialGPencilStyle *gp_style;
2314
2315         int flags = GP_STYLE_COLOR_LOCKED;
2316         bool isolate = false;
2317
2318         if (RNA_boolean_get(op->ptr, "affect_visibility"))
2319                 flags |= GP_STYLE_COLOR_HIDE;
2320
2321         if (ELEM(NULL, gpd, active_color)) {
2322                 BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
2323                 return OPERATOR_CANCELLED;
2324         }
2325
2326         /* Test whether to isolate or clear all flags */
2327         Material *ma = NULL;
2328         short *totcol = give_totcolp(ob);
2329         for (short i = 0; i < *totcol; i++) {
2330                 ma = give_current_material(ob, i + 1);
2331                 /* Skip if this is the active one */
2332                 if (ma == active_ma)
2333                         continue;
2334
2335                 /* If the flags aren't set, that means that the color is
2336                  * not alone, so we have some colors to isolate still
2337                  */
2338                 gp_style = ma->gp_style;
2339                 if ((gp_style->flag & flags) == 0) {
2340                         isolate = true;
2341                         break;
2342                 }
2343         }
2344
2345         /* Set/Clear flags as appropriate */
2346         if (isolate) {
2347                 /* Set flags on all "other" colors */
2348                 for (short i = 0; i < *totcol; i++) {
2349                         ma = give_current_material(ob, i + 1);
2350                         gp_style = ma->gp_style;
2351                         if (gp_style == active_color)
2352                                 continue;
2353                         else
2354                                 gp_style->flag |= flags;
2355                         DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2356                 }
2357         }
2358         else {
2359                 /* Clear flags - Restore everything else */
2360                 for (short i = 0; i < *totcol; i++) {
2361                         ma = give_current_material(ob, i + 1);
2362                         gp_style = ma->gp_style;
2363                         gp_style->flag &= ~flags;
2364                         DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2365                 }
2366         }
2367
2368         /* notifiers */
2369         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2370
2371         /* copy on write tag is needed, or else no refresh happens */
2372         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2373
2374         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2375
2376         return OPERATOR_FINISHED;
2377 }
2378
2379 void GPENCIL_OT_color_isolate(wmOperatorType *ot)
2380 {
2381         /* identifiers */
2382         ot->name = "Isolate Color";
2383         ot->idname = "GPENCIL_OT_color_isolate";
2384         ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
2385
2386         /* callbacks */
2387         ot->exec = gpencil_color_isolate_exec;
2388         ot->poll = gpencil_active_color_poll;
2389
2390         /* flags */
2391         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2392
2393         /* properties */
2394         RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
2395                 "the editability, also affect the visibility");
2396 }
2397
2398 /* *********************** Hide colors ******************************** */
2399
2400 static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
2401 {
2402         Object *ob = CTX_data_active_object(C);
2403         bGPdata *gpd = (bGPdata *)ob->data;
2404         MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
2405
2406         bool unselected = RNA_boolean_get(op->ptr, "unselected");
2407
2408         Material *ma = NULL;
2409         short *totcol = give_totcolp(ob);
2410         if (totcol == 0)
2411                 return OPERATOR_CANCELLED;
2412
2413         if (unselected) {
2414                 /* hide unselected */
2415                 MaterialGPencilStyle *color = NULL;
2416                 for (short i = 0; i < *totcol; i++) {
2417                         ma = give_current_material(ob, i + 1);
2418                         color = ma->gp_style;
2419                         if (active_color != color) {
2420                                 color->flag |= GP_STYLE_COLOR_HIDE;
2421                                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2422                         }
2423                 }
2424         }
2425         else {
2426                 /* hide selected/active */
2427                 active_color->flag |= GP_STYLE_COLOR_HIDE;
2428         }
2429
2430         /* updates */
2431         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
2432
2433         /* copy on write tag is needed, or else no refresh happens */
2434         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2435
2436         /* notifiers */
2437         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2438
2439         return OPERATOR_FINISHED;
2440 }
2441
2442 void GPENCIL_OT_color_hide(wmOperatorType *ot)
2443 {
2444         /* identifiers */
2445         ot->name = "Hide Color(s)";
2446         ot->idname = "GPENCIL_OT_color_hide";
2447         ot->description = "Hide selected/unselected Grease Pencil colors";
2448
2449         /* callbacks */
2450         ot->exec = gpencil_color_hide_exec;
2451         ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
2452
2453                                                                                   /* flags */
2454         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2455
2456         /* props */
2457         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
2458 }
2459
2460 /* ********************** Show All Colors ***************************** */
2461
2462 static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
2463 {
2464         Object *ob = CTX_data_active_object(C);
2465         bGPdata *gpd = (bGPdata *)ob->data;
2466         Material *ma = NULL;
2467         short *totcol = give_totcolp(ob);
2468
2469         if (totcol == 0)
2470                 return OPERATOR_CANCELLED;
2471
2472         /* make all colors visible */
2473         MaterialGPencilStyle *gp_style = NULL;
2474
2475         for (short i = 0; i < *totcol; i++) {
2476                 ma = give_current_material(ob, i + 1);
2477                 gp_style = ma->gp_style;
2478                 gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
2479                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2480         }
2481
2482         /* updates */
2483         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2484
2485         /* copy on write tag is needed, or else no refresh happens */
2486         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2487
2488         /* notifiers */
2489         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2490
2491         return OPERATOR_FINISHED;
2492 }
2493
2494 void GPENCIL_OT_color_reveal(wmOperatorType *ot)
2495 {
2496         /* identifiers */
2497         ot->name = "Show All Colors";
2498         ot->idname = "GPENCIL_OT_color_reveal";
2499         ot->description = "Unhide all hidden Grease Pencil colors";
2500
2501         /* callbacks */
2502         ot->exec = gpencil_color_reveal_exec;
2503         ot->poll = gpencil_active_color_poll;
2504
2505         /* flags */
2506         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2507 }
2508
2509 /* ***************** Lock/Unlock All colors ************************ */
2510
2511 static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
2512 {
2513
2514         Object *ob = CTX_data_active_object(C);
2515         bGPdata *gpd = (bGPdata *)ob->data;
2516         Material *ma = NULL;
2517         short *totcol = give_totcolp(ob);
2518
2519         if (totcol == 0)
2520                 return OPERATOR_CANCELLED;
2521
2522         /* make all layers non-editable */
2523         MaterialGPencilStyle *gp_style = NULL;
2524
2525         for (short i = 0; i < *totcol; i++) {
2526                 ma = give_current_material(ob, i + 1);
2527                 gp_style = ma->gp_style;
2528                 gp_style->flag |= GP_STYLE_COLOR_LOCKED;
2529                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2530         }
2531
2532         /* updates */
2533         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2534
2535         /* copy on write tag is needed, or else no refresh happens */
2536         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2537
2538         /* notifiers */
2539         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2540
2541         return OPERATOR_FINISHED;
2542 }
2543
2544 void GPENCIL_OT_color_lock_all(wmOperatorType *ot)
2545 {
2546         /* identifiers */
2547         ot->name = "Lock All Colors";
2548         ot->idname = "GPENCIL_OT_color_lock_all";
2549         ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
2550
2551         /* callbacks */
2552         ot->exec = gpencil_color_lock_all_exec;
2553         ot->poll = gpencil_active_color_poll;
2554
2555         /* flags */
2556         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2557 }
2558
2559 /* -------------------------- */
2560
2561 static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
2562 {
2563         Object *ob = CTX_data_active_object(C);
2564         bGPdata *gpd = (bGPdata *)ob->data;
2565         Material *ma = NULL;
2566         short *totcol = give_totcolp(ob);
2567
2568         if (totcol == 0)
2569                 return OPERATOR_CANCELLED;
2570
2571         /* make all layers editable again*/
2572         MaterialGPencilStyle *gp_style = NULL;
2573
2574         for (short i = 0; i < *totcol; i++) {
2575                 ma = give_current_material(ob, i + 1);
2576                 gp_style = ma->gp_style;
2577                 gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
2578                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2579         }
2580
2581         /* updates */
2582         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2583
2584         /* copy on write tag is needed, or else no refresh happens */
2585         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2586
2587         /* notifiers */
2588         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2589
2590         return OPERATOR_FINISHED;
2591 }
2592
2593 void GPENCIL_OT_color_unlock_all(wmOperatorType *ot)
2594 {
2595         /* identifiers */
2596         ot->name = "Unlock All Colors";
2597         ot->idname = "GPENCIL_OT_color_unlock_all";
2598         ot->description = "Unlock all Grease Pencil colors so that they can be edited";
2599
2600         /* callbacks */
2601         ot->exec = gpencil_color_unlock_all_exec;
2602         ot->poll = gpencil_active_color_poll;
2603
2604         /* flags */
2605         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2606 }
2607
2608
2609 /* ***************** Select all strokes using color ************************ */
2610
2611 static int gpencil_color_select_exec(bContext *C, wmOperator *op)
2612 {
2613         bGPdata *gpd = ED_gpencil_data_get_active(C);
2614         Object *ob = CTX_data_active_object(C);
2615         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
2616         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
2617         const bool deselected = RNA_boolean_get(op->ptr, "deselect");
2618
2619         /* sanity checks */
2620         if (ELEM(NULL, gpd, gp_style))
2621                 return OPERATOR_CANCELLED;
2622
2623         /* read all strokes and select*/
2624         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
2625         {
2626                 bGPDframe *init_gpf = gpl->actframe;
2627                 if (is_multiedit) {
2628                         init_gpf = gpl->frames.first;
2629                 }
2630                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
2631                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
2632
2633                                 /* verify something to do */
2634                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2635                                         /* skip strokes that are invalid for current view */
2636                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
2637                                                 continue;
2638                                         /* check if the color is editable */
2639                                         if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
2640                                                 continue;
2641
2642                                         /* select */
2643                                         if (ob->actcol == gps->mat_nr + 1) {
2644                                                 bGPDspoint *pt;
2645                                                 int i;
2646
2647                                                 if (!deselected) {
2648                                                         gps->flag |= GP_STROKE_SELECT;
2649                                                 }
2650                                                 else {
2651                                                         gps->flag &= ~GP_STROKE_SELECT;
2652                                                 }
2653                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2654                                                         if (!deselected) {
2655                                                                 pt->flag |= GP_SPOINT_SELECT;
2656                                                         }
2657                                                         else {
2658                                                                 pt->flag &= ~GP_SPOINT_SELECT;
2659                                                         }
2660                                                 }
2661                                         }
2662                                 }
2663                         }
2664                         /* if not multiedit, exit loop*/
2665                         if (!is_multiedit) {
2666                                 break;
2667                         }
2668
2669                 }
2670         }
2671         CTX_DATA_END;
2672
2673         /* copy on write tag is needed, or else no refresh happens */
2674         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2675
2676         /* notifiers */
2677         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2678
2679         return OPERATOR_FINISHED;
2680 }
2681
2682 void GPENCIL_OT_color_select(wmOperatorType *ot)
2683 {
2684         /* identifiers */
2685         ot->name = "Select Color";
2686         ot->idname = "GPENCIL_OT_color_select";
2687         ot->description = "Select all Grease Pencil strokes using current color";
2688
2689         /* callbacks */
2690         ot->exec = gpencil_color_select_exec;
2691         ot->poll = gpencil_active_color_poll;
2692
2693         /* flags */
2694         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2695
2696         /* props */
2697         ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
2698         RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2699 }