void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
	/* button to quickly show texture in texture tab */
	SpaceButs *sbuts = CTX_wm_space_buts(C);
	ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL;
	ButsTextureUser *user;

	/* only show button in other tabs in properties editor */
	if (!ct || sbuts->mainb == BCONTEXT_TEXTURE)
		return;

	/* find corresponding texture user */
	for (user = ct->users.first; user; user = user->next)
		if (user->ptr.data == ptr->data && user->prop == prop)
			break;
	
	/* draw button */
	if (user) {
		uiBlock *block = uiLayoutGetBlock(layout);
		uiBut *but;
		
		but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
		                   NULL, 0.0, 0.0, 0.0, 0.0, "Show texture in texture tab");
		UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop);
	}
}
void buttons_context_draw(const bContext *C, uiLayout *layout)
{
	SpaceButs *sbuts = CTX_wm_space_buts(C);
	ButsContextPath *path = sbuts->path;
	uiLayout *row;
	uiBlock *block;
	uiBut *but;
	PointerRNA *ptr;
	char namebuf[128], *name;
	int a, icon;

	if (!path)
		return;

	row = uiLayoutRow(layout, true);
	uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);

	block = uiLayoutGetBlock(row);
	UI_block_emboss_set(block, UI_EMBOSS_NONE);
	but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
	                       0, 0, 0, 0, TIP_("Follow context or keep fixed datablock displayed"));
	UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
	UI_but_func_set(but, pin_cb, NULL, NULL);

	for (a = 0; a < path->len; a++) {
		ptr = &path->ptr[a];

		if (a != 0)
			uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);

		if (ptr->data) {
			icon = RNA_struct_ui_icon(ptr->type);
			name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);

			if (name) {
				if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
					uiItemLDrag(row, ptr, "", icon);  /* save some space */
				else
					uiItemLDrag(row, ptr, name, icon);

				if (name != namebuf)
					MEM_freeN(name);
			}
			else
				uiItemL(row, "", icon);
		}
	}
}
Beispiel #3
0
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
static void mat_livedb_draw_tree_element(bContext *C, uiBlock *block, ARegion *ar, SpaceLDB *slivedb, LiveDbTreeElement *te, int startx, int *starty, int *row_num)
{
    LiveDbTreeElement   *ten;
    float               ufac = UI_UNIT_X / 20.0f;
    int                 offsx = 0, active = 0;
    int                 CUR_UNIT_Y;

    if(TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY)
        CUR_UNIT_Y = UI_UNIT_Y;
    else
        CUR_UNIT_Y = MAT_LIVEDB_UI_UNIT_Y;

    *starty -= CUR_UNIT_Y;
    ++ *row_num;

    if (*starty + 2 * CUR_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) {
        int xmax = ar->v2d.cur.xmax;
        unsigned char alpha = 128;

        /* icons can be ui buts, we don't want it to overlap with material previews */
        if(TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_MATERIAL)
            xmax -= MAT_LIVEDB_UI_UNIT_Y;

        glEnable(GL_BLEND);

        if(*row_num % 2) {
            UI_ThemeColorShade(TH_BACK, 6);
            glRecti(0, *starty + 1, ar->v2d.cur.xmax, *starty + CUR_UNIT_Y - 1);
        }

        if (*te->flag & TE_SELECTED) {
            float           col[4];
            unsigned char   col_circle[4];

            UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col);
            glColor3fv(col);
            glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + CUR_UNIT_Y - 1);

            /* active circle */
            UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col_circle);
            col_circle[3] = alpha;
            glColor4ubv((GLubyte *)col_circle);

            UI_draw_roundbox_corner_set(UI_CNR_ALL);
            UI_draw_roundbox((float)startx + UI_UNIT_X - ufac,
                       (float)*starty + (TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY ? 1.0f : UI_UNIT_Y * 3),
                       (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
                       (float)*starty + CUR_UNIT_Y - 1.0f * ufac,
                       UI_UNIT_Y / 2.0f - 1.0f * ufac);
            glEnable(GL_BLEND); /* roundbox disables it */
        }

        /* start by highlighting search matches */
        if (SEARCHING_MAT_LIVEDB(slivedb) && (*te->flag & TE_SEARCHMATCH))
        {
            char col[4];
            UI_GetThemeColorType4ubv(TH_MATCH, SPACE_MAT_LIVEDB, col);
            col[3] = alpha;
            glColor4ubv((GLubyte *)col);
            glRecti(startx, *starty + 1, ar->v2d.cur.xmax, *starty + CUR_UNIT_Y - 1);
        }

        /* open/close icon, only when sublevels */
        if (te->subtree.first || (*te->flag & TE_LAZY_CLOSED)) {
            int icon_x;
            if (TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY)
                icon_x = startx;
            else
                icon_x = startx + 5 * ufac;

            if (MAT_LIVEDB_ELEM_OPEN(te, slivedb))
                UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN);
            else
                UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
        }
        offsx += UI_UNIT_X;

        /* Element type icon */
        if(TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY)
            mat_livedb_elem_draw_icon((float)startx + offsx, (float)*starty, te);
        else
            mat_livedb_elem_draw_icon((float)startx + offsx, (float)*starty + UI_UNIT_X * 3, te);

        offsx += UI_UNIT_X;

        glDisable(GL_BLEND);

        /* name */
        if (active == 1) UI_ThemeColor(TH_TEXT_HI);
        else UI_ThemeColor(TH_TEXT);

        if(TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY)
            UI_fontstyle_draw_simple(UI_FSTYLE_WIDGET, startx + offsx, *starty + 5 * ufac, te->name);
        else {
            uiBut *bt;

            UI_fontstyle_draw_simple(UI_FSTYLE_WIDGET, startx + offsx, *starty + UI_UNIT_X * 3 + 5 * ufac, te->name);
            UI_fontstyle_draw_simple(UI_FSTYLE_WIDGET, startx + offsx, *starty + UI_UNIT_X * 2 + 5 * ufac, te->nick_name);
            UI_fontstyle_draw_simple(UI_FSTYLE_WIDGET, startx + offsx, *starty + UI_UNIT_X + 5 * ufac, te->copyright);

            bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_WORLD,
                                xmax - UI_UNIT_X - 3, *starty + 1 * ufac, UI_UNIT_X, UI_UNIT_Y,
                                NULL, 0.0, 0.0, 1.0, 0.5f, "Get item");
            UI_but_func_set(bt, get_material_cb, (void*)slivedb->server_address, (void*)te->item->mat_item.id);
            UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
        }

        offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(UI_FSTYLE_WIDGET, te->name));

        /* Closed item, we draw the category-info icons */
        if (TE_GET_TYPE(te->item->type) == MAT_LDB_TREE_ITEM_TYPE_CATEGORY && !MAT_LIVEDB_ELEM_OPEN(te, slivedb)) {
            if (te->subtree.first) {
                int tempx = startx + offsx;

                /* divider */
                UI_ThemeColorShade(TH_BACK, -40);
                glRecti(tempx   - 10.0f * ufac,
                        *starty +  4.0f * ufac,
                        tempx   -  8.0f * ufac,
                        *starty + CUR_UNIT_Y - 4.0f * ufac);

                glEnable(GL_BLEND);
                glPixelTransferf(GL_ALPHA_SCALE, 0.5);

                mat_livedb_draw_content_count_icons(&te->subtree, xmax, &tempx, *starty);

                glPixelTransferf(GL_ALPHA_SCALE, 1.0);
                glDisable(GL_BLEND);
            }
        }
    }
    /* store coord and continue, we need coordinates for elements outside view too */
    te->xs   = (float)startx;
    te->ys   = (float)*starty;
    te->xend = startx + offsx;

    if (MAT_LIVEDB_ELEM_OPEN(te, slivedb)) {
        for (ten = te->subtree.first; ten; ten = ten->next)
            mat_livedb_draw_tree_element(C, block, ar, slivedb, ten, startx + UI_UNIT_X, starty, row_num);
    }
    else {
        for (ten = te->subtree.first; ten; ten = ten->next)
            mat_livedb_set_coord_tree_element(slivedb, te, startx, starty);
    }
} /* mat_livedb_draw_tree_element() */
Beispiel #4
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);
}
Beispiel #5
0
static void graph_panel_key_properties(const bContext *C, Panel *pa)
{
	bAnimListElem *ale;
	FCurve *fcu;
	BezTriple *bezt, *prevbezt;
	
	uiLayout *layout = pa->layout;
	uiLayout *col;
	uiBlock *block;

	if (!graph_panel_context(C, &ale, &fcu))
		return;
	
	block = uiLayoutGetBlock(layout);
	/* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */
	
	/* only show this info if there are keyframes to edit */
	if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
		PointerRNA bezt_ptr, id_ptr, fcu_prop_ptr;
		PropertyRNA *fcu_prop = NULL;
		uiBut *but;
		int unit = B_UNIT_NONE;
		
		/* RNA pointer to keyframe, to allow editing */
		RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr);
		
		/* get property that F-Curve affects, for some unit-conversion magic */
		RNA_id_pointer_create(ale->id, &id_ptr);
		if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &fcu_prop_ptr, &fcu_prop)) {
			/* determine the unit for this property */
			unit = RNA_SUBTYPE_UNIT(RNA_property_subtype(fcu_prop));
		}
		
		/* interpolation */
		col = uiLayoutColumn(layout, false);
		if (fcu->flag & FCURVE_DISCRETE_VALUES) {
			uiLayout *split = uiLayoutSplit(col, 0.33f, true);
			uiItemL(split, IFACE_("Interpolation:"), ICON_NONE);
			uiItemL(split, IFACE_("None for Enum/Boolean"), ICON_IPO_CONSTANT);
		}
		else {
			uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
		}
		
		/* easing type */
		if (bezt->ipo > BEZT_IPO_BEZ)
			uiItemR(col, &bezt_ptr, "easing", 0, NULL, 0);

		/* easing extra */
		switch (bezt->ipo) {
			case BEZT_IPO_BACK:
				col = uiLayoutColumn(layout, 1);
				uiItemR(col, &bezt_ptr, "back", 0, NULL, 0);
				break;
			case BEZT_IPO_ELASTIC:
				col = uiLayoutColumn(layout, 1);
				uiItemR(col, &bezt_ptr, "amplitude", 0, NULL, 0);
				uiItemR(col, &bezt_ptr, "period", 0, NULL, 0);
				break;
			default:
				break;
		}
		
		/* numerical coordinate editing 
		 *  - we use the button-versions of the calls so that we can attach special update handlers
		 *    and unit conversion magic that cannot be achieved using a purely RNA-approach
		 */
		col = uiLayoutColumn(layout, true);
		/* keyframe itself */
		{
			uiItemL(col, IFACE_("Key:"), ICON_NONE);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, IFACE_("Frame:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "co", 0, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, IFACE_("Value:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "co", 1, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
			UI_but_unit_type_set(but, unit);
		}
		
		/* previous handle - only if previous was Bezier interpolation */
		if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
			uiItemL(col, IFACE_("Left Handle:"), ICON_NONE);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
			UI_but_unit_type_set(but, unit);
			
			/* XXX: with label? */
			but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_left_type", 0, 0, 0, -1, -1, "Type of left handle");
			UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
		}
		
		/* next handle - only if current is Bezier interpolation */
		if (bezt->ipo == BEZT_IPO_BEZ) {
			/* NOTE: special update callbacks are needed on the coords here due to T39911 */
			uiItemL(col, IFACE_("Right Handle:"), ICON_NONE);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_right", 0, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
			
			but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_right", 1, 0, 0, -1, -1, NULL);
			UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
			UI_but_unit_type_set(but, unit);
			
			/* XXX: with label? */
			but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
			                &bezt_ptr, "handle_right_type", 0, 0, 0, -1, -1, "Type of right handle");
			UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
		}
	}
	else {
		if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
			/* modifiers only - so no keyframes to be active */
			uiItemL(layout, IFACE_("F-Curve only has F-Modifiers"), ICON_NONE);
			uiItemL(layout, IFACE_("See Modifiers panel below"), ICON_INFO);
		}
		else if (fcu->fpt) {
			/* samples only */
			uiItemL(layout, IFACE_("F-Curve doesn't have any keyframes as it only contains sampled points"),
			        ICON_NONE);
		}
		else
			uiItemL(layout, IFACE_("No active keyframe on F-Curve"), ICON_NONE);
	}
	
	MEM_freeN(ale);
}