Beispiel #1
0
/* Used for drag and drop parenting */
TreeElement *outliner_dropzone_parent(bContext *C, wmEvent *event, TreeElement *te, float *fmval)
{
	SpaceOops *soops = CTX_wm_space_outliner(C);
	TreeStoreElem *tselem = TREESTORE(te);

	if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
		/* name and first icon */
		if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) {
			/* always makes active object */
			if (te->idcode == ID_OB) {
				return te;
			}
			else {
				return NULL;
			}
		}
	}

	/* Not it.  Let's look at its children. */
	if ((tselem->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
		for (te = te->subtree.first; te; te = te->next) {
			TreeElement *te_valid;
			te_valid = outliner_dropzone_parent(C, event, te, fmval);
			if (te_valid) return te_valid;
		}
	}
	return NULL;
}
Beispiel #2
0
static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement *te, int all, const float mval[2])
{
	
	if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
		TreeStoreElem *tselem= TREESTORE(te);
		
		/* all below close/open? */
		if(all) {
			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;
	}
	
	for(te= te->subtree.first; te; te= te->next) {
		if(do_outliner_item_openclose(C, soops, te, all, mval)) 
			return 1;
	}
	return 0;
	
}
Beispiel #3
0
static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
{
	TreeElement *tep;
	TreeStoreElem *tselem=NULL;
	Scene *sce=NULL;
	
	tep= te->parent;
	if(tep) {
		tselem= TREESTORE(tep);
		sce= (Scene *)tselem->id;
	}
	
	if(set) {	// make new scene active
		if(sce && scene != sce) {
			ED_screen_set_scene(C, sce);
		}
	}
	
	if(tep==NULL || tselem->id == (ID *)scene) {
		if(set) {
// XXX			extern_set_butspace(F8KEY, 0);
		}
		else {
			return 1;
		}
	}
	return 0;
}
Beispiel #4
0
void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, 
                                  void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
                                                       TreeStoreElem *, TreeStoreElem *))
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te = lb->first; te; te = te->next) {
		tselem = TREESTORE(te);
		if (tselem->flag & TSE_SELECTED) {
			if (tselem->type == 0 && te->idcode == ID_OB) {
				// when objects selected in other scenes... dunno if that should be allowed
				Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE);
				if (scene_owner && scene_act != scene_owner) {
					ED_screen_set_scene(C, CTX_wm_screen(C), scene_owner);
				}
				/* important to use 'scene_owner' not scene_act else deleting objects can crash.
				 * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
				 * outliner isn't showing scenes: Visible Layer draw mode for eg. */
				operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem);
			}
		}
		if (TSELEM_OPEN(tselem, soops)) {
			outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb);
		}
	}
}
Beispiel #5
0
/* Recursively iterate over tree, finding and working on selected items */
static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBase *tree, short mode)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te= tree->first; te; te=te->next) {
		tselem= TREESTORE(te);
		
		/* if item is selected, perform operation */
		if (tselem->flag & TSE_SELECTED) {
			ID *id= NULL;
			char *path= NULL;
			int array_index= 0;
			short flag= 0;
			short groupmode= KSP_GROUP_KSNAME;
			
			/* check if RNA-property described by this selected element is an animateable prop */
			if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && RNA_property_animateable(&te->rnaptr, te->directdata)) {
				/* get id + path + index info from the selected element */
				tree_element_to_path(soops, te, tselem, 
						&id, &path, &array_index, &flag, &groupmode);
			}
			
			/* only if ID and path were set, should we perform any actions */
			if (id && path) {
				/* action depends on mode */
				switch (mode) {
					case KEYINGSET_EDITMODE_ADD:
					{
						/* add a new path with the information obtained (only if valid) */
						// TODO: what do we do with group name? for now, we don't supply one, and just let this use the KeyingSet name
						BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
						ks->active_path= BLI_countlist(&ks->paths);
					}
						break;
					case KEYINGSET_EDITMODE_REMOVE:
					{
						/* find the relevant path, then remove it from the KeyingSet */
						KS_Path *ksp= BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode);
						
						if (ksp) {
							/* free path's data */
							BKE_keyingset_free_path(ks, ksp);

							ks->active_path= 0;
						}
					}
						break;
				}
				
				/* free path, since it had to be generated */
				MEM_freeN(path);
			}
		}
		
		/* go over sub-tree */
		if ((tselem->flag & TSE_CLOSED)==0)
			do_outliner_keyingset_editop(soops, ks, &te->subtree, mode);
	}
}
Beispiel #6
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;
}
Beispiel #7
0
static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, 
										 void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *))
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te=lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		if (tselem->flag & TSE_SELECTED) {
			if (tselem->type==0) {
				TreeStoreElem *tsep= TREESTORE(te->parent);
				operation_cb(C, scene, te, tsep, tselem);
			}
		}
		if (TSELEM_OPEN(tselem,soops)) {
			outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb);
		}
	}
}
Beispiel #8
0
static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid,
                                         void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te = lb->first; te; te = te->next) {
		tselem = TREESTORE(te);
		if (tselem->flag & TSE_SELECTED) {
			if (tselem->type == type) {
				TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
				operation_cb(te, tselem, tsep, newid);
			}
		}
		if (TSELEM_OPEN(tselem, soops)) {
			outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb);
		}
	}
}
ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
{
	TreeStoreElem *tselem;
	te = te->parent;
	
	while (te) {
		tselem = TREESTORE(te);
		if (tselem->type == 0 && te->idcode == idcode) return tselem->id;
		te = te->parent;
	}
	return NULL;
}
Beispiel #10
0
void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for(te= lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		if(set==0) tselem->flag &= ~flag;
		else tselem->flag |= flag;
		outliner_set_flag(soops, &te->subtree, flag, set);
	}
}
Beispiel #11
0
/* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/
static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for(te= lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		if(tselem->type==0 && te->idcode==ID_OB) return 1;
		if( subtree_has_objects(soops, &te->subtree)) return 1;
	}
	return 0;
}
Beispiel #12
0
/* return 1 when levels were opened */
static int outliner_open_back(SpaceOops *soops, TreeElement *te)
{
	TreeStoreElem *tselem;
	int retval= 0;
	
	for (te= te->parent; te; te= te->parent) {
		tselem= TREESTORE(te);
		if (tselem->flag & TSE_CLOSED) { 
			tselem->flag &= ~TSE_CLOSED;
			retval= 1;
		}
	}
	return retval;
}
Beispiel #13
0
int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	int level;
	
	for(te= lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		if(tselem->flag & flag) return curlevel;
		
		level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1);
		if(level) return level;
	}
	return 0;
}
Beispiel #14
0
/* recursive helper for function below */
static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
{
	TreeStoreElem *tselem= TREESTORE(te);
	
	/* store coord and continue, we need coordinates for elements outside view too */
	te->xs= (float)startx;
	te->ys= (float)(*starty);
	*starty-= UI_UNIT_Y;
	
	if((tselem->flag & TSE_CLOSED)==0) {
		TreeElement *ten;
		for(ten= te->subtree.first; ten; ten= ten->next) {
			outliner_set_coordinates_element(soops, ten, startx+UI_UNIT_X, starty);
		}
	}
	
}
Beispiel #15
0
static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	int change= 0;
	
	for (te= lb->first; te && *index >= 0; te=te->next, (*index)--) {
		tselem= TREESTORE(te);
		
		/* if we've encountered the right item, set its 'Outliner' selection status */
		if (*index == 0) {
			/* this should be the last one, so no need to do anything with index */
			if ((te->flag & TE_ICONROW)==0) {
				/* -1 value means toggle testing for now... */
				if (*selecting == -1) {
					if (tselem->flag & TSE_SELECTED) 
						*selecting= 0;
					else 
						*selecting= 1;
				}
				
				/* set selection */
				if (*selecting) 
					tselem->flag |= TSE_SELECTED;
				else 
					tselem->flag &= ~TSE_SELECTED;

				change |= 1;
			}
		}
		else if (TSELEM_OPEN(tselem,soops)) {
			/* Only try selecting sub-elements if we haven't hit the right element yet
			 *
			 * Hack warning:
			 * 	Index must be reduced before supplying it to the sub-tree to try to do
			 * 	selection, however, we need to increment it again for the next loop to 
			 * 	function correctly
			 */
			(*index)--;
			change |= outliner_select(soops, &te->subtree, index, selecting);
			(*index)++;
		}
	}

	return change;
}
Beispiel #16
0
static void set_operation_types(SpaceOops *soops, ListBase *lb,
                                int *scenelevel,
                                int *objectlevel,
                                int *idlevel,
                                int *datalevel)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te = lb->first; te; te = te->next) {
		tselem = TREESTORE(te);
		if (tselem->flag & TSE_SELECTED) {
			if (tselem->type) {
				if (*datalevel == 0)
					*datalevel = tselem->type;
				else if (*datalevel != tselem->type)
					*datalevel = -1;
			}
			else {
				int idcode = GS(tselem->id->name);
				switch (idcode) {
					case ID_SCE:
						*scenelevel = 1;
						break;
					case ID_OB:
						*objectlevel = 1;
						break;
						
					case ID_ME: case ID_CU: case ID_MB: case ID_LT:
					case ID_LA: case ID_AR: case ID_CA: case ID_SPK:
					case ID_MA: case ID_TE: case ID_IP: case ID_IM:
					case ID_SO: case ID_KE: case ID_WO: case ID_AC:
					case ID_NLA: case ID_TXT: case ID_GR:
						if (*idlevel == 0) *idlevel = idcode;
						else if (*idlevel != idcode) *idlevel = -1;
						break;
				}
			}
		}
		if (TSELEM_OPEN(tselem, soops)) {
			set_operation_types(soops, &te->subtree,
			                    scenelevel, objectlevel, idlevel, datalevel);
		}
	}
}
Beispiel #17
0
/* helper function for Show/Hide one level operator */
static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for(te= lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		
		if(open) {
			if(curlevel<=level) tselem->flag &= ~TSE_CLOSED;
		}
		else {
			if(curlevel>=level) tselem->flag |= TSE_CLOSED;
		}
		
		outliner_openclose_level(soops, &te->subtree, curlevel+1, level, open);
	}
}
Beispiel #18
0
/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
{
	TreeElement *te, *tes;
	TreeStoreElem *tselem;
	
	for (te = lb->first; te; te = te->next) {
		tselem = TREESTORE(te);
		if (tselem->type == 0) {
			if (tselem->id == id) return te;
			/* only deeper on scene or object */
			if (te->idcode == ID_OB || te->idcode == ID_SCE || (soops->outlinevis == SO_GROUPS && te->idcode == ID_GR)) {
				tes = outliner_find_id(soops, &te->subtree, id);
				if (tes) return tes;
			}
		}
	}
	return NULL;
}
Beispiel #19
0
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, 
										 void (*operation_cb)(int, TreeElement *, TreeStoreElem *))
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te=lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		if (tselem->flag & TSE_SELECTED) {
			if (tselem->type==type) {
				operation_cb(event, te, tselem);
			}
		}
		if (TSELEM_OPEN(tselem,soops)) {
			outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb);
		}
	}
}
Beispiel #20
0
static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, const float mval[2])
{	
	ReportList *reports= CTX_wm_reports(C); // XXX
	
	if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
		TreeStoreElem *tselem= TREESTORE(te);
		
		/* name and first icon */
		if(mval[0]>te->xs+UI_UNIT_X && mval[0]<te->xend) {
			
			do_item_rename(ar, te, tselem, reports) ;
		}
		return 1;
	}
	
	for(te= te->subtree.first; te; te= te->next) {
		if(do_outliner_item_rename(C, ar, soops, te, mval)) return 1;
	}
	return 0;
}
Beispiel #21
0
/* **************** Border Select Tool ****************** */
static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *rectf, TreeElement *te, int gesture_mode)
{
	TreeStoreElem *tselem= TREESTORE(te);

	if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
		if (gesture_mode == GESTURE_MODAL_SELECT) {
			tselem->flag |= TSE_SELECTED;
		}
		else {
			tselem->flag &= ~TSE_SELECTED;
		}
	}

	/* Look at its children. */
	if ((tselem->flag & TSE_CLOSED) == 0) {
		for (te = te->subtree.first; te; te = te->next) {
			outliner_item_border_select(scene, soops, rectf, te, gesture_mode);
		}
	}
	return;
}
Beispiel #22
0
static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te= lb->first; te; te= te->next) {
		/* check if this tree-element was the one we're seeking */
		if (te == teFind) {
			*found= 1;
			return;
		}
		
		/* try to see if sub-tree contains it then */
		outliner_open_reveal(soops, &te->subtree, teFind, found);
		if (*found) {
			tselem= TREESTORE(te);
			if (tselem->flag & TSE_CLOSED) 
				tselem->flag &= ~TSE_CLOSED;
			return;
		}
	}
}
Beispiel #23
0
int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te, float *fmval)
{
	SpaceOops *soops = CTX_wm_space_outliner(C);
	TreeStoreElem *tselem = TREESTORE(te);

	/* Check for row */
	if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
		/* Ignore drop on scene tree elements */
		if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) {
			if ((te->idcode == ID_SCE) && 
			    !ELEM3(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS))
			{
				return 0;
			}
			// Other codes to ignore?
		}
		
		/* Left or right of: (+), first icon, and name */
		if ((fmval[0] < (te->xs + UI_UNIT_X)) || (fmval[0] > te->xend)) {
			return 1;
		}
		else if (te->idcode != ID_OB) {
			return 1;
		}
		
		return 0;       // ID_OB, but mouse in undefined dropzone.
	}

	/* Not this row.  Let's look at its children. */
	if ((tselem->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
		for (te = te->subtree.first; te; te = te->next) {
			if (outliner_dropzone_parent_clear(C, event, te, fmval)) 
				return 1;
		}
	}
	return 0;
}
Beispiel #24
0
/* recursive helper function for Show Hierarchy operator */
static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase *lb)
{
	TreeElement *te;
	TreeStoreElem *tselem;

	/* open all object elems, close others */
	for(te= lb->first; te; te= te->next) {
		tselem= TREESTORE(te);
		
		if(tselem->type==0) {
			if(te->idcode==ID_SCE) {
				if(tselem->id!=(ID *)scene) tselem->flag |= TSE_CLOSED;
					else tselem->flag &= ~TSE_CLOSED;
			}
			else if(te->idcode==ID_OB) {
				if(subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
				else tselem->flag |= TSE_CLOSED;
			}
		}
		else tselem->flag |= TSE_CLOSED;
		
		if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(scene, soops, &te->subtree);
	}
}
Beispiel #25
0
static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
	bContext *C = C_v;
	SpaceOops *soops = CTX_wm_space_outliner(C);
	bConstraint *constraint = (bConstraint *)te->directdata;
	Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);

	if (event == OL_CONSTRAINTOP_ENABLE) {
		constraint->flag &= ~CONSTRAINT_OFF;
		ED_object_constraint_update(ob);
		WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
	}
	else if (event == OL_CONSTRAINTOP_DISABLE) {
		constraint->flag = CONSTRAINT_OFF;
		ED_object_constraint_update(ob);
		WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
	}
	else if (event == OL_CONSTRAINTOP_DELETE) {
		ListBase *lb = NULL;

		if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
			lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
		}
		else {
			lb = &ob->constraints;
		}

		if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
			/* there's no active constraint now, so make sure this is the case */
			BKE_constraints_active_set(&ob->constraints, NULL);
			ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
			WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
			te->store_elem->flag &= ~TSE_SELECTED;
		}
	}
}
Beispiel #26
0
static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
                                       TreeElement *te, const wmEvent *event, const float mval[2])
{
	ReportList *reports = CTX_wm_reports(C); // XXX...
	
	if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
		int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
		TreeStoreElem *tselem = TREESTORE(te);
		
		/* select object that's clicked on and popup context menu */
		if (!(tselem->flag & TSE_SELECTED)) {
			
			if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) )
				outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
			
			tselem->flag |= TSE_SELECTED;
			/* redraw, same as outliner_select function */
			soops->storeflag |= SO_TREESTORE_REDRAW;
			ED_region_tag_redraw(ar);
		}
		
		set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
		
		if (scenelevel) {
			//if (objectlevel || datalevel || idlevel) error("Mixed selection");
			//else pupmenu("Scene Operations%t|Delete");
		}
		else if (objectlevel) {
			WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
		}
		else if (idlevel) {
			if (idlevel == -1 || datalevel) {
				BKE_report(reports, RPT_WARNING, "Mixed selection");
			}
			else {
				if (idlevel == ID_GR)
					WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
				else
					WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
			}
		}
		else if (datalevel) {
			if (datalevel == -1) {
				BKE_report(reports, RPT_WARNING, "Mixed selection");
			}
			else {
				if (datalevel == TSE_ANIM_DATA)
					WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL);
				else if (datalevel == TSE_DRIVER_BASE) {
					/* do nothing... no special ops needed yet */
				}
				else if (ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
					/*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
				}
				else {
					WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
				}
			}
		}
		
		return 1;
	}
	
	for (te = te->subtree.first; te; te = te->next) {
		if (do_outliner_operation_event(C, scene, ar, soops, te, event, mval))
			return 1;
	}
	return 0;
}
Beispiel #27
0
/* Helper func to extract an RNA path from selected tree element 
 * NOTE: the caller must zero-out all values of the pointers that it passes here first, as
 * this function does not do that yet 
 */
static void tree_element_to_path(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, 
							ID **id, char **path, int *array_index, short *flag, short *UNUSED(groupmode))
{
	ListBase hierarchy = {NULL, NULL};
	LinkData *ld;
	TreeElement *tem, *temnext, *temsub;
	TreeStoreElem *tse, *tsenext;
	PointerRNA *ptr, *nextptr;
	PropertyRNA *prop;
	char *newpath=NULL;
	
	/* optimise tricks:
	 *	- Don't do anything if the selected item is a 'struct', but arrays are allowed
	 */
	if (tselem->type == TSE_RNA_STRUCT)
		return;
	
	/* Overview of Algorithm:
	 * 	1. Go up the chain of parents until we find the 'root', taking note of the 
	 *	   levels encountered in reverse-order (i.e. items are added to the start of the list
	 *      for more convenient looping later)
	 * 	2. Walk down the chain, adding from the first ID encountered 
	 *	   (which will become the 'ID' for the KeyingSet Path), and build a  
	 * 		path as we step through the chain
	 */
	 
	/* step 1: flatten out hierarchy of parents into a flat chain */
	for (tem= te->parent; tem; tem= tem->parent) {
		ld= MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()");
		ld->data= tem;
		BLI_addhead(&hierarchy, ld);
	}
	
	/* step 2: step down hierarchy building the path (NOTE: addhead in previous loop was needed so that we can loop like this) */
	for (ld= hierarchy.first; ld; ld= ld->next) {
		/* get data */
		tem= (TreeElement *)ld->data;
		tse= TREESTORE(tem);
		ptr= &tem->rnaptr;
		prop= tem->directdata;
		
		/* check if we're looking for first ID, or appending to path */
		if (*id) {
			/* just 'append' property to path 
			 *	- to prevent memory leaks, we must write to newpath not path, then free old path + swap them
			 */
			if(tse->type == TSE_RNA_PROPERTY) {
				if(RNA_property_type(prop) == PROP_POINTER) {
					/* for pointer we just append property name */
					newpath= RNA_path_append(*path, ptr, prop, 0, NULL);
				}
				else if(RNA_property_type(prop) == PROP_COLLECTION) {
					char buf[128], *name;
					
					temnext= (TreeElement*)(ld->next->data);
					tsenext= TREESTORE(temnext);
					
					nextptr= &temnext->rnaptr;
					name= RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf));
					
					if(name) {
						/* if possible, use name as a key in the path */
						newpath= RNA_path_append(*path, NULL, prop, 0, name);
						
						if(name != buf)
							MEM_freeN(name);
					}
					else {
						/* otherwise use index */
						int index= 0;
						
						for(temsub=tem->subtree.first; temsub; temsub=temsub->next, index++)
							if(temsub == temnext)
								break;
						
						newpath= RNA_path_append(*path, NULL, prop, index, NULL);
					}
					
					ld= ld->next;
				}
			}
			
			if(newpath) {
				if (*path) MEM_freeN(*path);
				*path= newpath;
				newpath= NULL;
			}
		}
		else {
			/* no ID, so check if entry is RNA-struct, and if that RNA-struct is an ID datablock to extract info from */
			if (tse->type == TSE_RNA_STRUCT) {
				/* ptr->data not ptr->id.data seems to be the one we want, since ptr->data is sometimes the owner of this ID? */
				if(RNA_struct_is_ID(ptr->type)) {
					*id= (ID *)ptr->data;
					
					/* clear path */
					if(*path) {
						MEM_freeN(*path);
						path= NULL;
					}
				}
			}
		}
	}

	/* step 3: if we've got an ID, add the current item to the path */
	if (*id) {
		/* add the active property to the path */
		ptr= &te->rnaptr;
		prop= te->directdata;
		
		/* array checks */
		if (tselem->type == TSE_RNA_ARRAY_ELEM) {
			/* item is part of an array, so must set the array_index */
			*array_index= te->index;
		}
		else if (RNA_property_array_length(ptr, prop)) {
			/* entire array was selected, so keyframe all */
			*flag |= KSP_FLAG_WHOLE_ARRAY;
		}
		
		/* path */
		newpath= RNA_path_append(*path, NULL, prop, 0, NULL);
		if (*path) MEM_freeN(*path);
		*path= newpath;
	}

	/* free temp data */
	BLI_freelistN(&hierarchy);
}
Beispiel #28
0
// TODO: this function needs to be split up! It's getting a bit too large...
// Note: "ID" is not always a real ID
static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 
                                         TreeElement *parent, short type, short index)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	ID *id = idv;
	
	if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
		id = ((PointerRNA *)idv)->id.data;
		if (!id) id = ((PointerRNA *)idv)->data;
	}

	/* One exception */
	if (type == TSE_ID_BASE) {
		/* pass */
	}
	else if (id == NULL) {
		return NULL;
	}

	te = MEM_callocN(sizeof(TreeElement), "tree elem");
	/* add to the visual tree */
	BLI_addtail(lb, te);
	/* add to the storage */
	check_persistent(soops, te, id, type, index);
	tselem = TREESTORE(te);
	
	/* if we are searching for something expand to see child elements */
	if (SEARCHING_OUTLINER(soops))
		tselem->flag |= TSE_CHILDSEARCH;
	
	te->parent = parent;
	te->index = index;   // for data arays
	if (ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
		/* pass */
	}
	else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
		/* pass */
	}
	else if (type == TSE_ANIM_DATA) {
		/* pass */
	}
	else if (type == TSE_ID_BASE) {
		/* pass */
	}
	else {
		/* do here too, for blend file viewer, own ID_LI then shows file name */
		if (GS(id->name) == ID_LI)
			te->name = ((Library *)id)->name;
		else
			te->name = id->name + 2; // default, can be overridden by Library or non-ID data
		te->idcode = GS(id->name);
	}
	
	if (type == 0) {
		TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
		
		/* ID datablock */
		if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
			outliner_add_id_contents(soops, te, tselem, id);
	}
	else if (type == TSE_ANIM_DATA) {
		IdAdtTemplate *iat = (IdAdtTemplate *)idv;
		AnimData *adt = (AnimData *)iat->adt;
		
		/* this element's info */
		te->name = IFACE_("Animation");
		te->directdata = adt;
		
		/* Action */
		outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
		
		/* Drivers */
		if (adt->drivers.first) {
			TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
			ID *lastadded = NULL;
			FCurve *fcu;
			
			ted->name = IFACE_("Drivers");
		
			for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
				if (fcu->driver && fcu->driver->variables.first) {
					ChannelDriver *driver = fcu->driver;
					DriverVar *dvar;
					
					for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
						/* loop over all targets used here */
						DRIVER_TARGETS_USED_LOOPER(dvar) 
						{
							if (lastadded != dtar->id) {
								// XXX this lastadded check is rather lame, and also fails quite badly...
								outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
								lastadded = dtar->id;
							}
						}
						DRIVER_TARGETS_LOOPER_END
					}
				}
			}
