Пример #1
0
static void file_panel_cb(bContext *C, void *arg_entry, void *UNUSED(arg_v))
{
	PointerRNA ptr;
	char *entry= (char*)arg_entry;

	WM_operator_properties_create(&ptr, "FILE_OT_select_bookmark");
	RNA_string_set(&ptr, "dir", entry);
	WM_operator_name_call(C, "FILE_OT_select_bookmark", WM_OP_INVOKE_REGION_WIN, &ptr);
	WM_operator_properties_free(&ptr);
}
Пример #2
0
static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
	PointerRNA ptr;
	PropertyRNA *prop;
	FileBrowseOp *fbo;
	char *str;

	uiFileBrowseContextProperty(C, &ptr, &prop);

	if(!prop)
		return OPERATOR_CANCELLED;

	str= RNA_property_string_get_alloc(&ptr, prop, NULL, 0);

	/* useful yet irritating feature, Shift+Click to open the file
	 * Alt+Click to browse a folder in the OS's browser */
	if(event->shift || event->alt) {
		PointerRNA props_ptr;

		if(event->alt) {
			char *lslash= BLI_last_slash(str);
			if(lslash)
				*lslash= '\0';
		}


		WM_operator_properties_create(&props_ptr, "WM_OT_path_open");
		RNA_string_set(&props_ptr, "filepath", str);
		WM_operator_name_call(C, "WM_OT_path_open", WM_OP_EXEC_DEFAULT, &props_ptr);
		WM_operator_properties_free(&props_ptr);

		MEM_freeN(str);
		return OPERATOR_CANCELLED;
	}
	else {
		const char *path_prop= RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
		fbo= MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
		fbo->ptr= ptr;
		fbo->prop= prop;
		op->customdata= fbo;

		RNA_string_set(op->ptr, path_prop, str);
		MEM_freeN(str);

		if(RNA_struct_find_property(op->ptr, "relative_path")) {
			if(!RNA_property_is_set(op->ptr, "relative_path")) {
				/* annoying exception!, if were dealign with the user prefs, default relative to be off */
				RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS && (ptr.data != &U));
			}
		}
		WM_event_add_fileselect(C, op);

		return OPERATOR_RUNNING_MODAL;
	}
}
Пример #3
0
static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
{
	wmKeyMapItem *kmin = MEM_dupallocN(kmi);

	kmin->prev= kmin->next= NULL;
	kmin->flag &= ~KMI_UPDATE;

	if(kmin->properties) {
		kmin->ptr= MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
		WM_operator_properties_create(kmin->ptr, kmin->idname);

		kmin->properties= IDP_CopyProperty(kmin->properties);
		kmin->ptr->data= kmin->properties;
	}

	return kmin;
}
Пример #4
0
static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
{
	wmWindow *win = CTX_wm_window(C);
	ToolSettings *ts = CTX_data_tool_settings(C);
	ScrArea *sa = CTX_wm_area(C);
	View3D *v3d = sa->spacedata.first;
	Object *obedit = CTX_data_edit_object(C);
	BMEditMesh *em = NULL;
	int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
	PointerRNA props_ptr;
	
	if (obedit && obedit->type == OB_MESH) {
		em = BMEdit_FromObject(obedit);
	}
	/* watch it: if sa->win does not exist, check that when calling direct drawing routines */

	switch (event) {
		case B_REDR:
			ED_area_tag_redraw(sa);
			break;

		case B_MODESELECT:
			WM_operator_properties_create(&props_ptr, "OBJECT_OT_mode_set");
			RNA_enum_set(&props_ptr, "mode", v3d->modeselect);
			WM_operator_name_call(C, "OBJECT_OT_mode_set", WM_OP_EXEC_REGION_WIN, &props_ptr);
			WM_operator_properties_free(&props_ptr);
			break;

		case B_SEL_VERT:
			if (em) {
				if (shift == 0 || em->selectmode == 0)
					em->selectmode = SCE_SELECT_VERTEX;
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Vertex");
			}
			break;
		case B_SEL_EDGE:
			if (em) {
				if (shift == 0 || em->selectmode == 0) {
					if ( (em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX) {
						if (ctrl) EDBM_selectmode_convert(em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
					}
					em->selectmode = SCE_SELECT_EDGE;
				}
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Edge");
			}
			break;
		case B_SEL_FACE:
			if (em) {
				if (shift == 0 || em->selectmode == 0) {
					if ( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)) {
						if (ctrl) EDBM_selectmode_convert(em, (ts->selectmode ^ SCE_SELECT_FACE), SCE_SELECT_FACE);
					}
					em->selectmode = SCE_SELECT_FACE;
				}
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Face");
			}
			break;

		case B_MAN_TRANS:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_TRANSLATE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_ROT:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_ROTATE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_SCALE:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_SCALE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_NDOF:
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_MODE:
			ED_area_tag_redraw(sa);
			break;
		default:
			break;
	}
}
Пример #5
0
static int edittranslation_exec(bContext *C, wmOperator *op)
{
	uiBut *but = uiContextActiveButton(C);
	int ret = OPERATOR_CANCELLED;

	if (but) {
		PointerRNA ptr;
		char popath[FILE_MAX];
		const char *root = U.i18ndir;
		const char *uilng = BLF_lang_get();

		uiStringInfo but_label = {BUT_GET_LABEL, NULL};
		uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
		uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
		uiStringInfo but_tip = {BUT_GET_TIP, NULL};
		uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL};
		uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
		uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
		uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
		uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL};
		uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL};

		if (!BLI_is_dir(root)) {
			BKE_report(op->reports, RPT_ERROR, "Please set your User Preferences' 'Translation Branches "
			                                   "Directory' path to a valid directory");
			return OPERATOR_CANCELLED;
		}
		if (!WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0)) {
			BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
			                                    "in the User Preferences", EDTSRC_I18N_OP_NAME);
			return OPERATOR_CANCELLED;
		}
		/* Try to find a valid po file for current language... */
		edittranslation_find_po_file(root, uilng, popath, FILE_MAX);
