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