diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-06-16 15:48:21 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-06-16 17:28:42 +0300 |
commit | d8c2c63c005b686c7489b06b889cd30cf9eeea9c (patch) | |
tree | d713b53a32d691537042fd16a1c61ea46388f1a1 /source | |
parent | 8f2acda7d72da9370f7ec3013026fadb0842cb54 (diff) |
UI: Add property decorator buttons
When use_property_split is enabled, this template adds
buttons to set keyframes, (Alternative to showing color).
See: T54951
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 4 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_anim.c | 49 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_layout.c | 91 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_ui.c | 13 |
5 files changed, 155 insertions, 3 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 876a382bb7c..0b4817c8049 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -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__ */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index fc0ad7e5dce..6a0dfcb5353 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -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); +} diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 1013f39faba..15e04c5a2c7 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -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); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index ac7bbb12912..b837062671b 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -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; diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 8083ae35dc1..70aa4709d8c 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -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) |