Python API: add a method for reordering modifiers.
Add an `object.modifiers.move()` method, similar to the one for constraints and some other collections. Currently reordering modifiers requires using operators, which depend on context. The implementation is straightforward, except for the need to make the severity of errors reported by the underlying editor code into a parameter, so that the new Python API function reports any problems as Python exceptions, and refactoring the code to allow aborting a blocked move before making any changes. I also turn the negative index condition from an assert into an error. Differential Revision: https://developer.blender.org/D16966
This commit is contained in:
parent
4a768a7857
commit
f7dd7d5454
|
@ -10,6 +10,7 @@
|
|||
#include "BLI_compiler_attrs.h"
|
||||
#include "DNA_object_enums.h"
|
||||
#include "DNA_userdef_enums.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -558,15 +559,19 @@ bool ED_object_modifier_remove(struct ReportList *reports,
|
|||
struct ModifierData *md);
|
||||
void ED_object_modifier_clear(struct Main *bmain, struct Scene *scene, struct Object *ob);
|
||||
bool ED_object_modifier_move_down(struct ReportList *reports,
|
||||
eReportType error_type,
|
||||
struct Object *ob,
|
||||
struct ModifierData *md);
|
||||
bool ED_object_modifier_move_up(struct ReportList *reports,
|
||||
eReportType error_type,
|
||||
struct Object *ob,
|
||||
struct ModifierData *md);
|
||||
bool ED_object_modifier_move_to_index(struct ReportList *reports,
|
||||
eReportType error_type,
|
||||
struct Object *ob,
|
||||
struct ModifierData *md,
|
||||
int index);
|
||||
int index,
|
||||
bool allow_partial);
|
||||
|
||||
bool ED_object_modifier_convert_psys_to_mesh(struct ReportList *reports,
|
||||
struct Main *bmain,
|
||||
|
|
|
@ -415,83 +415,139 @@ void ED_object_modifier_clear(Main *bmain, Scene *scene, Object *ob)
|
|||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
bool ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
|
||||
static bool object_modifier_check_move_before(ReportList *reports,
|
||||
eReportType error_type,
|
||||
ModifierData *md,
|
||||
ModifierData *md_prev)
|
||||
{
|
||||
if (md->prev) {
|
||||
if (md_prev) {
|
||||
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
||||
|
||||
if (mti->type != eModifierTypeType_OnlyDeform) {
|
||||
const ModifierTypeInfo *nmti = BKE_modifier_get_info((ModifierType)md->prev->type);
|
||||
const ModifierTypeInfo *nmti = BKE_modifier_get_info((ModifierType)md_prev->type);
|
||||
|
||||
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
|
||||
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
|
||||
BKE_report(reports, error_type, "Cannot move above a modifier requiring original data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_listbase_swaplinks(&ob->modifiers, md, md->prev);
|
||||
}
|
||||
else {
|
||||
BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the start of the list");
|
||||
BKE_report(reports, error_type, "Cannot move modifier beyond the start of the list");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
|
||||
bool ED_object_modifier_move_up(ReportList *reports,
|
||||
eReportType error_type,
|
||||
Object *ob,
|
||||
ModifierData *md)
|
||||
{
|
||||
if (md->next) {
|
||||
if (object_modifier_check_move_before(reports, error_type, md, md->prev)) {
|
||||
BLI_listbase_swaplinks(&ob->modifiers, md, md->prev);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool object_modifier_check_move_after(ReportList *reports,
|
||||
eReportType error_type,
|
||||
ModifierData *md,
|
||||
ModifierData *md_next)
|
||||
{
|
||||
if (md_next) {
|
||||
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
||||
|
||||
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
|
||||
const ModifierTypeInfo *nmti = BKE_modifier_get_info((ModifierType)md->next->type);
|
||||
const ModifierTypeInfo *nmti = BKE_modifier_get_info((ModifierType)md_next->type);
|
||||
|
||||
if (nmti->type != eModifierTypeType_OnlyDeform) {
|
||||
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
|
||||
BKE_report(reports, error_type, "Cannot move beyond a non-deforming modifier");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_listbase_swaplinks(&ob->modifiers, md, md->next);
|
||||
}
|
||||
else {
|
||||
BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the list");
|
||||
BKE_report(reports, error_type, "Cannot move modifier beyond the end of the list");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ED_object_modifier_move_down(ReportList *reports,
|
||||
eReportType error_type,
|
||||
Object *ob,
|
||||
ModifierData *md)
|
||||
{
|
||||
if (object_modifier_check_move_after(reports, error_type, md, md->next)) {
|
||||
BLI_listbase_swaplinks(&ob->modifiers, md, md->next);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ED_object_modifier_move_to_index(ReportList *reports,
|
||||
eReportType error_type,
|
||||
Object *ob,
|
||||
ModifierData *md,
|
||||
const int index)
|
||||
const int index,
|
||||
bool allow_partial)
|
||||
{
|
||||
BLI_assert(md != nullptr);
|
||||
BLI_assert(index >= 0);
|
||||
if (index >= BLI_listbase_count(&ob->modifiers)) {
|
||||
BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the stack");
|
||||
|
||||
if (index < 0 || index >= BLI_listbase_count(&ob->modifiers)) {
|
||||
BKE_report(reports, error_type, "Cannot move modifier beyond the end of the stack");
|
||||
return false;
|
||||
}
|
||||
|
||||
int md_index = BLI_findindex(&ob->modifiers, md);
|
||||
BLI_assert(md_index != -1);
|
||||
|
||||
if (md_index < index) {
|
||||
/* Move modifier down in list. */
|
||||
for (; md_index < index; md_index++) {
|
||||
if (!ED_object_modifier_move_down(reports, ob, md)) {
|
||||
ModifierData *md_target = md;
|
||||
|
||||
for (; md_index < index; md_index++, md_target = md_target->next) {
|
||||
if (!object_modifier_check_move_after(reports, error_type, md, md_target->next)) {
|
||||
if (!allow_partial || md == md_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(md != md_target && md_target);
|
||||
|
||||
BLI_remlink(&ob->modifiers, md);
|
||||
BLI_insertlinkafter(&ob->modifiers, md_target, md);
|
||||
}
|
||||
else if (md_index > index) {
|
||||
/* Move modifier up in list. */
|
||||
ModifierData *md_target = md;
|
||||
|
||||
for (; md_index > index; md_index--, md_target = md_target->prev) {
|
||||
if (!object_modifier_check_move_before(reports, error_type, md, md_target->prev)) {
|
||||
if (!allow_partial || md == md_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(md != md_target && md_target);
|
||||
|
||||
BLI_remlink(&ob->modifiers, md);
|
||||
BLI_insertlinkbefore(&ob->modifiers, md_target, md);
|
||||
}
|
||||
else {
|
||||
/* Move modifier up in list. */
|
||||
for (; md_index > index; md_index--) {
|
||||
if (!ED_object_modifier_move_up(reports, ob, md)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* NOTE: Dependency graph only uses modifier nodes for visibility updates, and exact order of
|
||||
|
@ -1518,7 +1574,7 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op)
|
|||
Object *ob = ED_object_active_context(C);
|
||||
ModifierData *md = edit_modifier_property_get(op, ob, 0);
|
||||
|
||||
if (!md || !ED_object_modifier_move_up(op->reports, ob, md)) {
|
||||
if (!md || !ED_object_modifier_move_up(op->reports, RPT_WARNING, ob, md)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -1563,7 +1619,7 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op)
|
|||
Object *ob = ED_object_active_context(C);
|
||||
ModifierData *md = edit_modifier_property_get(op, ob, 0);
|
||||
|
||||
if (!md || !ED_object_modifier_move_down(op->reports, ob, md)) {
|
||||
if (!md || !ED_object_modifier_move_down(op->reports, RPT_WARNING, ob, md)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -1609,7 +1665,7 @@ static int modifier_move_to_index_exec(bContext *C, wmOperator *op)
|
|||
ModifierData *md = edit_modifier_property_get(op, ob, 0);
|
||||
int index = RNA_int_get(op->ptr, "index");
|
||||
|
||||
if (!(md && ED_object_modifier_move_to_index(op->reports, ob, md, index))) {
|
||||
if (!(md && ED_object_modifier_move_to_index(op->reports, RPT_WARNING, ob, md, index, true))) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -1027,8 +1027,12 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
|
|||
}
|
||||
else {
|
||||
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
|
||||
ED_object_modifier_move_to_index(
|
||||
reports, ob, static_cast<ModifierData *>(drop_data->drag_directdata), index);
|
||||
ED_object_modifier_move_to_index(reports,
|
||||
RPT_WARNING,
|
||||
ob,
|
||||
static_cast<ModifierData *>(drop_data->drag_directdata),
|
||||
index,
|
||||
true);
|
||||
}
|
||||
break;
|
||||
case TSE_CONSTRAINT:
|
||||
|
|
|
@ -1759,6 +1759,19 @@ static void rna_Object_modifier_clear(Object *object, bContext *C)
|
|||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
|
||||
}
|
||||
|
||||
static void rna_Object_modifier_move(
|
||||
Object *object, Main *bmain, ReportList *reports, int from, int to)
|
||||
{
|
||||
ModifierData *md = BLI_findlink(&object->modifiers, from);
|
||||
|
||||
if (!md) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Invalid original modifier index '%d'", from);
|
||||
return;
|
||||
}
|
||||
|
||||
ED_object_modifier_move_to_index(reports, RPT_ERROR, object, md, to, false);
|
||||
}
|
||||
|
||||
static PointerRNA rna_Object_active_modifier_get(PointerRNA *ptr)
|
||||
{
|
||||
Object *ob = (Object *)ptr->owner_id;
|
||||
|
@ -2635,6 +2648,16 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
|
|||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
RNA_def_function_ui_description(func, "Remove all modifiers from the object");
|
||||
|
||||
/* move a modifier */
|
||||
func = RNA_def_function(srna, "move", "rna_Object_modifier_move");
|
||||
RNA_def_function_ui_description(func, "Move a modifier to a different position");
|
||||
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_int(
|
||||
func, "from_index", -1, INT_MIN, INT_MAX, "From Index", "Index to move", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
|
||||
/* Active modifier. */
|
||||
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Modifier");
|
||||
|
|
Loading…
Reference in New Issue