UI: Add property decorator buttons
When use_property_split is enabled, this template adds buttons to set keyframes, (Alternative to showing color). See: T54951
This commit is contained in:
parent
8f2acda7d7
commit
d8c2c63c00
Notes:
blender-bot
2023-02-14 09:09:43 +01:00
Referenced by issue #54995, Implement Properties Editor Design
|
@ -964,6 +964,7 @@ void uiLayoutSetScaleX(uiLayout *layout, float scale);
|
|||
void uiLayoutSetScaleY(uiLayout *layout, float scale);
|
||||
void uiLayoutSetEmboss(uiLayout *layout, char emboss);
|
||||
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
|
||||
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
|
||||
|
||||
int uiLayoutGetOperatorContext(uiLayout *layout);
|
||||
bool uiLayoutGetActive(uiLayout *layout);
|
||||
|
@ -976,6 +977,7 @@ float uiLayoutGetScaleX(uiLayout *layout);
|
|||
float uiLayoutGetScaleY(uiLayout *layout);
|
||||
int uiLayoutGetEmboss(uiLayout *layout);
|
||||
bool uiLayoutGetPropSep(uiLayout *layout);
|
||||
bool uiLayoutGetPropDecorate(uiLayout *layout);
|
||||
|
||||
/* layout specifiers */
|
||||
uiLayout *uiLayoutRow(uiLayout *layout, int align);
|
||||
|
@ -1257,5 +1259,7 @@ void UI_widgetbase_draw_cache_end(void);
|
|||
#define USE_UI_POPOVER_ONCE
|
||||
|
||||
bool UI_but_is_tool(const uiBut *but);
|
||||
#define UI_but_is_decorator(but) \
|
||||
((but)->func == ui_but_anim_decorate_cb)
|
||||
|
||||
#endif /* __UI_INTERFACE_H__ */
|
||||
|
|
|
@ -101,6 +101,23 @@ void ui_but_anim_flag(uiBut *but, float cfra)
|
|||
but->flag |= UI_BUT_DRIVEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (but->next && UI_but_is_decorator(but->next)) {
|
||||
uiBut *but_decor = but->next;
|
||||
int flag = but->flag;
|
||||
if (flag & UI_BUT_DRIVEN) {
|
||||
but_decor->icon = ICON_AUTO;
|
||||
}
|
||||
else if (flag & UI_BUT_ANIMATED_KEY) {
|
||||
but_decor->icon = ICON_SPACE2;
|
||||
}
|
||||
else if (flag & UI_BUT_ANIMATED) {
|
||||
but_decor->icon = ICON_SPACE3;
|
||||
}
|
||||
else {
|
||||
but_decor->icon = ICON_DOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,3 +316,35 @@ void ui_but_anim_paste_driver(bContext *C)
|
|||
/* this operator calls UI_context_active_but_prop_get */
|
||||
WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
|
||||
{
|
||||
uiBut *but = arg_but;
|
||||
but = but->prev;
|
||||
|
||||
/* FIXME(campbell), swapping active pointer is weak. */
|
||||
SWAP(struct uiHandleButtonData *, but->active, but->next->active);
|
||||
|
||||
if (but->flag & UI_BUT_DRIVEN) {
|
||||
/* pass */
|
||||
/* TODO: report? */
|
||||
}
|
||||
else if (but->flag & UI_BUT_ANIMATED_KEY) {
|
||||
PointerRNA props_ptr;
|
||||
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
|
||||
WM_operator_properties_create_ptr(&props_ptr, ot);
|
||||
RNA_boolean_set(&props_ptr, "all", false);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
}
|
||||
else {
|
||||
PointerRNA props_ptr;
|
||||
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
|
||||
WM_operator_properties_create_ptr(&props_ptr, ot);
|
||||
RNA_boolean_set(&props_ptr, "all", false);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
}
|
||||
|
||||
SWAP(struct uiHandleButtonData *, but->active, but->next->active);
|
||||
}
|
||||
|
|
|
@ -814,6 +814,7 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
|
|||
bool ui_but_anim_expression_set(uiBut *but, const char *str);
|
||||
bool ui_but_anim_expression_create(uiBut *but, const char *str);
|
||||
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
|
||||
void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy);
|
||||
|
||||
/* interface_eyedropper.c */
|
||||
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_animsys.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
|
@ -63,6 +64,10 @@
|
|||
|
||||
#include "interface_intern.h"
|
||||
|
||||
/* Show an icon button after each RNA button to use to quickly set keyframes,
|
||||
* this is a way to display animation/driven/override status, see T54951. */
|
||||
#define UI_PROP_DECORATE
|
||||
|
||||
/************************ Structs and Defines *************************/
|
||||
|
||||
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
|
||||
|
@ -132,6 +137,9 @@ enum {
|
|||
|
||||
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
|
||||
UI_ITEM_PROP_SEP = 1 << 3,
|
||||
/* Show an icon button next to each property (to set keyframes, show status).
|
||||
* Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
|
||||
UI_ITEM_PROP_DECORATE = 1 << 4,
|
||||
};
|
||||
|
||||
typedef struct uiButtonItem {
|
||||
|
@ -1477,6 +1485,18 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
|
|||
bool is_array;
|
||||
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
|
||||
|
||||
#ifdef UI_PROP_DECORATE
|
||||
struct {
|
||||
bool use_prop_decorate;
|
||||
uiLayout *layout;
|
||||
uiBut *but;
|
||||
} ui_decorate = {
|
||||
.use_prop_decorate = (
|
||||
((layout->item.flag & UI_ITEM_PROP_DECORATE) != 0) &&
|
||||
(use_prop_sep && ptr->id.data && id_can_have_animdata(ptr->id.data))),
|
||||
};
|
||||
#endif /* UI_PROP_DECORATE */
|
||||
|
||||
UI_block_layout_set_current(block, layout);
|
||||
|
||||
/* retrieve info */
|
||||
|
@ -1558,14 +1578,24 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
|
|||
|
||||
/* Split the label / property. */
|
||||
if (use_prop_sep) {
|
||||
uiLayout *layout_row = NULL;
|
||||
#ifdef UI_PROP_DECORATE
|
||||
if (ui_decorate.use_prop_decorate) {
|
||||
layout_row = uiLayoutRow(layout, true);
|
||||
layout_row->space = 0;
|
||||
}
|
||||
#endif /* UI_PROP_DECORATE */
|
||||
|
||||
if (name[0] == '\0') {
|
||||
/* Ensure we get a column when text is not set. */
|
||||
layout = uiLayoutColumn(layout, true);
|
||||
layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
|
||||
layout->space = 0;
|
||||
}
|
||||
else {
|
||||
const PropertySubType subtype = RNA_property_subtype(prop);
|
||||
uiLayout *layout_split = uiLayoutSplit(layout, UI_ITEM_PROP_SEP_DIVIDE, true);
|
||||
uiLayout *layout_split = uiLayoutSplit(
|
||||
layout_row ? layout_row : layout,
|
||||
UI_ITEM_PROP_SEP_DIVIDE, true);
|
||||
layout_split->space = 0;
|
||||
uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
|
||||
layout_sub->space = 0;
|
||||
|
@ -1607,6 +1637,15 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
|
|||
layout->space = 0;
|
||||
name = "";
|
||||
}
|
||||
|
||||
#ifdef UI_PROP_DECORATE
|
||||
if (ui_decorate.use_prop_decorate) {
|
||||
ui_decorate.layout = uiLayoutColumn(layout_row, true);
|
||||
ui_decorate.layout->space = 0;
|
||||
UI_block_layout_set_current(block, layout);
|
||||
ui_decorate.but = block->buttons.last;
|
||||
}
|
||||
#endif /* UI_PROP_DECORATE */
|
||||
}
|
||||
/* End split. */
|
||||
|
||||
|
@ -1655,6 +1694,39 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
|
|||
UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
|
||||
}
|
||||
|
||||
#ifdef UI_PROP_DECORATE
|
||||
if (ui_decorate.use_prop_decorate) {
|
||||
const bool is_anim = RNA_property_animateable(ptr, prop);
|
||||
uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
|
||||
uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
|
||||
layout_col->space = 0;
|
||||
layout_col->emboss = UI_EMBOSS_NONE;
|
||||
int i;
|
||||
for (i = 0; but_decorate; i++) {
|
||||
/* The icons are set in 'ui_but_anim_flag' */
|
||||
if (is_anim) {
|
||||
but = uiDefIconBut(
|
||||
block, UI_BTYPE_BUT, 0, ICON_DOT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
|
||||
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Animate property"));
|
||||
UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
|
||||
}
|
||||
else {
|
||||
/* We may show other information here in future, for now use empty space. */
|
||||
but = uiDefIconBut(
|
||||
block, UI_BTYPE_BUT, 0, ICON_BLANK1, 0, 0, UI_UNIT_X, UI_UNIT_Y,
|
||||
NULL, 0.0, 0.0, 0.0, 0.0, "");
|
||||
but->flag |= UI_BUT_DISABLED;
|
||||
}
|
||||
/* Order the decorator after the button we decorate, this is used so we can always
|
||||
* do a quick lookup. */
|
||||
BLI_remlink(&block->buttons, but);
|
||||
BLI_insertlinkafter(&block->buttons, but_decorate, but);
|
||||
but_decorate = but->next;
|
||||
}
|
||||
BLI_assert(len ? i < len : i == 1);
|
||||
}
|
||||
#endif /* UI_PROP_DECORATE */
|
||||
|
||||
if (no_bg) {
|
||||
layout->emboss = prev_emboss;
|
||||
}
|
||||
|
@ -3435,7 +3507,7 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali
|
|||
litem->redalert = layout->redalert;
|
||||
litem->w = layout->w;
|
||||
litem->emboss = layout->emboss;
|
||||
litem->item.flag = (layout->item.flag & UI_ITEM_PROP_SEP);
|
||||
litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
|
||||
BLI_addtail(&layout->items, litem);
|
||||
}
|
||||
|
||||
|
@ -3700,6 +3772,16 @@ void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
|
|||
SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_SEP);
|
||||
}
|
||||
|
||||
bool uiLayoutGetPropDecorate(uiLayout *layout)
|
||||
{
|
||||
return (layout->item.flag & UI_ITEM_PROP_DECORATE) != 0;
|
||||
}
|
||||
|
||||
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
|
||||
{
|
||||
SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_DECORATE);
|
||||
}
|
||||
|
||||
bool uiLayoutGetActive(uiLayout *layout)
|
||||
{
|
||||
return layout->active;
|
||||
|
@ -4002,6 +4084,9 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s
|
|||
layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
|
||||
layout->item.type = ITEM_LAYOUT_ROOT;
|
||||
|
||||
/* Only used when 'UI_ITEM_PROP_SEP' is set. */
|
||||
layout->item.flag = UI_ITEM_PROP_DECORATE;
|
||||
|
||||
layout->x = x;
|
||||
layout->y = y;
|
||||
layout->root = root;
|
||||
|
|
|
@ -963,6 +963,16 @@ static void rna_UILayout_property_split_set(PointerRNA *ptr, int value)
|
|||
uiLayoutSetPropSep(ptr->data, value);
|
||||
}
|
||||
|
||||
static int rna_UILayout_property_decorate_get(PointerRNA *ptr)
|
||||
{
|
||||
return uiLayoutGetPropDecorate(ptr->data);
|
||||
}
|
||||
|
||||
static void rna_UILayout_property_decorate_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
uiLayoutSetPropDecorate(ptr->data, value);
|
||||
}
|
||||
|
||||
#else /* RNA_RUNTIME */
|
||||
|
||||
static void rna_def_ui_layout(BlenderRNA *brna)
|
||||
|
@ -1030,6 +1040,9 @@ static void rna_def_ui_layout(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "use_property_split", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_UILayout_property_split_get", "rna_UILayout_property_split_set");
|
||||
|
||||
prop = RNA_def_property(srna, "use_property_decorate", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_UILayout_property_decorate_get", "rna_UILayout_property_decorate_set");
|
||||
}
|
||||
|
||||
static void rna_def_panel(BlenderRNA *brna)
|
||||
|
|
Loading…
Reference in New Issue