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