UI: Add shortcuts for grease pencil modifier panels
[blender.git] / source / blender / editors / object / object_gpencil_modifier.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2018 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edobj
22  */
23
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_gpencil_modifier_types.h"
32 #include "DNA_gpencil_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35
36 #include "BLI_listbase.h"
37 #include "BLI_string_utf8.h"
38 #include "BLI_utildefines.h"
39
40 #include "BKE_context.h"
41 #include "BKE_gpencil.h"
42 #include "BKE_gpencil_modifier.h"
43 #include "BKE_main.h"
44 #include "BKE_object.h"
45 #include "BKE_report.h"
46
47 #include "DEG_depsgraph.h"
48 #include "DEG_depsgraph_build.h"
49 #include "DEG_depsgraph_query.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53 #include "RNA_enum_types.h"
54
55 #include "ED_object.h"
56 #include "ED_screen.h"
57
58 #include "UI_interface.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "object_intern.h"
64
65 /******************************** API ****************************/
66
67 GpencilModifierData *ED_object_gpencil_modifier_add(
68     ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
69 {
70   GpencilModifierData *new_md = NULL;
71   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
72
73   if (ob->type != OB_GPENCIL) {
74     BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
75     return NULL;
76   }
77
78   if (mti->flags & eGpencilModifierTypeFlag_Single) {
79     if (BKE_gpencil_modifiers_findby_type(ob, type)) {
80       BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
81       return NULL;
82     }
83   }
84
85   /* get new modifier data to add */
86   new_md = BKE_gpencil_modifier_new(type);
87
88   BLI_addtail(&ob->greasepencil_modifiers, new_md);
89
90   if (name) {
91     BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name));
92   }
93
94   /* make sure modifier data has unique name */
95   BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
96
97   /* Enable edit mode visible by default. */
98   if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
99     new_md->mode |= eGpencilModifierMode_Editmode;
100   }
101
102   bGPdata *gpd = ob->data;
103   DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
104
105   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
106   DEG_relations_tag_update(bmain);
107
108   return new_md;
109 }
110
111 static bool gpencil_object_modifier_remove(Main *bmain,
112                                            Object *ob,
113                                            GpencilModifierData *md,
114                                            bool *UNUSED(r_sort_depsgraph))
115 {
116   /* It seems on rapid delete it is possible to
117    * get called twice on same modifier, so make
118    * sure it is in list. */
119   if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) {
120     return 0;
121   }
122
123   DEG_relations_tag_update(bmain);
124
125   BLI_remlink(&ob->greasepencil_modifiers, md);
126   BKE_gpencil_modifier_free(md);
127   BKE_object_free_derived_caches(ob);
128
129   return 1;
130 }
131
132 bool ED_object_gpencil_modifier_remove(ReportList *reports,
133                                        Main *bmain,
134                                        Object *ob,
135                                        GpencilModifierData *md)
136 {
137   bool sort_depsgraph = false;
138   bool ok;
139
140   ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
141
142   if (!ok) {
143     BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
144     return 0;
145   }
146
147   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
148   DEG_relations_tag_update(bmain);
149
150   return 1;
151 }
152
153 void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob)
154 {
155   GpencilModifierData *md = ob->greasepencil_modifiers.first;
156   bool sort_depsgraph = false;
157
158   if (!md) {
159     return;
160   }
161
162   while (md) {
163     GpencilModifierData *next_md;
164
165     next_md = md->next;
166
167     gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
168
169     md = next_md;
170   }
171
172   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
173   DEG_relations_tag_update(bmain);
174 }
175
176 int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports),
177                                        Object *ob,
178                                        GpencilModifierData *md)
179 {
180   if (md->prev) {
181     BLI_remlink(&ob->greasepencil_modifiers, md);
182     BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md);
183   }
184
185   return 1;
186 }
187
188 int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports),
189                                          Object *ob,
190                                          GpencilModifierData *md)
191 {
192   if (md->next) {
193     BLI_remlink(&ob->greasepencil_modifiers, md);
194     BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md);
195   }
196
197   return 1;
198 }
199
200 bool ED_object_gpencil_modifier_move_to_index(ReportList *reports,
201                                               Object *ob,
202                                               GpencilModifierData *md,
203                                               const int index)
204 {
205   BLI_assert(md != NULL);
206   BLI_assert(index >= 0);
207   if (index >= BLI_listbase_count(&ob->greasepencil_modifiers)) {
208     BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the stack");
209     return false;
210   }
211
212   int md_index = BLI_findindex(&ob->greasepencil_modifiers, md);
213   BLI_assert(md_index != -1);
214   if (md_index < index) {
215     /* Move modifier down in list. */
216     for (; md_index < index; md_index++) {
217       if (!ED_object_gpencil_modifier_move_down(reports, ob, md)) {
218         break;
219       }
220     }
221   }
222   else {
223     /* Move modifier up in list. */
224     for (; md_index > index; md_index--) {
225       if (!ED_object_gpencil_modifier_move_up(reports, ob, md)) {
226         break;
227       }
228     }
229   }
230
231   return true;
232 }
233
234 static int gpencil_modifier_apply_obdata(
235     ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
236 {
237   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
238
239   if (mti->isDisabled && mti->isDisabled(md, 0)) {
240     BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
241     return 0;
242   }
243
244   if (ob->type == OB_GPENCIL) {
245     if (ELEM(NULL, ob, ob->data)) {
246       return 0;
247     }
248     else if (mti->bakeModifier == NULL) {
249       BKE_report(reports, RPT_ERROR, "Not implemented");
250       return 0;
251     }
252     mti->bakeModifier(bmain, depsgraph, md, ob);
253     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
254   }
255   else {
256     BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
257     return 0;
258   }
259
260   return 1;
261 }
262
263 int ED_object_gpencil_modifier_apply(Main *bmain,
264                                      ReportList *reports,
265                                      Depsgraph *depsgraph,
266                                      Object *ob,
267                                      GpencilModifierData *md,
268                                      int UNUSED(mode))
269 {
270
271   if (ob->type == OB_GPENCIL) {
272     if (ob->mode != OB_MODE_OBJECT) {
273       BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode");
274       return 0;
275     }
276
277     if (((ID *)ob->data)->us > 1) {
278       BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
279       return 0;
280     }
281   }
282   else if (((ID *)ob->data)->us > 1) {
283     BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
284     return 0;
285   }
286
287   if (md != ob->greasepencil_modifiers.first) {
288     BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
289   }
290
291   if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) {
292     return 0;
293   }
294
295   BLI_remlink(&ob->greasepencil_modifiers, md);
296   BKE_gpencil_modifier_free(md);
297
298   return 1;
299 }
300
301 int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
302 {
303   GpencilModifierData *nmd;
304   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
305   GpencilModifierType type = md->type;
306
307   if (mti->flags & eGpencilModifierTypeFlag_Single) {
308     if (BKE_gpencil_modifiers_findby_type(ob, type)) {
309       BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
310       return 0;
311     }
312   }
313
314   nmd = BKE_gpencil_modifier_new(md->type);
315   BKE_gpencil_modifier_copydata(md, nmd);
316   BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
317   BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
318
319   return 1;
320 }
321
322 /************************ add modifier operator *********************/
323
324 static int gpencil_modifier_add_exec(bContext *C, wmOperator *op)
325 {
326   Main *bmain = CTX_data_main(C);
327   Scene *scene = CTX_data_scene(C);
328   Object *ob = ED_object_active_context(C);
329   int type = RNA_enum_get(op->ptr, "type");
330
331   if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) {
332     return OPERATOR_CANCELLED;
333   }
334
335   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
336
337   return OPERATOR_FINISHED;
338 }
339
340 static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C,
341                                                           PointerRNA *UNUSED(ptr),
342                                                           PropertyRNA *UNUSED(prop),
343                                                           bool *r_free)
344 {
345   Object *ob = ED_object_active_context(C);
346   EnumPropertyItem *item = NULL;
347   const EnumPropertyItem *md_item, *group_item = NULL;
348   const GpencilModifierTypeInfo *mti;
349   int totitem = 0, a;
350
351   if (!ob) {
352     return rna_enum_object_greasepencil_modifier_type_items;
353   }
354
355   for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
356     md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
357     if (md_item->identifier[0]) {
358       mti = BKE_gpencil_modifier_get_info(md_item->value);
359
360       if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) {
361         continue;
362       }
363     }
364     else {
365       group_item = md_item;
366       md_item = NULL;
367
368       continue;
369     }
370
371     if (group_item) {
372       RNA_enum_item_add(&item, &totitem, group_item);
373       group_item = NULL;
374     }
375
376     RNA_enum_item_add(&item, &totitem, md_item);
377   }
378
379   RNA_enum_item_end(&item, &totitem);
380   *r_free = true;
381
382   return item;
383 }
384
385 void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
386 {
387   PropertyRNA *prop;
388
389   /* identifiers */
390   ot->name = "Add Modifier";
391   ot->description = "Add a procedural operation/effect to the active grease pencil object";
392   ot->idname = "OBJECT_OT_gpencil_modifier_add";
393
394   /* api callbacks */
395   ot->invoke = WM_menu_invoke;
396   ot->exec = gpencil_modifier_add_exec;
397   ot->poll = ED_operator_object_active_editable;
398
399   /* flags */
400   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
401
402   /* properties */
403   prop = RNA_def_enum(ot->srna,
404                       "type",
405                       rna_enum_object_modifier_type_items,
406                       eGpencilModifierType_Thick,
407                       "Type",
408                       "");
409   RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf);
410   ot->prop = prop;
411 }
412
413 /********** generic functions for operators using mod names and data context *********************/
414
415 static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
416 {
417   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
418   Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
419
420   if (!ob || ID_IS_LINKED(ob)) {
421     return 0;
422   }
423   if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) {
424     return 0;
425   }
426   if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) {
427     return 0;
428   }
429
430   if (ID_IS_OVERRIDE_LIBRARY(ob)) {
431     CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override");
432     return (((GpencilModifierData *)ptr.data)->flag &
433             eGpencilModifierFlag_OverrideLibrary_Local) != 0;
434   }
435
436   return 1;
437 }
438
439 static bool gpencil_edit_modifier_poll(bContext *C)
440 {
441   return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0);
442 }
443
444 static void gpencil_edit_modifier_properties(wmOperatorType *ot)
445 {
446   PropertyRNA *prop = RNA_def_string(
447       ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
448   RNA_def_property_flag(prop, PROP_HIDDEN);
449 }
450
451 static void gpencil_edit_modifier_report_property(wmOperatorType *ot)
452 {
453   PropertyRNA *prop = RNA_def_boolean(
454       ot->srna, "report", false, "Report", "Create a notification after the operation");
455   RNA_def_property_flag(prop, PROP_HIDDEN);
456 }
457
458 /**
459  * \param event: If this isn't NULL, the operator will also look for panels underneath
460  * the cursor with customdata set to a modifier.
461  * \param r_retval: This should be used if #event is used in order to to return
462  * #OPERATOR_PASS_THROUGH to check other operators with the same key set.
463  */
464 static bool gpencil_edit_modifier_invoke_properties(bContext *C,
465                                                     wmOperator *op,
466                                                     const wmEvent *event,
467                                                     int *r_retval)
468 {
469   if (RNA_struct_property_is_set(op->ptr, "modifier")) {
470     return true;
471   }
472
473   PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier);
474   if (ctx_ptr.data != NULL) {
475     GpencilModifierData *md = ctx_ptr.data;
476     RNA_string_set(op->ptr, "modifier", md->name);
477     return true;
478   }
479
480   /* Check the custom data of panels under the mouse for a modifier. */
481   if (event != NULL) {
482     PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event);
483
484     if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) {
485       if (RNA_struct_is_a(panel_ptr->type, &RNA_GpencilModifier)) {
486         GpencilModifierData *md = panel_ptr->data;
487         RNA_string_set(op->ptr, "modifier", md->name);
488         return true;
489       }
490       else {
491         BLI_assert(r_retval != NULL); /* We need the return value in this case. */
492         if (r_retval != NULL) {
493           *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED);
494         }
495         return false;
496       }
497     }
498   }
499
500   if (r_retval != NULL) {
501     *r_retval = OPERATOR_CANCELLED;
502   }
503   return false;
504 }
505
506 static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
507                                                                Object *ob,
508                                                                int type)
509 {
510   char modifier_name[MAX_NAME];
511   GpencilModifierData *md;
512   RNA_string_get(op->ptr, "modifier", modifier_name);
513
514   md = BKE_gpencil_modifiers_findby_name(ob, modifier_name);
515
516   if (md && type != 0 && md->type != type) {
517     md = NULL;
518   }
519
520   return md;
521 }
522
523 /************************ remove modifier operator *********************/
524
525 static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
526 {
527   Main *bmain = CTX_data_main(C);
528   Object *ob = ED_object_active_context(C);
529   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
530
531   if (md == NULL) {
532     return OPERATOR_CANCELLED;
533   }
534
535   /* Store name temporarily for report. */
536   char name[MAX_NAME];
537   strcpy(name, md->name);
538
539   if (!ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) {
540     return OPERATOR_CANCELLED;
541   }
542
543   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
544
545   if (RNA_boolean_get(op->ptr, "report")) {
546     BKE_reportf(op->reports, RPT_INFO, "Removed modifier: %s", name);
547   }
548
549   return OPERATOR_FINISHED;
550 }
551
552 static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
553 {
554   int retval;
555   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
556     return gpencil_modifier_remove_exec(C, op);
557   }
558   else {
559     return retval;
560   }
561 }
562
563 void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot)
564 {
565   ot->name = "Remove Grease Pencil Modifier";
566   ot->description = "Remove a modifier from the active grease pencil object";
567   ot->idname = "OBJECT_OT_gpencil_modifier_remove";
568
569   ot->invoke = gpencil_modifier_remove_invoke;
570   ot->exec = gpencil_modifier_remove_exec;
571   ot->poll = gpencil_edit_modifier_poll;
572
573   /* flags */
574   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
575   gpencil_edit_modifier_properties(ot);
576   gpencil_edit_modifier_report_property(ot);
577 }
578
579 /************************ move up modifier operator *********************/
580
581 static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op)
582 {
583   Object *ob = ED_object_active_context(C);
584   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
585
586   if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) {
587     return OPERATOR_CANCELLED;
588   }
589
590   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
591   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
592
593   return OPERATOR_FINISHED;
594 }
595
596 static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event)
597 {
598   int retval;
599   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
600     return gpencil_modifier_move_up_exec(C, op);
601   }
602   else {
603     return retval;
604   }
605 }
606
607 void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot)
608 {
609   ot->name = "Move Up Modifier";
610   ot->description = "Move modifier up in the stack";
611   ot->idname = "OBJECT_OT_gpencil_modifier_move_up";
612
613   ot->invoke = gpencil_modifier_move_up_invoke;
614   ot->exec = gpencil_modifier_move_up_exec;
615   ot->poll = gpencil_edit_modifier_poll;
616
617   /* flags */
618   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
619   gpencil_edit_modifier_properties(ot);
620 }
621
622 /************************ move down modifier operator *********************/
623
624 static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op)
625 {
626   Object *ob = ED_object_active_context(C);
627   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
628
629   if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) {
630     return OPERATOR_CANCELLED;
631   }
632
633   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
634   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
635
636   return OPERATOR_FINISHED;
637 }
638
639 static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event)
640 {
641   int retval;
642   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
643     return gpencil_modifier_move_down_exec(C, op);
644   }
645   else {
646     return retval;
647   }
648 }
649
650 void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot)
651 {
652   ot->name = "Move Down Modifier";
653   ot->description = "Move modifier down in the stack";
654   ot->idname = "OBJECT_OT_gpencil_modifier_move_down";
655
656   ot->invoke = gpencil_modifier_move_down_invoke;
657   ot->exec = gpencil_modifier_move_down_exec;
658   ot->poll = gpencil_edit_modifier_poll;
659
660   /* flags */
661   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
662   gpencil_edit_modifier_properties(ot);
663 }
664
665 /* ************************* Move to Index Gpencil Modifier Operator ************************* */
666
667 static bool gpencil_modifier_move_to_index_poll(bContext *C)
668 {
669   return gpencil_edit_modifier_poll(C);
670 }
671
672 static int gpencil_modifier_move_to_index_exec(bContext *C, wmOperator *op)
673 {
674   Object *ob = ED_object_active_context(C);
675   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
676   int index = RNA_int_get(op->ptr, "index");
677
678   if (!ED_object_gpencil_modifier_move_to_index(op->reports, ob, md, index)) {
679     return OPERATOR_CANCELLED;
680   }
681
682   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
683   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
684
685   return OPERATOR_FINISHED;
686 }
687
688 static int gpencil_modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event)
689 {
690   int retval;
691   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
692     return gpencil_modifier_move_to_index_exec(C, op);
693   }
694   else {
695     return retval;
696   }
697 }
698
699 void OBJECT_OT_gpencil_modifier_move_to_index(wmOperatorType *ot)
700 {
701   ot->name = "Move Active Modifier to Index";
702   ot->idname = "OBJECT_OT_gpencil_modifier_move_to_index";
703   ot->description =
704       "Change the modifier's position in the list so it evaluates after the set number of "
705       "others";
706
707   ot->invoke = gpencil_modifier_move_to_index_invoke;
708   ot->exec = gpencil_modifier_move_to_index_exec;
709   ot->poll = gpencil_modifier_move_to_index_poll;
710
711   /* flags */
712   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
713   edit_modifier_properties(ot);
714   RNA_def_int(
715       ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the modifier to", 0, INT_MAX);
716 }
717
718 /************************ apply modifier operator *********************/
719
720 static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
721 {
722   Main *bmain = CTX_data_main(C);
723   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
724   Object *ob = ED_object_active_context(C);
725   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
726   int apply_as = RNA_enum_get(op->ptr, "apply_as");
727
728   if (md == NULL) {
729     return OPERATOR_CANCELLED;
730   }
731
732   /* Store name temporarily for report. */
733   char name[MAX_NAME];
734   strcpy(name, md->name);
735
736   if (!ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {
737     return OPERATOR_CANCELLED;
738   }
739
740   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
741   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
742
743   if (RNA_boolean_get(op->ptr, "report")) {
744     BKE_reportf(op->reports, RPT_INFO, "Applied modifier: %s", name);
745   }
746
747   return OPERATOR_FINISHED;
748 }
749
750 static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event)
751 {
752   int retval;
753   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
754     return gpencil_modifier_apply_exec(C, op);
755   }
756   else {
757     return retval;
758   }
759 }
760
761 static const EnumPropertyItem gpencil_modifier_apply_as_items[] = {
762     {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
763     {MODIFIER_APPLY_SHAPE,
764      "SHAPE",
765      0,
766      "New Shape",
767      "Apply deform-only modifier to a new shape on this object"},
768     {0, NULL, 0, NULL, NULL},
769 };
770
771 void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot)
772 {
773   ot->name = "Apply Modifier";
774   ot->description = "Apply modifier and remove from the stack";
775   ot->idname = "OBJECT_OT_gpencil_modifier_apply";
776
777   ot->invoke = gpencil_modifier_apply_invoke;
778   ot->exec = gpencil_modifier_apply_exec;
779   ot->poll = gpencil_edit_modifier_poll;
780
781   /* flags */
782   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
783
784   RNA_def_enum(ot->srna,
785                "apply_as",
786                gpencil_modifier_apply_as_items,
787                MODIFIER_APPLY_DATA,
788                "Apply as",
789                "How to apply the modifier to the geometry");
790   gpencil_edit_modifier_properties(ot);
791   gpencil_edit_modifier_report_property(ot);
792 }
793
794 /************************ copy modifier operator *********************/
795
796 static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op)
797 {
798   Object *ob = ED_object_active_context(C);
799   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
800
801   if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) {
802     return OPERATOR_CANCELLED;
803   }
804
805   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
806   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
807
808   return OPERATOR_FINISHED;
809 }
810
811 static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
812 {
813   int retval;
814   if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
815     return gpencil_modifier_copy_exec(C, op);
816   }
817   else {
818     return retval;
819   }
820 }
821
822 void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
823 {
824   ot->name = "Copy Modifier";
825   ot->description = "Duplicate modifier at the same position in the stack";
826   ot->idname = "OBJECT_OT_gpencil_modifier_copy";
827
828   ot->invoke = gpencil_modifier_copy_invoke;
829   ot->exec = gpencil_modifier_copy_exec;
830   ot->poll = gpencil_edit_modifier_poll;
831
832   /* flags */
833   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
834   gpencil_edit_modifier_properties(ot);
835 }