GPencil: Add lock icon to Vertex Groups list
[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 *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
1738         MDeformVert *dvert;
1739         const int def_nr = ob->actdef - 1;
1740         bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
1741         if (defgroup == NULL) {
1742                 return OPERATOR_CANCELLED;
1743         }
1744         if (defgroup->flag & DG_LOCK_WEIGHT) {
1745                 BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
1746                 return OPERATOR_CANCELLED;
1747         }
1748
1749         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1750         {
1751                 for (int i = 0; i < gps->totpoints; i++) {
1752                         dvert = &gps->dvert[i];
1753                         MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1754                         if (dw == NULL) {
1755                                 defvert_add_index_notest(dvert, def_nr, 1.0f);
1756                         }
1757                         else if (dw->weight == 1.0f) {
1758                                 defvert_remove_group(dvert, dw);
1759                         }
1760                         else {
1761                                 dw->weight = 1.0f - dw->weight;
1762                         }
1763                 }
1764         }
1765         CTX_DATA_END;
1766
1767         /* notifiers */
1768         bGPdata *gpd = ob->data;
1769         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1770         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1771
1772         return OPERATOR_FINISHED;
1773 }
1774
1775 void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
1776 {
1777         /* identifiers */
1778         ot->name = "Invert Vertex Group";
1779         ot->idname = "GPENCIL_OT_vertex_group_invert";
1780         ot->description = "Invert weights to the active vertex group";
1781
1782         /* api callbacks */
1783         ot->poll = gpencil_vertex_group_weight_poll;
1784         ot->exec = gpencil_vertex_group_invert_exec;
1785
1786         /* flags */
1787         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1788 }
1789
1790 /* smooth */
1791 static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
1792 {
1793         const float fac = RNA_float_get(op->ptr, "factor");
1794         const int repeat = RNA_int_get(op->ptr, "repeat");
1795
1796         ToolSettings *ts = CTX_data_tool_settings(C);
1797         Object *ob = CTX_data_active_object(C);
1798
1799         /* sanity checks */
1800         if (ELEM(NULL, ts, ob, ob->data)) {
1801                 return OPERATOR_CANCELLED;
1802         }
1803
1804         const int def_nr = ob->actdef - 1;
1805         bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
1806         if (defgroup == NULL) {
1807                 return OPERATOR_CANCELLED;
1808         }
1809         if (defgroup->flag & DG_LOCK_WEIGHT) {
1810                 BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
1811                 return OPERATOR_CANCELLED;
1812         }
1813
1814         bGPDspoint *pta, *ptb, *ptc;
1815         MDeformVert *dverta, *dvertb;
1816
1817         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1818         {
1819                 if (gps->dvert == NULL) {
1820                         continue;
1821                 }
1822
1823                 for (int s = 0; s < repeat; s++) {
1824                         for (int i = 0; i < gps->totpoints; i++) {
1825                                 /* previous point */
1826                                 if (i > 0) {
1827                                         pta = &gps->points[i - 1];
1828                                         dverta = &gps->dvert[i - 1];
1829                                 }
1830                                 else {
1831                                         pta = &gps->points[i];
1832                                         dverta = &gps->dvert[i];
1833                                 }
1834                                 /* current */
1835                                 ptb = &gps->points[i];
1836                                 dvertb = &gps->dvert[i];
1837                                 /* next point */
1838                                 if (i + 1 < gps->totpoints) {
1839                                         ptc = &gps->points[i + 1];
1840                                 }
1841                                 else {
1842                                         ptc = &gps->points[i];
1843                                 }
1844
1845                                 float wa = defvert_find_weight(dverta, def_nr);
1846                                 float wb = defvert_find_weight(dvertb, def_nr);
1847
1848                                 /* the optimal value is the corresponding to the interpolation of the weight
1849                                  * at the distance of point b
1850                                  */
1851                                 const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
1852                                 const float optimal = interpf(wa, wb, opfac);
1853                                 /* Based on influence factor, blend between original and optimal */
1854                                 MDeformWeight *dw = defvert_verify_index(dvertb, def_nr);
1855                                 if (dw) {
1856                                         dw->weight = interpf(wb, optimal, fac);
1857                                         CLAMP(dw->weight, 0.0, 1.0f);
1858                                 }
1859                         }
1860                 }
1861         }
1862         CTX_DATA_END;
1863
1864         /* notifiers */
1865         bGPdata *gpd = ob->data;
1866         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1867         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1868
1869         return OPERATOR_FINISHED;
1870 }
1871
1872 void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
1873 {
1874         /* identifiers */
1875         ot->name = "Smooth Vertex Group";
1876         ot->idname = "GPENCIL_OT_vertex_group_smooth";
1877         ot->description = "Smooth weights to the active vertex group";
1878
1879         /* api callbacks */
1880         ot->poll = gpencil_vertex_group_weight_poll;
1881         ot->exec = gpencil_vertex_group_smooth_exec;
1882
1883         /* flags */
1884         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1885
1886         RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
1887         RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
1888 }
1889
1890 /* normalize */
1891 static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
1892 {
1893         ToolSettings *ts = CTX_data_tool_settings(C);
1894         Object *ob = CTX_data_active_object(C);
1895
1896         /* sanity checks */
1897         if (ELEM(NULL, ts, ob, ob->data)) {
1898                 return OPERATOR_CANCELLED;
1899         }
1900
1901         MDeformVert *dvert;
1902         const int def_nr = ob->actdef - 1;
1903         bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
1904         if (defgroup == NULL) {
1905                 return OPERATOR_CANCELLED;
1906         }
1907         if (defgroup->flag & DG_LOCK_WEIGHT) {
1908                 BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
1909                 return OPERATOR_CANCELLED;
1910         }
1911
1912         CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
1913         {
1914                 /* look for max value */
1915                 float maxvalue = 0.0f;
1916                 for (int i = 0; i < gps->totpoints; i++) {
1917                         dvert = &gps->dvert[i];
1918                         MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1919                         if ((dw != NULL) &&     (dw->weight > maxvalue)) {
1920                                 maxvalue = dw->weight;
1921                         }
1922                 }
1923
1924                 /* normalize weights */
1925                 if (maxvalue > 0.0f) {
1926                         for (int i = 0; i < gps->totpoints; i++) {
1927                                 dvert = &gps->dvert[i];
1928                                 MDeformWeight *dw = defvert_find_index(dvert, def_nr);
1929                                 if (dw != NULL) {
1930                                         dw->weight = dw->weight / maxvalue;
1931                                 }
1932                         }
1933                 }
1934         }
1935         CTX_DATA_END;
1936
1937         /* notifiers */
1938         bGPdata *gpd = ob->data;
1939         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1940         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
1941
1942         return OPERATOR_FINISHED;
1943 }
1944
1945 void GPENCIL_OT_vertex_group_normalize(wmOperatorType *ot)
1946 {
1947         /* identifiers */
1948         ot->name = "Normalize Vertex Group";
1949         ot->idname = "GPENCIL_OT_vertex_group_normalize";
1950         ot->description = "Normalize weights to the active vertex group";
1951
1952         /* api callbacks */
1953         ot->poll = gpencil_vertex_group_weight_poll;
1954         ot->exec = gpencil_vertex_group_normalize_exec;
1955
1956         /* flags */
1957         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1958 }
1959
1960 /****************************** Join ***********************************/
1961
1962 /* userdata for joined_gpencil_fix_animdata_cb() */
1963 typedef struct tJoinGPencil_AdtFixData {
1964         bGPdata *src_gpd;
1965         bGPdata *tar_gpd;
1966
1967         GHash *names_map;
1968 } tJoinGPencil_AdtFixData;
1969
1970 /* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */
1971 static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
1972 {
1973         tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
1974         ID *src_id = &afd->src_gpd->id;
1975         ID *dst_id = &afd->tar_gpd->id;
1976
1977         GHashIterator gh_iter;
1978
1979         /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
1980         if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
1981                 GHASH_ITER(gh_iter, afd->names_map) {
1982                         const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
1983                         const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
1984
1985                         /* only remap if changed;
1986                          * this still means there will be some waste if there aren't many drivers/keys */
1987                         if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
1988                                 fcu->rna_path = BKE_animsys_fix_rna_path_rename(
1989                                         id, fcu->rna_path, "layers",
1990                                         old_name, new_name, 0, 0, false);
1991
1992                                 /* we don't want to apply a second remapping on this F-Curve now,
1993                                  * so stop trying to fix names names
1994                                  */
1995                                 break;
1996                         }
1997                 }
1998         }
1999
2000         /* Fix driver targets */
2001         if (fcu->driver) {
2002                 /* Fix driver references to invalid ID's */
2003                 for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
2004                         /* only change the used targets, since the others will need fixing manually anyway */
2005                         DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
2006                         {
2007                                 /* change the ID's used... */
2008                                 if (dtar->id == src_id) {
2009                                         dtar->id = dst_id;
2010
2011                                         /* also check on the subtarget...
2012                                          * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
2013                                          *      little twists so that we know that it isn't going to clobber the wrong data
2014                                          */
2015                                         if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
2016                                                 GHASH_ITER(gh_iter, afd->names_map) {
2017                                                         const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
2018                                                         const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
2019
2020                                                         /* only remap if changed */
2021                                                         if (!STREQ(old_name, new_name)) {
2022                                                                 if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
2023                                                                         /* Fix up path */
2024                                                                         dtar->rna_path = BKE_animsys_fix_rna_path_rename(
2025                                                                                 id, dtar->rna_path, "layers",
2026                                                                                 old_name, new_name, 0, 0, false);
2027                                                                         break; /* no need to try any more names for layer path */
2028                                                                 }
2029                                                         }
2030                                                 }
2031                                         }
2032                                 }
2033                         }
2034                         DRIVER_TARGETS_LOOPER_END;
2035                 }
2036         }
2037 }
2038
2039 /* join objects called from OBJECT_OT_join */
2040 int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
2041 {
2042         Main *bmain = CTX_data_main(C);
2043         Scene *scene = CTX_data_scene(C);
2044         Depsgraph *depsgraph = CTX_data_depsgraph(C);
2045         Object  *ob_active = CTX_data_active_object(C);
2046         bGPdata *gpd_dst = NULL;
2047         bool ok = false;
2048
2049         /* Ensure we're in right mode and that the active object is correct */
2050         if (!ob_active || ob_active->type != OB_GPENCIL)
2051                 return OPERATOR_CANCELLED;
2052
2053         bGPdata *gpd = (bGPdata *)ob_active->data;
2054         if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
2055                 return OPERATOR_CANCELLED;
2056         }
2057
2058         /* Ensure all rotations are applied before */
2059         // XXX: Why don't we apply them here instead of warning?
2060         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2061         {
2062                 if (ob_iter->type == OB_GPENCIL) {
2063                         if ((ob_iter->rot[0] != 0) ||
2064                             (ob_iter->rot[1] != 0) ||
2065                             (ob_iter->rot[2] != 0))
2066                         {
2067                                 BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
2068                                 return OPERATOR_CANCELLED;
2069                         }
2070                 }
2071         }
2072         CTX_DATA_END;
2073
2074         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2075         {
2076                 if (ob_iter == ob_active) {
2077                         ok = true;
2078                         break;
2079                 }
2080         }
2081         CTX_DATA_END;
2082
2083         /* that way the active object is always selected */
2084         if (ok == false) {
2085                 BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
2086                 return OPERATOR_CANCELLED;
2087         }
2088
2089         gpd_dst = ob_active->data;
2090         Object *ob_dst = ob_active;
2091
2092         /* loop and join all data */
2093         CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
2094         {
2095                 if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
2096                         /* we assume that each datablock is not already used in active object */
2097                         if (ob_active->data != ob_iter->data) {
2098                                 Object *ob_src = ob_iter;
2099                                 bGPdata *gpd_src = ob_iter->data;
2100
2101                                 /* Apply all GP modifiers before */
2102                                 for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
2103                                         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
2104                                         if (mti->bakeModifier) {
2105                                                 mti->bakeModifier(bmain, depsgraph, md, ob_iter);
2106                                         }
2107                                 }
2108
2109                                 /* copy vertex groups to the base one's */
2110                                 int old_idx = 0;
2111                                 for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
2112                                         bDeformGroup *vgroup = MEM_dupallocN(dg);
2113                                         int idx = BLI_listbase_count(&ob_active->defbase);
2114                                         defgroup_unique_name(vgroup, ob_active);
2115                                         BLI_addtail(&ob_active->defbase, vgroup);
2116                                         /* update vertex groups in strokes in original data */
2117                                         for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
2118                                                 for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
2119                                                         for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2120                                                                 MDeformVert *dvert;
2121                                                                 int i;
2122                                                                 for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
2123                                                                         if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
2124                                                                                 dvert->dw->def_nr = idx;
2125                                                                         }
2126                                                                 }
2127                                                         }
2128                                                 }
2129                                         }
2130                                         old_idx++;
2131                                 }
2132                                 if (ob_active->defbase.first && ob_active->actdef == 0) {
2133                                         ob_active->actdef = 1;
2134                                 }
2135
2136                                 /* add missing materials reading source materials and checking in destination object */
2137                                 short *totcol = give_totcolp(ob_src);
2138
2139                                 for (short i = 0; i < *totcol; i++) {
2140                                         Material *tmp_ma = give_current_material(ob_src, i + 1);
2141                                         BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
2142                                 }
2143
2144                                 /* duplicate bGPDlayers  */
2145                                 tJoinGPencil_AdtFixData afd = {0};
2146                                 afd.src_gpd = gpd_src;
2147                                 afd.tar_gpd = gpd_dst;
2148                                 afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
2149
2150                                 float imat[3][3], bmat[3][3];
2151                                 float offset_global[3];
2152                                 float offset_local[3];
2153
2154                                 sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
2155                                 copy_m3_m4(bmat, ob_active->obmat);
2156                                 invert_m3_m3(imat, bmat);
2157                                 mul_m3_v3(imat, offset_global);
2158                                 mul_v3_m3v3(offset_local, imat, offset_global);
2159
2160
2161                                 for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
2162                                         bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
2163                                         float diff_mat[4][4];
2164                                         float inverse_diff_mat[4][4];
2165
2166                                         /* recalculate all stroke points */
2167                                         ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
2168                                         invert_m4_m4(inverse_diff_mat, diff_mat);
2169
2170                                         Material *ma_src = NULL;
2171                                         for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
2172                                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2173
2174                                                         /* reasign material. Look old material and try to find in dst */
2175                                                         ma_src = give_current_material(ob_src, gps->mat_nr + 1);
2176                                                         gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
2177
2178                                                         bGPDspoint *pt;
2179                                                         int i;
2180                                                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2181                                                                 float mpt[3];
2182                                                                 mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
2183                                                                 sub_v3_v3(mpt, offset_local);
2184                                                                 mul_v3_m4v3(&pt->x, diff_mat, mpt);
2185                                                         }
2186                                                 }
2187                                         }
2188
2189                                         /* be sure name is unique in new object */
2190                                         BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info));
2191                                         BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
2192
2193                                         /* add to destination datablock */
2194                                         BLI_addtail(&gpd_dst->layers, gpl_new);
2195                                 }
2196
2197                                 /* Fix all the animation data */
2198                                 BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
2199                                 BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
2200
2201                                 /* Only copy over animdata now, after all the remapping has been done,
2202                                  * so that we don't have to worry about ambiguities re which datablock
2203                                  * a layer came from!
2204                                  */
2205                                 if (ob_iter->adt) {
2206                                         if (ob_active->adt == NULL) {
2207                                                 /* no animdata, so just use a copy of the whole thing */
2208                                                 ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
2209                                         }
2210                                         else {
2211                                                 /* merge in data - we'll fix the drivers manually */
2212                                                 BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
2213                                         }
2214                                 }
2215
2216                                 if (gpd_src->adt) {
2217                                         if (gpd_dst->adt == NULL) {
2218                                                 /* no animdata, so just use a copy of the whole thing */
2219                                                 gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
2220                                         }
2221                                         else {
2222                                                 /* merge in data - we'll fix the drivers manually */
2223                                                 BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
2224                                         }
2225                                 }
2226                                 DEG_id_tag_update(&gpd_src->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
2227                         }
2228
2229                         /* Free the old object */
2230                         ED_object_base_free_and_unlink(bmain, scene, ob_iter);
2231                 }
2232         }
2233         CTX_DATA_END;
2234
2235         DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
2236         DEG_relations_tag_update(bmain);  /* because we removed object(s) */
2237
2238         WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
2239
2240         return OPERATOR_FINISHED;
2241 }
2242
2243 /* Color Handle operator */
2244 static bool gpencil_active_color_poll(bContext *C)
2245 {
2246         Object *ob = CTX_data_active_object(C);
2247         if (ob && ob->data && (ob->type == OB_GPENCIL)) {
2248                 short *totcolp = give_totcolp(ob);
2249                 return *totcolp > 0;
2250         }
2251         return false;
2252 }
2253
2254
2255 /* ******************* Lock and hide any color non used in current layer ************************** */
2256 static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
2257 {
2258         bGPdata *gpd = ED_gpencil_data_get_active(C);
2259         Object *ob = CTX_data_active_object(C);
2260         MaterialGPencilStyle *gp_style = NULL;
2261
2262         /* sanity checks */
2263         if (ELEM(NULL, gpd))
2264                 return OPERATOR_CANCELLED;
2265
2266         /* first lock and hide all colors */
2267         Material *ma = NULL;
2268         short *totcol = give_totcolp(ob);
2269         if (totcol == 0)
2270                 return OPERATOR_CANCELLED;
2271
2272         for (short i = 0; i < *totcol; i++) {
2273                 ma = give_current_material(ob, i + 1);
2274                 gp_style = ma->gp_style;
2275                 gp_style->flag |= GP_STYLE_COLOR_LOCKED;
2276                 gp_style->flag |= GP_STYLE_COLOR_HIDE;
2277                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2278         }
2279
2280         /* loop all selected strokes and unlock any color used in active layer */
2281         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
2282                 /* only editable and visible layers are considered */
2283                 if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) {
2284                         for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
2285                                 /* skip strokes that are invalid for current view */
2286                                 if (ED_gpencil_stroke_can_use(C, gps) == false)
2287                                         continue;
2288
2289                                 ma = give_current_material(ob, gps->mat_nr + 1);
2290                                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2291
2292                                 gp_style = ma->gp_style;
2293                                 /* unlock/unhide color if not unlocked before */
2294                                 if (gp_style != NULL) {
2295                                         gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
2296                                         gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
2297                                 }
2298                         }
2299                 }
2300         }
2301         /* updates */
2302         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2303
2304         /* copy on write tag is needed, or else no refresh happens */
2305         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2306
2307         /* notifiers */
2308         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
2309         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2310
2311         return OPERATOR_FINISHED;
2312 }
2313
2314 void GPENCIL_OT_lock_layer(wmOperatorType *ot)
2315 {
2316         /* identifiers */
2317         ot->name = "Disable Unused Layer Colors";
2318         ot->idname = "GPENCIL_OT_lock_layer";
2319         ot->description = "Lock and hide any color not used in any layer";
2320
2321         /* api callbacks */
2322         ot->exec = gpencil_lock_layer_exec;
2323         ot->poll = gp_active_layer_poll;
2324 }
2325
2326 /* ********************** Isolate gpencil_ color **************************** */
2327
2328 static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
2329 {
2330         bGPdata *gpd = ED_gpencil_data_get_active(C);
2331         Object *ob = CTX_data_active_object(C);
2332         Material *active_ma = give_current_material(ob, ob->actcol);
2333         MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
2334         MaterialGPencilStyle *gp_style;
2335
2336         int flags = GP_STYLE_COLOR_LOCKED;
2337         bool isolate = false;
2338
2339         if (RNA_boolean_get(op->ptr, "affect_visibility"))
2340                 flags |= GP_STYLE_COLOR_HIDE;
2341
2342         if (ELEM(NULL, gpd, active_color)) {
2343                 BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
2344                 return OPERATOR_CANCELLED;
2345         }
2346
2347         /* Test whether to isolate or clear all flags */
2348         Material *ma = NULL;
2349         short *totcol = give_totcolp(ob);
2350         for (short i = 0; i < *totcol; i++) {
2351                 ma = give_current_material(ob, i + 1);
2352                 /* Skip if this is the active one */
2353                 if (ma == active_ma)
2354                         continue;
2355
2356                 /* If the flags aren't set, that means that the color is
2357                  * not alone, so we have some colors to isolate still
2358                  */
2359                 gp_style = ma->gp_style;
2360                 if ((gp_style->flag & flags) == 0) {
2361                         isolate = true;
2362                         break;
2363                 }
2364         }
2365
2366         /* Set/Clear flags as appropriate */
2367         if (isolate) {
2368                 /* Set flags on all "other" colors */
2369                 for (short i = 0; i < *totcol; i++) {
2370                         ma = give_current_material(ob, i + 1);
2371                         gp_style = ma->gp_style;
2372                         if (gp_style == active_color)
2373                                 continue;
2374                         else
2375                                 gp_style->flag |= flags;
2376                         DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2377                 }
2378         }
2379         else {
2380                 /* Clear flags - Restore everything else */
2381                 for (short i = 0; i < *totcol; i++) {
2382                         ma = give_current_material(ob, i + 1);
2383                         gp_style = ma->gp_style;
2384                         gp_style->flag &= ~flags;
2385                         DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2386                 }
2387         }
2388
2389         /* notifiers */
2390         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2391
2392         /* copy on write tag is needed, or else no refresh happens */
2393         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2394
2395         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2396
2397         return OPERATOR_FINISHED;
2398 }
2399
2400 void GPENCIL_OT_color_isolate(wmOperatorType *ot)
2401 {
2402         /* identifiers */
2403         ot->name = "Isolate Color";
2404         ot->idname = "GPENCIL_OT_color_isolate";
2405         ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
2406
2407         /* callbacks */
2408         ot->exec = gpencil_color_isolate_exec;
2409         ot->poll = gpencil_active_color_poll;
2410
2411         /* flags */
2412         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2413
2414         /* properties */
2415         RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
2416                 "the editability, also affect the visibility");
2417 }
2418
2419 /* *********************** Hide colors ******************************** */
2420
2421 static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
2422 {
2423         Object *ob = CTX_data_active_object(C);
2424         bGPdata *gpd = (bGPdata *)ob->data;
2425         MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
2426
2427         bool unselected = RNA_boolean_get(op->ptr, "unselected");
2428
2429         Material *ma = NULL;
2430         short *totcol = give_totcolp(ob);
2431         if (totcol == 0)
2432                 return OPERATOR_CANCELLED;
2433
2434         if (unselected) {
2435                 /* hide unselected */
2436                 MaterialGPencilStyle *color = NULL;
2437                 for (short i = 0; i < *totcol; i++) {
2438                         ma = give_current_material(ob, i + 1);
2439                         color = ma->gp_style;
2440                         if (active_color != color) {
2441                                 color->flag |= GP_STYLE_COLOR_HIDE;
2442                                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2443                         }
2444                 }
2445         }
2446         else {
2447                 /* hide selected/active */
2448                 active_color->flag |= GP_STYLE_COLOR_HIDE;
2449         }
2450
2451         /* updates */
2452         DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
2453
2454         /* copy on write tag is needed, or else no refresh happens */
2455         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2456
2457         /* notifiers */
2458         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2459
2460         return OPERATOR_FINISHED;
2461 }
2462
2463 void GPENCIL_OT_color_hide(wmOperatorType *ot)
2464 {
2465         /* identifiers */
2466         ot->name = "Hide Color(s)";
2467         ot->idname = "GPENCIL_OT_color_hide";
2468         ot->description = "Hide selected/unselected Grease Pencil colors";
2469
2470         /* callbacks */
2471         ot->exec = gpencil_color_hide_exec;
2472         ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
2473
2474                                                                                   /* flags */
2475         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2476
2477         /* props */
2478         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
2479 }
2480
2481 /* ********************** Show All Colors ***************************** */
2482
2483 static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
2484 {
2485         Object *ob = CTX_data_active_object(C);
2486         bGPdata *gpd = (bGPdata *)ob->data;
2487         Material *ma = NULL;
2488         short *totcol = give_totcolp(ob);
2489
2490         if (totcol == 0)
2491                 return OPERATOR_CANCELLED;
2492
2493         /* make all colors visible */
2494         MaterialGPencilStyle *gp_style = NULL;
2495
2496         for (short i = 0; i < *totcol; i++) {
2497                 ma = give_current_material(ob, i + 1);
2498                 gp_style = ma->gp_style;
2499                 gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
2500                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2501         }
2502
2503         /* updates */
2504         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2505
2506         /* copy on write tag is needed, or else no refresh happens */
2507         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2508
2509         /* notifiers */
2510         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2511
2512         return OPERATOR_FINISHED;
2513 }
2514
2515 void GPENCIL_OT_color_reveal(wmOperatorType *ot)
2516 {
2517         /* identifiers */
2518         ot->name = "Show All Colors";
2519         ot->idname = "GPENCIL_OT_color_reveal";
2520         ot->description = "Unhide all hidden Grease Pencil colors";
2521
2522         /* callbacks */
2523         ot->exec = gpencil_color_reveal_exec;
2524         ot->poll = gpencil_active_color_poll;
2525
2526         /* flags */
2527         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2528 }
2529
2530 /* ***************** Lock/Unlock All colors ************************ */
2531
2532 static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
2533 {
2534
2535         Object *ob = CTX_data_active_object(C);
2536         bGPdata *gpd = (bGPdata *)ob->data;
2537         Material *ma = NULL;
2538         short *totcol = give_totcolp(ob);
2539
2540         if (totcol == 0)
2541                 return OPERATOR_CANCELLED;
2542
2543         /* make all layers non-editable */
2544         MaterialGPencilStyle *gp_style = NULL;
2545
2546         for (short i = 0; i < *totcol; i++) {
2547                 ma = give_current_material(ob, i + 1);
2548                 gp_style = ma->gp_style;
2549                 gp_style->flag |= GP_STYLE_COLOR_LOCKED;
2550                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2551         }
2552
2553         /* updates */
2554         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2555
2556         /* copy on write tag is needed, or else no refresh happens */
2557         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2558
2559         /* notifiers */
2560         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2561
2562         return OPERATOR_FINISHED;
2563 }
2564
2565 void GPENCIL_OT_color_lock_all(wmOperatorType *ot)
2566 {
2567         /* identifiers */
2568         ot->name = "Lock All Colors";
2569         ot->idname = "GPENCIL_OT_color_lock_all";
2570         ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
2571
2572         /* callbacks */
2573         ot->exec = gpencil_color_lock_all_exec;
2574         ot->poll = gpencil_active_color_poll;
2575
2576         /* flags */
2577         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2578 }
2579
2580 /* -------------------------- */
2581
2582 static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
2583 {
2584         Object *ob = CTX_data_active_object(C);
2585         bGPdata *gpd = (bGPdata *)ob->data;
2586         Material *ma = NULL;
2587         short *totcol = give_totcolp(ob);
2588
2589         if (totcol == 0)
2590                 return OPERATOR_CANCELLED;
2591
2592         /* make all layers editable again*/
2593         MaterialGPencilStyle *gp_style = NULL;
2594
2595         for (short i = 0; i < *totcol; i++) {
2596                 ma = give_current_material(ob, i + 1);
2597                 gp_style = ma->gp_style;
2598                 gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
2599                 DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
2600         }
2601
2602         /* updates */
2603         DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
2604
2605         /* copy on write tag is needed, or else no refresh happens */
2606         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2607
2608         /* notifiers */
2609         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2610
2611         return OPERATOR_FINISHED;
2612 }
2613
2614 void GPENCIL_OT_color_unlock_all(wmOperatorType *ot)
2615 {
2616         /* identifiers */
2617         ot->name = "Unlock All Colors";
2618         ot->idname = "GPENCIL_OT_color_unlock_all";
2619         ot->description = "Unlock all Grease Pencil colors so that they can be edited";
2620
2621         /* callbacks */
2622         ot->exec = gpencil_color_unlock_all_exec;
2623         ot->poll = gpencil_active_color_poll;
2624
2625         /* flags */
2626         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2627 }
2628
2629
2630 /* ***************** Select all strokes using color ************************ */
2631
2632 static int gpencil_color_select_exec(bContext *C, wmOperator *op)
2633 {
2634         bGPdata *gpd = ED_gpencil_data_get_active(C);
2635         Object *ob = CTX_data_active_object(C);
2636         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
2637         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
2638         const bool deselected = RNA_boolean_get(op->ptr, "deselect");
2639
2640         /* sanity checks */
2641         if (ELEM(NULL, gpd, gp_style))
2642                 return OPERATOR_CANCELLED;
2643
2644         /* read all strokes and select*/
2645         CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
2646         {
2647                 bGPDframe *init_gpf = gpl->actframe;
2648                 if (is_multiedit) {
2649                         init_gpf = gpl->frames.first;
2650                 }
2651                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
2652                         if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
2653
2654                                 /* verify something to do */
2655                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
2656                                         /* skip strokes that are invalid for current view */
2657                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
2658                                                 continue;
2659                                         /* check if the color is editable */
2660                                         if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
2661                                                 continue;
2662
2663                                         /* select */
2664                                         if (ob->actcol == gps->mat_nr + 1) {
2665                                                 bGPDspoint *pt;
2666                                                 int i;
2667
2668                                                 if (!deselected) {
2669                                                         gps->flag |= GP_STROKE_SELECT;
2670                                                 }
2671                                                 else {
2672                                                         gps->flag &= ~GP_STROKE_SELECT;
2673                                                 }
2674                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
2675                                                         if (!deselected) {
2676                                                                 pt->flag |= GP_SPOINT_SELECT;
2677                                                         }
2678                                                         else {
2679                                                                 pt->flag &= ~GP_SPOINT_SELECT;
2680                                                         }
2681                                                 }
2682                                         }
2683                                 }
2684                         }
2685                         /* if not multiedit, exit loop*/
2686                         if (!is_multiedit) {
2687                                 break;
2688                         }
2689
2690                 }
2691         }
2692         CTX_DATA_END;
2693
2694         /* copy on write tag is needed, or else no refresh happens */
2695         DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
2696
2697         /* notifiers */
2698         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
2699
2700         return OPERATOR_FINISHED;
2701 }
2702
2703 void GPENCIL_OT_color_select(wmOperatorType *ot)
2704 {
2705         /* identifiers */
2706         ot->name = "Select Color";
2707         ot->idname = "GPENCIL_OT_color_select";
2708         ot->description = "Select all Grease Pencil strokes using current color";
2709
2710         /* callbacks */
2711         ot->exec = gpencil_color_select_exec;
2712         ot->poll = gpencil_active_color_poll;
2713
2714         /* flags */
2715         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2716
2717         /* props */
2718         ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
2719         RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2720 }