Esempio n. 1
0
/* evaluation settings for active NLA-Strip */
static void nla_panel_evaluation(const bContext *C, Panel *pa)
{
	PointerRNA strip_ptr;
	uiLayout *layout = pa->layout;
	uiLayout *col, *sub;
	uiBlock *block;

	/* check context and also validity of pointer */
	if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
		return;
		
	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
		
	col = uiLayoutColumn(layout, true);
	uiItemR(col, &strip_ptr, "use_animated_influence", 0, NULL, ICON_NONE);
	
	sub = uiLayoutColumn(col, true);
	uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_influence"));
	uiItemR(sub, &strip_ptr, "influence", 0, NULL, ICON_NONE);

	col = uiLayoutColumn(layout, true);
	sub = uiLayoutRow(col, false);
	uiItemR(sub, &strip_ptr, "use_animated_time", 0, NULL, ICON_NONE);
	uiItemR(sub, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);

	sub = uiLayoutRow(col, false);
	uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_time"));
	uiItemR(sub, &strip_ptr, "strip_time", 0, NULL, ICON_NONE);
}
/* TODO de-duplicate redo panel functions - campbell */
static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
{
	wmOperator *op = WM_operator_last_redo(C);
	ARegion *ar;
	ARegion *ar1;

	if (op == NULL) {
		return;
	}

	/* keep in sync with logic in ED_undo_operator_repeat() */
	ar = CTX_wm_region(C);
	ar1 = BKE_area_find_region_active_win(CTX_wm_area(C));
	if (ar1)
		CTX_wm_region_set((bContext *)C, ar1);

	if (WM_operator_poll((bContext *)C, op->type)) {
		uiBlock *block = uiLayoutGetBlock(pa->layout);

		if (!WM_operator_check_ui_enabled(C, op->type->name))
			uiLayoutSetEnabled(pa->layout, false);

		/* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */
		UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);

		view3d_panel_operator_redo_operator(C, pa, op);
	}

	/* set region back */
	CTX_wm_region_set((bContext *)C, ar);
}
Esempio n. 3
0
/* active AnimData */
static void nla_panel_animdata(const bContext *C, Panel *pa)
{
	PointerRNA adt_ptr;
	/* AnimData *adt; */
	uiLayout *layout = pa->layout;
	uiLayout *row;
	uiBlock *block;
	
	/* check context and also validity of pointer */
	if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
		return;

	/* adt = adt_ptr.data; */
	
	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
	
	/* AnimData Source Properties ----------------------------------- */
	
	/* icon + id-block name of block where AnimData came from to prevent 
	 * accidentally changing the properties of the wrong action
	 */
	if (adt_ptr.id.data) {
		ID *id = adt_ptr.id.data;
		PointerRNA id_ptr;
		
		RNA_id_pointer_create(id, &id_ptr);
		
		/* ID-block name > AnimData */
		row = uiLayoutRow(layout, true);
		uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
		
		uiItemL(row, id->name + 2, RNA_struct_ui_icon(id_ptr.type));  /* id-block (src) */
		uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);                   /* expander */
		uiItemL(row, IFACE_("Animation Data"), ICON_ANIM_DATA);       /* animdata */
		
		uiItemS(layout);
	}
	
	/* Active Action Properties ------------------------------------- */
	/* action */
	row = uiLayoutRow(layout, true);
	uiTemplateID(
	        row, (bContext *)C, &adt_ptr, "action",
	        "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL);
	
	/* extrapolation */
	row = uiLayoutRow(layout, true);
	uiItemR(row, &adt_ptr, "action_extrapolation", 0, NULL, ICON_NONE);
	
	/* blending */
	row = uiLayoutRow(layout, true);
	uiItemR(row, &adt_ptr, "action_blend_type", 0, NULL, ICON_NONE);
		
	/* influence */
	row = uiLayoutRow(layout, true);
	uiItemR(row, &adt_ptr, "action_influence", 0, NULL, ICON_NONE);
}
Esempio n. 4
0
/* active NLA-Track */
static void nla_panel_track(const bContext *C, Panel *pa)
{
	PointerRNA nlt_ptr;
	uiLayout *layout = pa->layout;
	uiLayout *row;
	uiBlock *block;
	
	/* check context and also validity of pointer */
	if (!nla_panel_context(C, NULL, &nlt_ptr, NULL))
		return;
	
	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
	
	/* Info - Active NLA-Context:Track ----------------------  */
	row = uiLayoutRow(layout, true);
	uiItemR(row, &nlt_ptr, "name", 0, NULL, ICON_NLA);
}
Esempio n. 5
0
static void graph_panel_modifiers(const bContext *C, Panel *pa)	
{
	bAnimListElem *ale;
	FCurve *fcu;
	FModifier *fcm;
	uiLayout *col, *row;
	uiBlock *block;
	bool active;
	
	if (!graph_panel_context(C, &ale, &fcu))
		return;
	
	block = uiLayoutGetBlock(pa->layout);
	UI_block_func_handle_set(block, do_graph_region_modifier_buttons, NULL);
	
	/* 'add modifier' button at top of panel */
	{
		row = uiLayoutRow(pa->layout, false);
		
		/* this is an operator button which calls a 'add modifier' operator... 
		 * a menu might be nicer but would be tricky as we need some custom filtering
		 */
		uiItemMenuEnumO(row, (bContext *)C, "GRAPH_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
		
		/* copy/paste (as sub-row) */
		row = uiLayoutRow(row, true);
		uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
		uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
	}
	
	active = !(fcu->flag & FCURVE_MOD_OFF);
	/* draw each modifier */
	for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
		col = uiLayoutColumn(pa->layout, true);
		uiLayoutSetActive(col, active);
		
		ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
	}
	
	MEM_freeN(ale);
}
Esempio n. 6
0
/* action-clip only settings for active NLA-Strip */
static void nla_panel_actclip(const bContext *C, Panel *pa)
{
	PointerRNA strip_ptr;
	uiLayout *layout = pa->layout;
	uiLayout *column, *row;
	uiBlock *block;

	/* check context and also validity of pointer */
	if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
		return;
	
	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
		
	/* Strip Properties ------------------------------------- */
	/* action pointer */
	row = uiLayoutRow(layout, true);
	uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION);
		
	/* action extents */
	// XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
	column = uiLayoutColumn(layout, true);
	uiItemL(column, IFACE_("Action Extents:"), ICON_NONE);
	uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE);
	uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE);
	
	// XXX: this layout may actually be too abstract and confusing, and may be better using standard column layout
	row = uiLayoutRow(layout, false);
	uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE);
	uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length");
		
	/* action usage */
	column = uiLayoutColumn(layout, true);
	uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == false);
	uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
	uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE);
	uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE);
}
Esempio n. 7
0
/* F-Modifiers for active NLA-Strip */
static void nla_panel_modifiers(const bContext *C, Panel *pa)
{
	PointerRNA strip_ptr;
	NlaStrip *strip;
	FModifier *fcm;
	uiLayout *col, *row;
	uiBlock *block;

	/* check context and also validity of pointer */
	if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
		return;
	strip = strip_ptr.data;
		
	block = uiLayoutGetBlock(pa->layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
	
	/* 'add modifier' button at top of panel */
	{
		row = uiLayoutRow(pa->layout, false);
		block = uiLayoutGetBlock(row);
		
		// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
		uiItemMenuEnumO(row, (bContext *)C, "NLA_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
		
		/* copy/paste (as sub-row) */
		row = uiLayoutRow(row, true);
		uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy");
		uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste");
	}
	
	/* draw each modifier */
	for (fcm = strip->modifiers.first; fcm; fcm = fcm->next) {
		col = uiLayoutColumn(pa->layout, true);
		
		ANIM_uiTemplate_fmodifier_draw(col, strip_ptr.id.data, &strip->modifiers, fcm);
	}
}
Esempio n. 8
0
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
{
	Object *obedit = CTX_data_edit_object(C);
	uiBlock *block = uiLayoutGetBlock(layout);

	UI_block_func_handle_set(block, do_view3d_header_buttons, NULL);

	if (obedit && (obedit->type == OB_MESH)) {
		BMEditMesh *em = BKE_editmesh_from_object(obedit);
		uiLayout *row;

		row = uiLayoutRow(layout, true);
		block = uiLayoutGetBlock(row);
		uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
		                 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
		                 TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection"));
		uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
		                 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
		                 TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click expands/contracts selection"));
		uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
		                 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
		                 TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
	}
}
Esempio n. 9
0
/* generic settings for active NLA-Strip */
static void nla_panel_properties(const bContext *C, Panel *pa)
{
	PointerRNA strip_ptr;
	uiLayout *layout = pa->layout;
	uiLayout *column, *row, *sub;
	uiBlock *block;
	short showEvalProps = 1;
	
	if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
		return;
	
	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
	
	/* Strip Properties ------------------------------------- */
	/* strip type */
	row = uiLayoutColumn(layout, true);
	uiItemR(row, &strip_ptr, "name", 0, NULL, ICON_NLA);     // XXX icon?
	uiItemR(row, &strip_ptr, "type", 0, NULL, ICON_NONE);
	
	/* strip extents */
	column = uiLayoutColumn(layout, true);
	uiItemL(column, IFACE_("Strip Extents:"), ICON_NONE);
	uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE);
	uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE);
	
	/* Evaluation-Related Strip Properties ------------------ */
	
	/* sound properties strips don't have these settings */
	if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_SOUND)
		showEvalProps = 0;
	
	/* only show if allowed to... */
	if (showEvalProps) {
		/* extrapolation */
		row = uiLayoutRow(layout, true);
		uiItemR(row, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE);
		
		/* blending */
		row = uiLayoutRow(layout, true);
		uiItemR(row, &strip_ptr, "blend_type", 0, NULL, ICON_NONE);
			
		/* blend in/out + autoblending
		 *	- blend in/out can only be set when autoblending is off
		 */
		column = uiLayoutColumn(layout, true);
		uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
		uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE);     // XXX as toggle?

		sub = uiLayoutColumn(column, true);
		uiLayoutSetActive(sub, RNA_boolean_get(&strip_ptr, "use_auto_blend") == false);
		uiItemR(sub, &strip_ptr, "blend_in", 0, NULL, ICON_NONE);
		uiItemR(sub, &strip_ptr, "blend_out", 0, NULL, ICON_NONE);
			
		/* settings */
		column = uiLayoutColumn(layout, true);
		uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time")));
		uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
		uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE);
		uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
	}
}
Esempio n. 10
0
void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
{
	bScreen *screen = CTX_wm_screen(C);
	ScrArea *sa = CTX_wm_area(C);
	View3D *v3d = sa->spacedata.first;
	Scene *scene = CTX_data_scene(C);
	ToolSettings *ts = CTX_data_tool_settings(C);
	PointerRNA v3dptr, toolsptr, sceneptr;
	Object *ob = OBACT;
	Object *obedit = CTX_data_edit_object(C);
	uiBlock *block;
	uiLayout *row;
	bool is_paint = false;
	int modeselect;
	
	RNA_pointer_create(&screen->id, &RNA_SpaceView3D, v3d, &v3dptr);
	RNA_pointer_create(&scene->id, &RNA_ToolSettings, ts, &toolsptr);
	RNA_pointer_create(&scene->id, &RNA_Scene, scene, &sceneptr);

	block = uiLayoutGetBlock(layout);
	UI_block_func_handle_set(block, do_view3d_header_buttons, NULL);

	/* other buttons: */
	UI_block_emboss_set(block, UI_EMBOSS);
	
	/* mode */
	if (ob) {
		modeselect = ob->mode;
		is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
	}
	else {
		modeselect = OB_MODE_OBJECT;
	}

	row = uiLayoutRow(layout, false);
	{
		EnumPropertyItem *item = object_mode_items;
		const char *name = "";
		int icon = ICON_OBJECT_DATAMODE;

		while (item->identifier) {
			if (item->value == modeselect && item->identifier[0]) {
				name = IFACE_(item->name);
				icon = item->icon;
				break;
			}
			item++;
		}

		uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon);
	}

	/* Draw type */
	uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);

	if (obedit == NULL && is_paint) {
		if (ob->mode & OB_MODE_ALL_PAINT) {
			/* Only for Weight Paint. makes no sense in other paint modes. */
			row = uiLayoutRow(layout, true);
			uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
		}

		/* Manipulators aren't used in paint modes */
		if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
			/* masks aren't used for sculpt and particle painting */
			PointerRNA meshptr;

			RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr);
			if (ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT)) {
				uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
			}
			else {
				row = uiLayoutRow(layout, true);
				uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
				uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
			}
		}
	}
	else {
		row = uiLayoutRow(layout, true);
		uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);

		/* pose/object only however we want to allow in weight paint mode too
		 * so don't be totally strict and just check not-editmode for now 
		 * XXX We never get here when we are in Weight Paint mode
		 */
		if (obedit == NULL) {
			uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
		}

		/* Transform widget / manipulators */
		row = uiLayoutRow(layout, true);
		uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
		if (v3d->twflag & V3D_USE_MANIPULATOR) {
			uiItemR(row, &v3dptr, "transform_manipulators", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
		}
		uiItemR(row, &v3dptr, "transform_orientation", 0, "", ICON_NONE);
	}

	if (obedit == NULL && v3d->localvd == NULL) {
		unsigned int ob_lay = ob ? ob->lay : 0;

		/* Layers */
		uiTemplateLayers(layout, v3d->scenelock ? &sceneptr : &v3dptr, "layers", &v3dptr, "layers_used", ob_lay);

		/* Scene lock */
		uiItemR(layout, &v3dptr, "lock_camera_and_layers", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
	}
	
	uiTemplateEditModeSelection(layout, C);
}
Esempio n. 11
0
/* driver settings for active F-Curve (only for 'Drivers' mode) */
static void graph_panel_drivers(const bContext *C, Panel *pa)
{
	bAnimListElem *ale;
	FCurve *fcu;
	ChannelDriver *driver;
	DriverVar *dvar;
	
	PointerRNA driver_ptr;
	uiLayout *col;
	uiBlock *block;
	uiBut *but;
	
	/* Get settings from context */
	if (!graph_panel_context(C, &ale, &fcu))
		return;
	driver = fcu->driver;
	
	/* set event handler for panel */
	block = uiLayoutGetBlock(pa->layout); // xxx?
	UI_block_func_handle_set(block, do_graph_region_driver_buttons, NULL);
	
	/* general actions - management */
	col = uiLayoutColumn(pa->layout, false);
	block = uiLayoutGetBlock(col);
	but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"),
	               0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
	               NULL, 0.0, 0.0, 0, 0,
	               TIP_("Force updates of dependencies"));
	UI_but_func_set(but, driver_update_flags_cb, fcu, NULL);

	but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMOUT, IFACE_("Remove Driver"),
	               0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
	               NULL, 0.0, 0.0, 0, 0,
	               TIP_("Remove this driver"));
	UI_but_funcN_set(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
		
	/* driver-level settings - type, expressions, and errors */
	RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
	
	col = uiLayoutColumn(pa->layout, true);
	block = uiLayoutGetBlock(col);
	uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);

	/* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */
	if (driver->type == DRIVER_TYPE_PYTHON) {
		bool bpy_data_expr_error = (strstr(driver->expression, "bpy.data.") != NULL);
		bool bpy_ctx_expr_error  = (strstr(driver->expression, "bpy.context.") != NULL);
		
		/* expression */
		uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
		
		/* errors? */
		if ((G.f & G_SCRIPT_AUTOEXEC) == 0) {
			uiItemL(col, IFACE_("ERROR: Python auto-execution disabled"), ICON_CANCEL);
		}
		else if (driver->flag & DRIVER_FLAG_INVALID) {
			uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_CANCEL);
		}
		
		/* Explicit bpy-references are evil. Warn about these to prevent errors */
		/* TODO: put these in a box? */
		if (bpy_data_expr_error || bpy_ctx_expr_error) {
			uiItemL(col, IFACE_("WARNING: Driver expression may not work correctly"), ICON_HELP);
			
			if (bpy_data_expr_error) {
				uiItemL(col, IFACE_("TIP: Use variables instead of bpy.data paths (see below)"), ICON_ERROR);
			}
			if (bpy_ctx_expr_error) {
				uiItemL(col, IFACE_("TIP: bpy.context is not safe for renderfarm usage"), ICON_ERROR);
			}
		}
	}
	else {
		/* errors? */
		if (driver->flag & DRIVER_FLAG_INVALID)
			uiItemL(col, IFACE_("ERROR: Invalid target channel(s)"), ICON_ERROR);
			
		/* Warnings about a lack of variables
		 * NOTE: The lack of variables is generally a bad thing, since it indicates
		 *       that the driver doesn't work at all. This particular scenario arises
		 *       primarily when users mistakenly try to use drivers for procedural
		 *       property animation
		 */
		if (BLI_listbase_is_empty(&driver->variables)) {
			uiItemL(col, IFACE_("ERROR: Driver is useless without any inputs"), ICON_ERROR);
			
			if (!BLI_listbase_is_empty(&fcu->modifiers)) {
				uiItemL(col, IFACE_("TIP: Use F-Curves for procedural animation instead"), ICON_INFO);
				uiItemL(col, IFACE_("F-Modifiers can generate curves for those too"), ICON_INFO);
			}
		}
	}
		
	col = uiLayoutColumn(pa->layout, true);

	if (driver->type == DRIVER_TYPE_PYTHON) {
		uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
	}

	/* debug setting */
	uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE);
		
	/* value of driver */
	if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
		uiLayout *row = uiLayoutRow(col, true);
		char valBuf[32];
			
		uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
			
		BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
		uiItemL(row, valBuf, ICON_NONE);
	}
	
	/* add/copy/paste driver variables */
	{
		uiLayout *row;
		
		/* add driver variable */
		row = uiLayoutRow(pa->layout, false);
		block = uiLayoutGetBlock(row);
		but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
	                           0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
	                           NULL, 0.0, 0.0, 0, 0,
	                           TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
		UI_but_func_set(but, driver_add_var_cb, driver, NULL);
		
		/* copy/paste (as sub-row) */
		row = uiLayoutRow(row, true);
		block = uiLayoutGetBlock(row);
		
		uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy");
		uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste");
	}
	
	/* loop over targets, drawing them */
	for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
		PointerRNA dvar_ptr;
		uiLayout *box, *row;
		uiLayout *subrow, *sub;
		
		/* sub-layout column for this variable's settings */
		col = uiLayoutColumn(pa->layout, true);
		
		/* 1) header panel */
		box = uiLayoutBox(col);
		RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
		
		row = uiLayoutRow(box, false);
		block = uiLayoutGetBlock(row);
		
		/* 1.1) variable type and name */
		subrow = uiLayoutRow(row, true);
		
		/* 1.1.1) variable type */
		sub = uiLayoutRow(subrow, true);                     /* HACK: special group just for the enum, otherwise we */
		uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);  /*       we get ugly layout with text included too...  */
		
		uiItemR(sub, &dvar_ptr, "type", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
		
		/* 1.1.2) variable name */
		sub = uiLayoutRow(subrow, true);                       /* HACK: special group to counteract the effects of the previous */
		uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_EXPAND);  /*       enum, which now pushes everything too far right         */
		
		uiItemR(sub, &dvar_ptr, "name", 0, "", ICON_NONE);
		
		/* 1.2) invalid name? */
		UI_block_emboss_set(block, UI_EMBOSS_NONE);
		
		if (dvar->flag & DVAR_FLAG_INVALID_NAME) {
			but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ERROR, 290, 0, UI_UNIT_X, UI_UNIT_Y,
			                   NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Invalid variable name, click here for details"));
			UI_but_func_set(but, driver_dvar_invalid_name_query_cb, dvar, NULL); // XXX: reports?
		}
		
		/* 1.3) remove button */
		but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
		                   NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
		UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
		UI_block_emboss_set(block, UI_EMBOSS);
		
		
		/* 2) variable type settings */
		box = uiLayoutBox(col);
		/* controls to draw depends on the type of variable */
		switch (dvar->type) {
			case DVAR_TYPE_SINGLE_PROP:     /* single property */
				graph_panel_driverVar__singleProp(box, ale->id, dvar);
				break;
			case DVAR_TYPE_ROT_DIFF:     /* rotational difference */
				graph_panel_driverVar__rotDiff(box, ale->id, dvar);
				break;
			case DVAR_TYPE_LOC_DIFF:     /* location difference */
				graph_panel_driverVar__locDiff(box, ale->id, dvar);
				break;
			case DVAR_TYPE_TRANSFORM_CHAN:     /* transform channel */
				graph_panel_driverVar__transChan(box, ale->id, dvar);
				break;
		}
		
		/* 3) value of variable */
		if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
			char valBuf[32];
			
			box = uiLayoutBox(col);
			row = uiLayoutRow(box, true);
			uiItemL(row, IFACE_("Value:"), ICON_NONE);
			
			if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
			    (dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
			     dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
			     dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX))
			{
				BLI_snprintf(valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
			}
			else {
				BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
			}
			
			uiItemL(row, valBuf, ICON_NONE);
		}
	}
	
	/* cleanup */
	MEM_freeN(ale);
}