Beispiel #29
0
static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *soops, int again, int flags) 
{
	ReportList *reports = NULL; // CTX_wm_reports(C);
	TreeElement *te= NULL;
	TreeElement *last_find;
	TreeStoreElem *tselem;
	int ytop, xdelta, prevFound=0;
	char name[32];
	
	/* get last found tree-element based on stored search_tse */
	last_find= outliner_find_tse(soops, &soops->search_tse);
	
	/* determine which type of search to do */
	if (again && last_find) {
		/* no popup panel - previous + user wanted to search for next after previous */		
		BLI_strncpy(name, soops->search_string, sizeof(name));
		flags= soops->search_flags;
		
		/* try to find matching element */
		te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
		if (te==NULL) {
			/* no more matches after previous, start from beginning again */
			prevFound= 1;
			te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
		}
	}
	else {
		/* pop up panel - no previous, or user didn't want search after previous */
		strcpy(name, "");
// XXX		if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
//			te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound);
//		}
//		else return; /* XXX RETURN! XXX */
	}

	/* do selection and reveal */
	if (te) {
		tselem= TREESTORE(te);
		if (tselem) {
			/* expand branches so that it will be visible, we need to get correct coordinates */
			if( outliner_open_back(soops, te))
				outliner_set_coordinates(ar, soops);
			
			/* deselect all visible, and select found element */
			outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
			tselem->flag |= TSE_SELECTED;
			
			/* make te->ys center of view */
			ytop= (int)(te->ys + (ar->v2d.mask.ymax-ar->v2d.mask.ymin)/2);
			if(ytop>0) ytop= 0;
			ar->v2d.cur.ymax= (float)ytop;
			ar->v2d.cur.ymin= (float)(ytop-(ar->v2d.mask.ymax-ar->v2d.mask.ymin));
			
			/* make te->xs ==> te->xend center of view */
			xdelta = (int)(te->xs - ar->v2d.cur.xmin);
			ar->v2d.cur.xmin += xdelta;
			ar->v2d.cur.xmax += xdelta;
			
			/* store selection */
			soops->search_tse= *tselem;
			
			BLI_strncpy(soops->search_string, name, 33);
			soops->search_flags= flags;
			
			/* redraw */
			soops->storeflag |= SO_TREESTORE_REDRAW;
		}
	}
	else {
		/* no tree-element found */
		BKE_report(reports, RPT_WARNING, "Not found: %s", name);
	}
}
Beispiel #30
0
/* Recursively iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOops *soops, ListBase *tree, ReportList *reports, short mode)
{
	TreeElement *te;
	TreeStoreElem *tselem;
	
	for (te= tree->first; te; te=te->next) {
		tselem= TREESTORE(te);
		
		/* if item is selected, perform operation */
		if (tselem->flag & TSE_SELECTED) {
			ID *id= NULL;
			char *path= NULL;
			int array_index= 0;
			short flag= 0;
			short groupmode= KSP_GROUP_KSNAME;
			
			/* check if RNA-property described by this selected element is an animateable prop */
			if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && RNA_property_animateable(&te->rnaptr, te->directdata)) {
				/* get id + path + index info from the selected element */
				tree_element_to_path(soops, te, tselem, 
						&id, &path, &array_index, &flag, &groupmode);
			}
			
			/* only if ID and path were set, should we perform any actions */
			if (id && path) {
				short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
				int arraylen = 1;
				
				/* array checks */
				if (flag & KSP_FLAG_WHOLE_ARRAY) {
					/* entire array was selected, so add drivers for all */
					arraylen= RNA_property_array_length(&te->rnaptr, te->directdata);
				}
				else
					arraylen= array_index;
				
				/* we should do at least one step */
				if (arraylen == array_index)
					arraylen++;
				
				/* for each array element we should affect, add driver */
				for (; array_index < arraylen; array_index++) {
					/* action depends on mode */
					switch (mode) {
						case DRIVERS_EDITMODE_ADD:
						{
							/* add a new driver with the information obtained (only if valid) */
							ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
						}
							break;
						case DRIVERS_EDITMODE_REMOVE:
						{
							/* remove driver matching the information obtained (only if valid) */
							ANIM_remove_driver(reports, id, path, array_index, dflags);
						}
							break;
					}
				}
				
				/* free path, since it had to be generated */
				MEM_freeN(path);
			}
			
			
		}
		
		/* go over sub-tree */
		if ((tselem->flag & TSE_CLOSED)==0)
			do_outliner_drivers_editop(soops, &te->subtree, reports, mode);
	}
}