This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/editors/object/object_gpencil_modifier.c

702 lines
20 KiB
C
Raw Normal View History

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup edobj
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "MEM_guardedalloc.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "WM_types.h"
#include "object_intern.h"
/******************************** API ****************************/
GpencilModifierData *ED_object_gpencil_modifier_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
{
GpencilModifierData *new_md = NULL;
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
if (ob->type != OB_GPENCIL) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
return NULL;
}
if (mti->flags & eGpencilModifierTypeFlag_Single) {
if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return NULL;
}
}
/* get new modifier data to add */
new_md = BKE_gpencil_modifier_new(type);
BLI_addtail(&ob->greasepencil_modifiers, new_md);
if (name) {
BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name));
}
/* make sure modifier data has unique name */
BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
/* Enable edit mode visible by default. */
if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
new_md->mode |= eGpencilModifierMode_Editmode;
}
bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(bmain);
return new_md;
}
/* Return true if the object has a modifier of type 'type' other than
* the modifier pointed to be 'exclude', otherwise returns false. */
static bool UNUSED_FUNCTION(gpencil_object_has_modifier)(const Object *ob,
const GpencilModifierData *exclude,
GpencilModifierType type)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
2019-04-22 09:19:45 +10:00
if ((md != exclude) && (md->type == type)) {
return true;
2019-04-22 09:19:45 +10:00
}
}
return false;
}
static bool gpencil_object_modifier_remove(Main *bmain,
Object *ob,
GpencilModifierData *md,
bool *UNUSED(r_sort_depsgraph))
{
/* It seems on rapid delete it is possible to
* get called twice on same modifier, so make
* sure it is in list. */
if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) {
return 0;
}
DEG_relations_tag_update(bmain);
BLI_remlink(&ob->greasepencil_modifiers, md);
BKE_gpencil_modifier_free(md);
BKE_object_free_derived_caches(ob);
return 1;
}
bool ED_object_gpencil_modifier_remove(ReportList *reports,
Main *bmain,
Object *ob,
GpencilModifierData *md)
{
bool sort_depsgraph = false;
bool ok;
ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
return 0;
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(bmain);
return 1;
}
void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
bool sort_depsgraph = false;
2019-04-22 09:19:45 +10:00
if (!md) {
return;
2019-04-22 09:19:45 +10:00
}
while (md) {
GpencilModifierData *next_md;
next_md = md->next;
gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
md = next_md;
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(bmain);
}
int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports),
Object *ob,
GpencilModifierData *md)
{
if (md->prev) {
BLI_remlink(&ob->greasepencil_modifiers, md);
BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md);
}
return 1;
}
int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports),
Object *ob,
GpencilModifierData *md)
{
if (md->next) {
BLI_remlink(&ob->greasepencil_modifiers, md);
BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md);
}
return 1;
}
static int gpencil_modifier_apply_obdata(
ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->isDisabled && mti->isDisabled(md, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
return 0;
}
if (ob->type == OB_GPENCIL) {
if (ELEM(NULL, ob, ob->data)) {
return 0;
}
else if (mti->bakeModifier == NULL) {
BKE_report(reports, RPT_ERROR, "Not implemented");
return 0;
}
mti->bakeModifier(bmain, depsgraph, md, ob);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return 0;
}
return 1;
}
int ED_object_gpencil_modifier_apply(Main *bmain,
ReportList *reports,
Depsgraph *depsgraph,
Object *ob,
GpencilModifierData *md,
int UNUSED(mode))
{
if (ob->type == OB_GPENCIL) {
if (ob->mode != OB_MODE_OBJECT) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode");
return 0;
}
if (((ID *)ob->data)->us > 1) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
return 0;
}
}
else if (((ID *)ob->data)->us > 1) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
return 0;
}
2019-04-22 09:19:45 +10:00
if (md != ob->greasepencil_modifiers.first) {
BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
2019-04-22 09:19:45 +10:00
}
if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) {
return 0;
}
BLI_remlink(&ob->greasepencil_modifiers, md);
BKE_gpencil_modifier_free(md);
return 1;
}
int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
{
GpencilModifierData *nmd;
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
GpencilModifierType type = md->type;
if (mti->flags & eGpencilModifierTypeFlag_Single) {
if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return 0;
}
}
nmd = BKE_gpencil_modifier_new(md->type);
BKE_gpencil_modifier_copydata(md, nmd);
BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
return 1;
}
/************************ add modifier operator *********************/
static int gpencil_modifier_add_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
2019-04-22 09:19:45 +10:00
if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL;
const EnumPropertyItem *md_item, *group_item = NULL;
const GpencilModifierTypeInfo *mti;
int totitem = 0, a;
2019-04-22 09:19:45 +10:00
if (!ob) {
return rna_enum_object_greasepencil_modifier_type_items;
2019-04-22 09:19:45 +10:00
}
for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
if (md_item->identifier[0]) {
mti = BKE_gpencil_modifier_get_info(md_item->value);
2019-04-22 09:19:45 +10:00
if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) {
continue;
2019-04-22 09:19:45 +10:00
}
}
else {
group_item = md_item;
md_item = NULL;
continue;
}
if (group_item) {
RNA_enum_item_add(&item, &totitem, group_item);
group_item = NULL;
}
RNA_enum_item_add(&item, &totitem, md_item);
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Add Modifier";
ot->description = "Add a procedural operation/effect to the active grease pencil object";
ot->idname = "OBJECT_OT_gpencil_modifier_add";
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = gpencil_modifier_add_exec;
ot->poll = ED_operator_object_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_enum(ot->srna,
"type",
rna_enum_object_modifier_type_items,
eGpencilModifierType_Thick,
"Type",
"");
RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf);
ot->prop = prop;
}
/********** generic functions for operators using mod names and data context *********************/
static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
2019-04-22 09:19:45 +10:00
if (!ob || ID_IS_LINKED(ob)) {
return 0;
2019-04-22 09:19:45 +10:00
}
if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) {
return 0;
2019-04-22 09:19:45 +10:00
}
if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) {
return 0;
2019-04-22 09:19:45 +10:00
}
if (ID_IS_OVERRIDE_LIBRARY(ob)) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override");
return (((GpencilModifierData *)ptr.data)->flag &
eGpencilModifierFlag_OverrideLibrary_Local) != 0;
}
return 1;
}
static bool gpencil_edit_modifier_poll(bContext *C)
{
return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0);
}
static void gpencil_edit_modifier_properties(wmOperatorType *ot)
{
PropertyRNA *prop = RNA_def_string(
ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op)
{
GpencilModifierData *md;
if (RNA_struct_property_is_set(op->ptr, "modifier")) {
return true;
}
else {
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier);
if (ptr.data) {
md = ptr.data;
RNA_string_set(op->ptr, "modifier", md->name);
return true;
}
}
return false;
}
static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
Object *ob,
int type)
{
char modifier_name[MAX_NAME];
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
md = BKE_gpencil_modifiers_findby_name(ob, modifier_name);
2019-04-22 09:19:45 +10:00
if (md && type != 0 && md->type != type) {
md = NULL;
2019-04-22 09:19:45 +10:00
}
return md;
}
/************************ remove modifier operator *********************/
static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
2019-04-22 09:19:45 +10:00
if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int gpencil_modifier_remove_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
2019-04-22 09:19:45 +10:00
if (gpencil_edit_modifier_invoke_properties(C, op)) {
return gpencil_modifier_remove_exec(C, op);
2019-04-22 09:19:45 +10:00
}
else {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
}
void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot)
{
ot->name = "Remove Grease Pencil Modifier";
ot->description = "Remove a modifier from the active grease pencil object";
ot->idname = "OBJECT_OT_gpencil_modifier_remove";
ot->invoke = gpencil_modifier_remove_invoke;
ot->exec = gpencil_modifier_remove_exec;
ot->poll = gpencil_edit_modifier_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
/************************ move up modifier operator *********************/
static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
2019-04-22 09:19:45 +10:00
if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int gpencil_modifier_move_up_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
2019-04-22 09:19:45 +10:00
if (gpencil_edit_modifier_invoke_properties(C, op)) {
return gpencil_modifier_move_up_exec(C, op);
2019-04-22 09:19:45 +10:00
}
else {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
}
void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot)
{
ot->name = "Move Up Modifier";
ot->description = "Move modifier up in the stack";
ot->idname = "OBJECT_OT_gpencil_modifier_move_up";
ot->invoke = gpencil_modifier_move_up_invoke;
ot->exec = gpencil_modifier_move_up_exec;
ot->poll = gpencil_edit_modifier_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
/************************ move down modifier operator *********************/
static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
2019-04-22 09:19:45 +10:00
if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int gpencil_modifier_move_down_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
2019-04-22 09:19:45 +10:00
if (gpencil_edit_modifier_invoke_properties(C, op)) {
return gpencil_modifier_move_down_exec(C, op);
2019-04-22 09:19:45 +10:00
}
else {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
}
void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot)
{
ot->name = "Move Down Modifier";
ot->description = "Move modifier down in the stack";
ot->idname = "OBJECT_OT_gpencil_modifier_move_down";
ot->invoke = gpencil_modifier_move_down_invoke;
ot->exec = gpencil_modifier_move_down_exec;
ot->poll = gpencil_edit_modifier_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
/************************ apply modifier operator *********************/
static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Refactor access to dependency graph This change ensures that operators which needs access to evaluated data first makes sure there is a dependency graph. Other accesses to the dependency graph made it more explicit about whether they just need a valid dependency graph pointer or whether they expect the graph to be already evaluated. This replaces OPTYPE_USE_EVAL_DATA which is now removed. Some general rules about usage of accessors: - Drawing is expected to happen from a fully evaluated dependency graph. There is now a function to access it, which will in the future control that dependency graph is actually evaluated. This check is not yet done because there are some things to be taken care about first: for example, post-update hooks might leave scene in a state where something is still tagged for update. - All operators which needs to access evaluated state must use CTX_data_ensure_evaluated_depsgraph(). This function replaces OPTYPE_USE_EVAL_DATA. The call is generally to be done in the very beginning of the operator, prior other logic (unless this is some comprehensive operator which might or might not need access to an evaluated state). This call is never to be used from a loop. If some utility function requires evaluated state of dependency graph the graph is to be passed as an explicit argument. This way it is clear that no evaluation happens in a loop or something like this. - All cases which needs to know dependency graph pointer, but which doesn't want to actually evaluate it can use old-style function CTX_data_depsgraph_pointer(), assuming that underlying code will ensure dependency graph is evaluated prior to accessing it. - The new functions are replacing OPTYPE_USE_EVAL_DATA, so now it is explicit and local about where dependency graph is being ensured. This commit also contains some fixes of wrong usage of evaluation functions on original objects. Ideally should be split out, but in reality with all the APIs being renamed is quite tricky. Fixes T67454: Blender crash on rapid undo and select Speculation here is that sometimes undo and selection operators are sometimes handled in the same event loop iteration, which leaves non-evaluated dependency graph. Fixes T67973: Crash on Fix Deforms operator Fixes T67902: Crash when undo a loop cut Reviewers: brecht Reviewed By: brecht Subscribers: lichtwerk Maniphest Tasks: T67454 Differential Revision: https://developer.blender.org/D5343
2019-07-25 16:36:22 +02:00
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
int apply_as = RNA_enum_get(op->ptr, "apply_as");
if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {
return OPERATOR_CANCELLED;
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
2019-04-22 09:19:45 +10:00
if (gpencil_edit_modifier_invoke_properties(C, op)) {
return gpencil_modifier_apply_exec(C, op);
2019-04-22 09:19:45 +10:00
}
else {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
}
static const EnumPropertyItem gpencil_modifier_apply_as_items[] = {
{MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
{MODIFIER_APPLY_SHAPE,
"SHAPE",
0,
"New Shape",
"Apply deform-only modifier to a new shape on this object"},
{0, NULL, 0, NULL, NULL},
};
void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot)
{
ot->name = "Apply Modifier";
ot->description = "Apply modifier and remove from the stack";
ot->idname = "OBJECT_OT_gpencil_modifier_apply";
ot->invoke = gpencil_modifier_apply_invoke;
ot->exec = gpencil_modifier_apply_exec;
ot->poll = gpencil_edit_modifier_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_enum(ot->srna,
"apply_as",
gpencil_modifier_apply_as_items,
MODIFIER_APPLY_DATA,
"Apply as",
"How to apply the modifier to the geometry");
gpencil_edit_modifier_properties(ot);
}
/************************ copy modifier operator *********************/
static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
2019-04-22 09:19:45 +10:00
if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
2019-04-22 09:19:45 +10:00
if (gpencil_edit_modifier_invoke_properties(C, op)) {
return gpencil_modifier_copy_exec(C, op);
2019-04-22 09:19:45 +10:00
}
else {
return OPERATOR_CANCELLED;
2019-04-22 09:19:45 +10:00
}
}
void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
{
ot->name = "Copy Modifier";
ot->description = "Duplicate modifier at the same position in the stack";
ot->idname = "OBJECT_OT_gpencil_modifier_copy";
ot->invoke = gpencil_modifier_copy_invoke;
ot->exec = gpencil_modifier_copy_exec;
ot->poll = gpencil_edit_modifier_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}