Example #1
0
static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
                                   TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Group *group = (Group *)tselem->id;
	GroupObject *gob;
	Base *base;
	
	for (gob = group->gobject.first; gob; gob = gob->next) {
		base = BKE_scene_base_find(scene, gob->ob);
		if (base) {
			base->object->flag |= SELECT;
			base->flag |= SELECT;
		}
		else {
			/* link to scene */
			base = MEM_callocN(sizeof(Base), "add_base");
			BLI_addhead(&scene->base, base);
			base->lay = gob->ob->lay;
			gob->ob->flag |= SELECT;
			base->flag = gob->ob->flag;
			base->object = gob->ob;
			id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
		}
	}
}
Example #2
0
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
	switch (GS(r_id_remap_data->id->name)) {
		case ID_SCE:
		{
			Scene *sce = (Scene *)r_id_remap_data->id;

			if (!r_id_remap_data->new_id) {
				const bool is_indirect = (sce->id.lib != NULL);
				const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;

				/* In case we are unlinking... */
				if (!r_id_remap_data->old_id) {
					/* ... everything from scene. */
					Base *base, *base_next;
					for (base = sce->base.first; base; base = base_next) {
						base_next = base->next;
						libblock_remap_data_preprocess_scene_base_unlink(
						            r_id_remap_data, sce, base, skip_indirect, is_indirect);
					}
				}
				else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
					/* ... a specific object from scene. */
					Object *old_ob = (Object *)r_id_remap_data->old_id;
					Base *base = BKE_scene_base_find(sce, old_ob);

					if (base) {
						libblock_remap_data_preprocess_scene_base_unlink(
						            r_id_remap_data, sce, base, skip_indirect, is_indirect);
					}
				}
			}
			break;
		}
		case ID_OB:
		{
			ID *old_id = r_id_remap_data->old_id;
			if (!old_id || GS(old_id->name) == ID_AR) {
				Object *ob = (Object *)r_id_remap_data->id;
				/* Object's pose holds reference to armature bones... sic */
				/* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
				 * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
				 * another complex and risky condition nightmare like the one we have in
				 * foreach_libblock_remap_callback()... */
				if (ob->pose && (!old_id || ob->data == old_id)) {
					BLI_assert(ob->type == OB_ARMATURE);
					ob->pose->flag |= POSE_RECALC;
					/* We need to clear pose bone pointers immediately, things like undo writefile may be called
					 * before pose is actually recomputed, can lead to segfault... */
					BKE_pose_clear_pointers(ob->pose);
				}
			}
			break;
		}
		default:
			break;
	}
}
Example #3
0
void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	
	if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
	if (base) {
		base->object->restrictflag ^= OB_RESTRICT_RENDER;
	}
}
Example #4
0
static int  tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops,
                                           TreeElement *te, int set, bool recursive)
{
	TreeStoreElem *tselem = TREESTORE(te);
	Scene *sce;
	Base *base;
	Object *ob = NULL;
	
	/* if id is not object, we search back */
	if (te->idcode == ID_OB) {
		ob = (Object *)tselem->id;
	}
	else {
		ob = (Object *)outliner_search_back(soops, te, ID_OB);
		if (ob == OBACT) return 0;
	}
	if (ob == NULL) return 0;
	
	sce = (Scene *)outliner_search_back(soops, te, ID_SCE);
	if (sce && scene != sce) {
		ED_screen_set_scene(C, CTX_wm_screen(C), sce);
		scene = sce;
	}
	
	/* find associated base in current scene */
	base = BKE_scene_base_find(scene, ob);

	if (base) {
		if (set == 2) {
			/* swap select */
			if (base->flag & SELECT)
				ED_base_object_select(base, BA_DESELECT);
			else 
				ED_base_object_select(base, BA_SELECT);
		}
		else {
			/* deleselect all */
			BKE_scene_base_deselect_all(scene);
			ED_base_object_select(base, BA_SELECT);
		}

		if (recursive) {
			/* Recursive select/deselect for Object hierarchies */
			do_outliner_object_select_recursive(scene, ob, (ob->flag & SELECT) != 0);
		}

		if (C) {
			ED_base_object_activate(C, base); /* adds notifier */
			WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
		}
	}
	
	if (ob != scene->obedit)
		ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
		
	return 1;
}
Example #5
0
static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
                               TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	
	if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
	if (base) {
		base->flag &= ~SELECT;
		base->object->flag &= ~SELECT;
	}
}
Example #6
0
static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
                             TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	
	if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
	if (base && ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0)) {
		base->flag |= SELECT;
		base->object->flag |= SELECT;
	}
}
Example #7
0
void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	Object *ob = (Object *)tselem->id;
	
	/* add check for edit mode */
	if (!common_restrict_check(C, ob)) return;
	
	if (base || (base = BKE_scene_base_find(scene, ob))) {
		if ((base->object->restrictflag ^= OB_RESTRICT_VIEW)) {
			ED_base_object_select(base, BA_DESELECT);
		}
	}
}
Example #8
0
static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
                             TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	
	if (base == NULL)
		base = BKE_scene_base_find(scene, (Object *)tselem->id);
	if (base) {
		// check also library later
		if (scene->obedit == base->object)
			ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
		
		ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
		te->directdata = NULL;
		tselem->id = NULL;
	}
}
Example #9
0
static int parent_clear_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
	Scene *scene = CTX_data_scene(C);
	Object *ob = NULL;
	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);

	ED_object_parent_clear(C, RNA_enum_get(op->ptr, "type"));

	return OPERATOR_FINISHED;
}
Example #10
0
static int tree_element_active_pose(bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
{
	Object *ob = (Object *)tselem->id;
	Base *base = BKE_scene_base_find(scene, ob);
	
	if (set) {
		if (scene->obedit)
			ED_object_exit_editmode(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
		
		if (ob->mode & OB_MODE_POSE)
			ED_armature_exit_posemode(C, base);
		else 
			ED_armature_enter_posemode(C, base);
	}
	else {
		if (ob->mode & OB_MODE_POSE) return 1;
	}
	return 0;
}
Example #11
0
static void object_delete_hierarchy_cb(
        bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
	Base *base = (Base *)te->directdata;
	Object *obedit = scene->obedit;

	if (!base) {
		base = BKE_scene_base_find(scene, (Object *)tselem->id);
	}
	if (base) {
		/* Check also library later. */
		for (; obedit && (obedit != base->object); obedit = obedit->parent);
		if (obedit == base->object) {
			ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
		}

		outline_delete_hierarchy(C, scene, base);
		te->directdata = NULL;
		tselem->id = NULL;
	}

	WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera)
{
	ListBase *markers = ED_context_get_markers(C);
	ARegion *ar = CTX_wm_region(C);
	View2D *v2d = UI_view2d_fromcontext(C);
	float viewx;
	int x, y, cfra;
	
	if (markers == NULL)
		return OPERATOR_PASS_THROUGH;

	x = event->x - ar->winrct.xmin;
	y = event->y - ar->winrct.ymin;
	
	UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
	
	cfra = ED_markers_find_nearest_marker_time(markers, viewx);
	
	if (extend)
		select_timeline_marker_frame(markers, cfra, 1);
	else
		select_timeline_marker_frame(markers, cfra, 0);
	
#ifdef DURIAN_CAMERA_SWITCH

	if (camera) {
		Scene *scene = CTX_data_scene(C);
		Base *base;
		TimeMarker *marker;
		int sel = 0;
		
		if (!extend)
			BKE_scene_base_deselect_all(scene);
		
		for (marker = markers->first; marker; marker = marker->next) {
			if (marker->frame == cfra) {
				sel = (marker->flag & SELECT);
				break;
			}
		}
		
		for (marker = markers->first; marker; marker = marker->next) {
			if (marker->camera) {
				if (marker->frame == cfra) {
					base = BKE_scene_base_find(scene, marker->camera);
					if (base) {
						ED_base_object_select(base, sel);
						if (sel)
							ED_base_object_activate(C, base);
					}
				}
			}
		}
		
		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
	}
#else
	(void)camera;
#endif

	WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
	WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);

	/* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
	return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
Example #13
0
void DocumentImporter::finish()
{
	if (mImportStage != General)
		return;

	Main *bmain = CTX_data_main(mContext);
	// TODO: create a new scene except the selected <visual_scene> - use current blender scene for it
	Scene *sce = CTX_data_scene(mContext);
	unit_converter.calculate_scale(*sce);

	std::vector<Object *> *objects_to_scale = new std::vector<Object *>();

	/** TODO Break up and put into 2-pass parsing of DAE */
	std::vector<const COLLADAFW::VisualScene *>::iterator it;
	for (it = vscenes.begin(); it != vscenes.end(); it++) {
		PointerRNA sceneptr, unit_settings;
		PropertyRNA *system, *scale;
		
		// for scene unit settings: system, scale_length

		RNA_id_pointer_create(&sce->id, &sceneptr);
		unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
		system = RNA_struct_find_property(&unit_settings, "system");
		scale = RNA_struct_find_property(&unit_settings, "scale_length");

		if (this->import_settings->import_units) {
			
			switch (unit_converter.isMetricSystem()) {
				case UnitConverter::Metric:
					RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
					break;
				case UnitConverter::Imperial:
					RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL);
					break;
				default:
					RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE);
					break;
			}
			float unit_factor = unit_converter.getLinearMeter();
			RNA_property_float_set(&unit_settings, scale, unit_factor);
			fprintf(stdout, "Collada: Adjusting Blender units to Importset units: %f.\n", unit_factor);

		}

		// Write nodes to scene
		const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
		for (unsigned int i = 0; i < roots.getCount(); i++) {
			std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
			objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
			delete objects_done;
		}

		// update scene
		DAG_relations_tag_update(bmain);
		WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL);

	}


	mesh_importer.optimize_material_assignements();

	armature_importer.set_tags_map(this->uid_tags_map);
	armature_importer.make_armatures(mContext);
	armature_importer.make_shape_keys();
	DAG_relations_tag_update(bmain);

