Outliner Drag & Drop fixes
OUTLINER_OT_parent_drop * use scene of child instead of active scene * poll to check if parent and child are in same scene OUTLINER_OT_parent_clear * get scene from child instead of only working on active scene * poll to check if no parent OUTLINER_OT_scene_drop && OBJECT_OT_make_links_scene * memory leak on error * would only link some objects on error
This commit is contained in:
@@ -85,8 +85,8 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
|
||||
extern struct EnumPropertyItem prop_make_parent_types[];
|
||||
|
||||
int ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, struct Object *par, int partype);
|
||||
void ED_object_parent_clear(struct bContext *C, int type);
|
||||
struct Base *ED_object_scene_link(struct ReportList *reports, struct Scene *scene, struct Object *ob);
|
||||
void ED_object_parent_clear(struct Object *ob, int type);
|
||||
struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob);
|
||||
|
||||
/* generic editmode keys like pet
|
||||
* do_pet
|
||||
|
||||
@@ -424,27 +424,35 @@ EnumPropertyItem prop_clear_parent_types[] = {
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
void ED_object_parent_clear(bContext *C, int type)
|
||||
void ED_object_parent_clear(Object *ob, int type)
|
||||
{
|
||||
|
||||
if (ob->parent == NULL)
|
||||
return;
|
||||
|
||||
if (type == 0) {
|
||||
ob->parent = NULL;
|
||||
}
|
||||
else if (type == 1) {
|
||||
ob->parent = NULL;
|
||||
BKE_object_apply_mat4(ob, ob->obmat, TRUE, FALSE);
|
||||
}
|
||||
else if (type == 2)
|
||||
unit_m4(ob->parentinv);
|
||||
|
||||
ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
|
||||
}
|
||||
|
||||
/* note, poll should check for editable scene */
|
||||
static int parent_clear_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
int type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
|
||||
{
|
||||
if (ob->parent == NULL)
|
||||
continue;
|
||||
|
||||
if (type == 0) {
|
||||
ob->parent = NULL;
|
||||
}
|
||||
else if (type == 1) {
|
||||
ob->parent = NULL;
|
||||
BKE_object_apply_mat4(ob, ob->obmat, TRUE, FALSE);
|
||||
}
|
||||
else if (type == 2)
|
||||
unit_m4(ob->parentinv);
|
||||
|
||||
ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
|
||||
ED_object_parent_clear(ob, type);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
@@ -452,13 +460,6 @@ void ED_object_parent_clear(bContext *C, int type)
|
||||
DAG_ids_flush_update(bmain, 0);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
|
||||
}
|
||||
|
||||
/* note, poll should check for editable scene */
|
||||
static int parent_clear_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
ED_object_parent_clear(C, RNA_enum_get(op->ptr, "type"));
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1195,22 +1196,11 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
|
||||
}
|
||||
#endif
|
||||
|
||||
Base *ED_object_scene_link(ReportList *reports, Scene *scene, Object *ob)
|
||||
Base *ED_object_scene_link(Scene *scene, Object *ob)
|
||||
{
|
||||
Base *base;
|
||||
|
||||
if (ELEM(NULL, ob, scene)) {
|
||||
BKE_report(reports, RPT_ERROR, "Couldn't find scene");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BKE_scene_base_find(scene, ob)) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is already in scene \"%s\"", ob->id.name + 2, scene->id.name + 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scene->id.lib) {
|
||||
BKE_report(reports, RPT_ERROR, "Can't link objects into a linked scene");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1225,16 +1215,24 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
|
||||
|
||||
if (scene_to == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Couldn't find scene");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (scene_to == CTX_data_scene(C)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (scene_to->id.lib) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't link objects into a linked scene");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
|
||||
{
|
||||
if (ED_object_scene_link(op->reports, scene_to, base->object) == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
ED_object_scene_link(scene_to, base->object);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
|
||||
@@ -1453,7 +1453,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
SpaceOops *soops = CTX_wm_space_outliner(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Scene *scene = NULL;
|
||||
TreeElement *te = NULL;
|
||||
TreeElement *te_found = NULL;
|
||||
char childname[MAX_ID_NAME];
|
||||
@@ -1485,10 +1485,12 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* check dragged object (child) is active */
|
||||
if (ob != CTX_data_active_object(C))
|
||||
ED_base_object_select(BKE_scene_base_find(scene, ob), BA_SELECT);
|
||||
|
||||
scene = (Scene *)outliner_search_back(soops, te_found, ID_SCE);
|
||||
|
||||
if(scene == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
|
||||
if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype)) {
|
||||
DAG_scene_sort(bmain, scene);
|
||||
@@ -1654,19 +1656,31 @@ int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te,
|
||||
|
||||
static int parent_clear_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = NULL;
|
||||
Object *ob = NULL;
|
||||
SpaceOops *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te;
|
||||
char obname[MAX_ID_NAME];
|
||||
|
||||
RNA_string_get(op->ptr, "dragged_obj", obname);
|
||||
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
|
||||
|
||||
/* check dragged object (child) is active */
|
||||
if (ob != CTX_data_active_object(C))
|
||||
ED_base_object_select(BKE_scene_base_find(scene, ob), BA_SELECT);
|
||||
/* search forwards to find the object */
|
||||
te = outliner_find_id(soops, &soops->tree, (ID *)ob);
|
||||
/* then search backwards to get the scene */
|
||||
scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
|
||||
|
||||
ED_object_parent_clear(C, RNA_enum_get(op->ptr, "type"));
|
||||
if(scene == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type"));
|
||||
|
||||
DAG_scene_sort(bmain, scene);
|
||||
DAG_ids_flush_update(bmain, 0);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1735,8 +1749,12 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
|
||||
RNA_string_get(op->ptr, "object", obname);
|
||||
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
|
||||
|
||||
base = ED_object_scene_link(op->reports, scene, ob);
|
||||
|
||||
if (ELEM(NULL, ob, scene) || scene->id.lib != NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
base = ED_object_scene_link(scene, ob);
|
||||
|
||||
if (base == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_screen.h"
|
||||
@@ -52,6 +53,9 @@
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
@@ -91,7 +95,13 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
|
||||
for (te = soops->tree.first; te; te = te->next) {
|
||||
TreeElement *te_valid;
|
||||
te_valid = outliner_dropzone_parent(C, event, te, fmval);
|
||||
if (te_valid) return 1;
|
||||
if (te_valid) {
|
||||
/* check that parent/child are both in the same scene */
|
||||
Scene *scene = (Scene *)outliner_search_back(soops, te_valid, ID_SCE);
|
||||
if (BKE_scene_base_find(scene, (Object *)id)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +127,9 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, wmEvent *event)
|
||||
if (drag->type == WM_DRAG_ID) {
|
||||
ID *id = (ID *)drag->poin;
|
||||
if (GS(id->name) == ID_OB) {
|
||||
//TODO: Check if no parent?
|
||||
if (((Object *)id)->parent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
/* Ensure location under cursor is valid dropzone */
|
||||
for (te = soops->tree.first; te; te = te->next) {
|
||||
if (outliner_dropzone_parent_clear(C, event, te, fmval)) return 1;
|
||||
|
||||
Reference in New Issue
Block a user