/*		printf("po path: %s\n", popath);*/
		if (popath[0] == '\0') {
			BKE_reportf(op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root);
			return OPERATOR_CANCELLED;
		}

		uiButGetStrInfo(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
		                &rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);

		WM_operator_properties_create(&ptr, EDTSRC_I18N_OP_NAME);
		RNA_string_set(&ptr, "lang", uilng);
		RNA_string_set(&ptr, "po_file", popath);
		RNA_string_set(&ptr, "but_label", but_label.strinfo);
		RNA_string_set(&ptr, "rna_label", rna_label.strinfo);
		RNA_string_set(&ptr, "enum_label", enum_label.strinfo);
		RNA_string_set(&ptr, "but_tip", but_tip.strinfo);
		RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo);
		RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo);
		RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo);
		RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
		RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
		RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
		ret = WM_operator_name_call(C, EDTSRC_I18N_OP_NAME, WM_OP_INVOKE_DEFAULT, &ptr);

		/* Clean up */
		if (but_label.strinfo)
			MEM_freeN(but_label.strinfo);
		if (rna_label.strinfo)
			MEM_freeN(rna_label.strinfo);
		if (enum_label.strinfo)
			MEM_freeN(enum_label.strinfo);
		if (but_tip.strinfo)
			MEM_freeN(but_tip.strinfo);
		if (rna_tip.strinfo)
			MEM_freeN(rna_tip.strinfo);
		if (enum_tip.strinfo)
			MEM_freeN(enum_tip.strinfo);
		if (rna_struct.strinfo)
			MEM_freeN(rna_struct.strinfo);
		if (rna_prop.strinfo)
			MEM_freeN(rna_prop.strinfo);
		if (rna_enum.strinfo)
			MEM_freeN(rna_enum.strinfo);
		if (rna_ctxt.strinfo)
			MEM_freeN(rna_ctxt.strinfo);

		return ret;
	}
	else {
		BKE_report(op->reports, RPT_ERROR, "Active button not found");
		return OPERATOR_CANCELLED;
	}
}
Пример #6
0
/* called by ghost, here we handle events for windows themselves or send to event system */
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
{
	bContext *C = C_void_ptr;
	wmWindowManager *wm = CTX_wm_manager(C);
	GHOST_TEventType type = GHOST_GetEventType(evt);
	int time = GHOST_GetEventTime(evt);
	
	if (type == GHOST_kEventQuit) {
		WM_exit(C);
	}
	else {
		GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
		GHOST_TEventDataPtr data = GHOST_GetEventData(evt);
		wmWindow *win;
		
		if (!ghostwin) {
			/* XXX - should be checked, why are we getting an event here, and */
			/* what is it? */
			puts("<!> event has no window");
			return 1;
		}
		else if (!GHOST_ValidWindow(g_system, ghostwin)) {
			/* XXX - should be checked, why are we getting an event here, and */
			/* what is it? */
			puts("<!> event has invalid window");			
			return 1;
		}
		else {
			win = GHOST_GetWindowUserData(ghostwin);
		}
		
		switch (type) {
			case GHOST_kEventWindowDeactivate:
				wm_event_add_ghostevent(wm, win, type, time, data);
				win->active = 0; /* XXX */
				break;
			case GHOST_kEventWindowActivate: 
			{
				GHOST_TEventKeyData kdata;
				wmEvent event;
				int cx, cy, wx, wy;
				
				wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
				
				win->active = 1;
//				window_handle(win, INPUTCHANGE, win->active);
				
				/* bad ghost support for modifier keys... so on activate we set the modifiers again */
				kdata.ascii = '\0';
				kdata.utf8_buf[0] = '\0';
				if (win->eventstate->shift && !query_qual(SHIFT)) {
					kdata.key = GHOST_kKeyLeftShift;
					wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
				}
				if (win->eventstate->ctrl && !query_qual(CONTROL)) {
					kdata.key = GHOST_kKeyLeftControl;
					wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
				}
				if (win->eventstate->alt && !query_qual(ALT)) {
					kdata.key = GHOST_kKeyLeftAlt;
					wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
				}
				if (win->eventstate->oskey && !query_qual(OS)) {
					kdata.key = GHOST_kKeyOS;
					wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
				}
				/* keymodifier zero, it hangs on hotkeys that open windows otherwise */
				win->eventstate->keymodifier = 0;
				
				/* entering window, update mouse pos. but no event */
				GHOST_GetCursorPosition(g_system, &wx, &wy);
				
				GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
				win->eventstate->x = cx;
				win->eventstate->y = (win->sizey - 1) - cy;
				
				win->addmousemove = 1;   /* enables highlighted buttons */
				
				wm_window_make_drawable(C, win);

				/* window might be focused by mouse click in configuration of window manager
				 * when focus is not following mouse
				 * click could have been done on a button and depending on window manager settings
				 * click would be passed to blender or not, but in any case button under cursor
				 * should be activated, so at max next click on button without moving mouse
				 * would trigger it's handle function
				 * currently it seems to be common practice to generate new event for, but probably
				 * we'll need utility function for this? (sergey)
				 */
				event = *(win->eventstate);
				event.type = MOUSEMOVE;
				event.prevx = event.x;
				event.prevy = event.y;

				wm_event_add(win, &event);

				break;
			}
			case GHOST_kEventWindowClose: {
				wm_window_close(C, wm, win);
				break;
			}
			case GHOST_kEventWindowUpdate: {
				if (G.debug & G_DEBUG_EVENTS) {
					printf("%s: ghost redraw %d\n", __func__, win->winid);
				}
				
				wm_window_make_drawable(C, win);
				WM_event_add_notifier(C, NC_WINDOW, NULL);

				break;
			}
			case GHOST_kEventWindowSize:
			case GHOST_kEventWindowMove: {
				GHOST_TWindowState state;
				state = GHOST_GetWindowState(win->ghostwin);
				win->windowstate = state;

				/* win32: gives undefined window size when minimized */
				if (state != GHOST_kWindowStateMinimized) {
					GHOST_RectangleHandle client_rect;
					int l, t, r, b, scr_w, scr_h;
					int sizex, sizey, posx, posy;
					
					client_rect = GHOST_GetClientBounds(win->ghostwin);
					GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
					
					GHOST_DisposeRectangle(client_rect);
					
					wm_get_screensize(&scr_w, &scr_h);
					sizex = r - l;
					sizey = b - t;
					posx = l;
					posy = scr_h - t - win->sizey;

					/*
					 * Ghost sometimes send size or move events when the window hasn't changed.
					 * One case of this is using compiz on linux. To alleviate the problem
					 * we ignore all such event here.
					 * 
					 * It might be good to eventually do that at Ghost level, but that is for 
					 * another time.
					 */
					if (win->sizex != sizex ||
					    win->sizey != sizey ||
					    win->posx != posx ||
					    win->posy != posy)
					{
						win->sizex = sizex;
						win->sizey = sizey;
						win->posx = posx;
						win->posy = posy;

						/* debug prints */
						if (G.debug & G_DEBUG_EVENTS) {
							const char *state_str;
							state = GHOST_GetWindowState(win->ghostwin);

							if (state == GHOST_kWindowStateNormal) {
								state_str = "normal";
							}
							else if (state == GHOST_kWindowStateMinimized) {
								state_str = "minimized";
							}
							else if (state == GHOST_kWindowStateMaximized) {
								state_str = "maximized";
							}
							else if (state == GHOST_kWindowStateFullScreen) {
								state_str = "fullscreen";
							}
							else {
								state_str = "<unknown>";
							}

							printf("%s: window %d state = %s\n", __func__, win->winid, state_str);

							if (type != GHOST_kEventWindowSize) {
								printf("win move event pos %d %d size %d %d\n",
								       win->posx, win->posy, win->sizex, win->sizey);
							}
						}
					
						wm_window_make_drawable(C, win);
						wm_draw_window_clear(win);
						WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
						WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
					}
				}
				break;
			}
				
			case GHOST_kEventOpenMainFile:
			{
				PointerRNA props_ptr;
				wmWindow *oldWindow;
				char *path = GHOST_GetEventData(evt);
				
				if (path) {
					/* operator needs a valid window in context, ensures
					 * it is correctly set */
					oldWindow = CTX_wm_window(C);
					CTX_wm_window_set(C, win);
					
					WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile");
					RNA_string_set(&props_ptr, "filepath", path);
					WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr);
					WM_operator_properties_free(&props_ptr);
					
					CTX_wm_window_set(C, oldWindow);
				}
				break;
			}
			case GHOST_kEventDraggingDropDone:
			{
				wmEvent event;
				GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
				int cx, cy, wx, wy;
				
				/* entering window, update mouse pos */
				GHOST_GetCursorPosition(g_system, &wx, &wy);
				
				GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
				win->eventstate->x = cx;
				win->eventstate->y = (win->sizey - 1) - cy;
				
				event = *(win->eventstate);  /* copy last state, like mouse coords */
				
				/* activate region */
				event.type = MOUSEMOVE;
				event.prevx = event.x;
				event.prevy = event.y;
				
				wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
				win->active = 1;
				
				wm_event_add(win, &event);
				
				
				/* make blender drop event with custom data pointing to wm drags */
				event.type = EVT_DROP;
				event.val = KM_RELEASE;
				event.custom = EVT_DATA_LISTBASE;
				event.customdata = &wm->drags;
				event.customdatafree = 1;
				
				wm_event_add(win, &event);
				
				/* printf("Drop detected\n"); */
				
				/* add drag data to wm for paths: */
				
				if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
					GHOST_TStringArray *stra = ddd->data;
					int a, icon;
					
					for (a = 0; a < stra->count; a++) {
						printf("drop file %s\n", stra->strings[a]);
						/* try to get icon type from extension */
						icon = ED_file_extension_icon((char *)stra->strings[a]);
						
						WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0);
						/* void poin should point to string, it makes a copy */
						break; /* only one drop element supported now */
					}
				}
				
				
				
				break;
			}
			
			default:
				wm_event_add_ghostevent(wm, win, type, time, data);
				break;
		}

	}
	return 1;
}
Пример #7
0
static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
	PointerRNA ptr;
	PropertyRNA *prop;
	FileBrowseOp *fbo;
	char *str;

	if (CTX_wm_space_file(C)) {
		BKE_report(op->reports, RPT_ERROR, "Cannot activate a file selector, one already open");
		return OPERATOR_CANCELLED;
	}

	uiFileBrowseContextProperty(C, &ptr, &prop);

	if (!prop)
		return OPERATOR_CANCELLED;

	str = RNA_property_string_get_alloc(&ptr, prop, NULL, 0, NULL);

	/* useful yet irritating feature, Shift+Click to open the file
	 * Alt+Click to browse a folder in the OS's browser */
	if (event->shift || event->alt) {
		PointerRNA props_ptr;

		if (event->alt) {
			char *lslash = (char *)BLI_last_slash(str);
			if (lslash)
				*lslash = '\0';
		}


		WM_operator_properties_create(&props_ptr, "WM_OT_path_open");
		RNA_string_set(&props_ptr, "filepath", str);
		WM_operator_name_call(C, "WM_OT_path_open", WM_OP_EXEC_DEFAULT, &props_ptr);
		WM_operator_properties_free(&props_ptr);

		MEM_freeN(str);
		return OPERATOR_CANCELLED;
	}
	else {
		const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
		fbo = MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
		fbo->ptr = ptr;
		fbo->prop = prop;
		op->customdata = fbo;

		RNA_string_set(op->ptr, path_prop, str);
		MEM_freeN(str);

		/* normally ED_fileselect_get_params would handle this but we need to because of stupid
		 * user-prefs exception - campbell */
		if (RNA_struct_find_property(op->ptr, "relative_path")) {
			if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
				/* annoying exception!, if were dealing with the user prefs, default relative to be off */
				RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS && (ptr.data != &U));
			}
		}
		WM_event_add_fileselect(C, op);

		return OPERATOR_RUNNING_MODAL;
	}
}
Пример #8
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;
}