#if 0
	armature_importer.fix_animation();
#endif

	for (std::vector<const COLLADAFW::VisualScene *>::iterator it = vscenes.begin(); it != vscenes.end(); it++) {
		const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();

		for (unsigned int i = 0; i < roots.getCount(); i++) {
			translate_anim_recursive(roots[i], NULL, NULL);
		}
	}

	if (libnode_ob.size()) {
		Scene *sce = CTX_data_scene(mContext);

		fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
		// free all library_nodes
		std::vector<Object *>::iterator it;
		for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
			Object *ob = *it;

			Base *base = BKE_scene_base_find(sce, ob);
			if (base) {
				BLI_remlink(&sce->base, base);
				BKE_libblock_free_us(G.main, base->object);
				if (sce->basact == base)
					sce->basact = NULL;
				MEM_freeN(base);
			}
		}
		libnode_ob.clear();

		DAG_relations_tag_update(bmain);
	}
	
	bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);

	delete objects_to_scale;
}
Example #14
0
static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
                                     TreeElement *te, int extend, const float mval[2])
{
	
	if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
		TreeStoreElem *tselem = TREESTORE(te);
		int openclose = 0;
		
		/* open close icon */
		if ((te->flag & TE_ICONROW) == 0) {               // hidden icon, no open/close
			if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X)
				openclose = 1;
		}
		
		if (openclose) {
			/* all below close/open? */
			if (extend) {
				tselem->flag &= ~TSE_CLOSED;
				outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
			}
			else {
				if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
				else tselem->flag |= TSE_CLOSED;
				
			}
			
			return 1;
		}
		/* name and first icon */
		else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
			
			/* always makes active object */
			if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
				tree_element_set_active_object(C, scene, soops, te, 1 + (extend != 0 && tselem->type == 0));
			
			if (tselem->type == 0) { // the lib blocks
				/* editmode? */
				if (te->idcode == ID_SCE) {
					if (scene != (Scene *)tselem->id) {
						ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
					}
				}
				else if (te->idcode == ID_GR) {
					Group *gr = (Group *)tselem->id;
					GroupObject *gob;
					
					if (extend) {
						int sel = BA_SELECT;
						for (gob = gr->gobject.first; gob; gob = gob->next) {
							if (gob->ob->flag & SELECT) {
								sel = BA_DESELECT;
								break;
							}
						}
						
						for (gob = gr->gobject.first; gob; gob = gob->next) {
							ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel);
						}
					}
					else {
						BKE_scene_base_deselect_all(scene);
						
						for (gob = gr->gobject.first; gob; gob = gob->next) {
							if ((gob->ob->flag & SELECT) == 0)
								ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT);
						}
					}
					
					WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
				}
				else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
					WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
				}
				else {  // rest of types
					tree_element_active(C, scene, soops, te, 1);
				}
				
			}
			else tree_element_type_active(C, scene, soops, te, tselem, 1 + (extend != 0));
			
			return 1;
		}
	}
	
	for (te = te->subtree.first; te; te = te->next) {
		if (do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
	}
	return 0;
}
Example #15
0
static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
	Object *par = NULL;
	Object *ob = NULL;
	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);
	TreeElement *te = NULL;
	TreeElement *te_found = NULL;
	char childname[MAX_ID_NAME];
	char parname[MAX_ID_NAME];
	int partype = 0;
	float fmval[2];

	UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);

	/* Find object hovered over */
	for (te = soops->tree.first; te; te = te->next) {
		te_found = outliner_dropzone_parent(C, event, te, fmval);
		if (te_found) break;
	}

	if (te_found) {
		RNA_string_set(op->ptr, "parent", te_found->name);
		/* Identify parent and child */
		RNA_string_get(op->ptr, "child", childname);
		ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
		RNA_string_get(op->ptr, "parent", parname);
		par = (Object *)BKE_libblock_find_name(ID_OB, parname);
		
		if (ELEM(NULL, ob, par)) {
			if (par == NULL) printf("par==NULL\n");
			return OPERATOR_CANCELLED;
		}
		if (ob == par) {
			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);
		
		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);
				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);
			}
		}
		else {
			/* Menu creation */
			uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
			uiLayout *layout = uiPupMenuLayout(pup);
			
			PointerRNA ptr;
			
			WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
			RNA_string_set(&ptr, "parent", parname);
			RNA_string_set(&ptr, "child", childname);
			RNA_enum_set(&ptr, "type", PAR_OBJECT);
			/* Cannot use uiItemEnumO()... have multiple properties to set. */
			uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Object"),
			            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
			
			/* par becomes parent, make the associated menus */
			if (par->type == OB_ARMATURE) {
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_ARMATURE);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Armature Deform"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("   With Empty Groups"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("   With Envelope Weights"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("   With Automatic Weights"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_BONE);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Bone"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
			}
			else if (par->type == OB_CURVE) {
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_CURVE);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Curve Deform"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_FOLLOW);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Follow Path"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
				
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Path Constraint"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
			}
			else if (par->type == OB_LATTICE) {
				WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop");
				RNA_string_set(&ptr, "parent", parname);
				RNA_string_set(&ptr, "child", childname);
				RNA_enum_set(&ptr, "type", PAR_LATTICE);
				uiItemFullO(layout, "OUTLINER_OT_parent_drop", IFACE_("Lattice Deform"),
				            0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
			}
			
			uiPupMenuEnd(C, pup);
			
			return OPERATOR_CANCELLED;
		}
	}
	else {
		return OPERATOR_CANCELLED;
	}

	return OPERATOR_FINISHED;
}