2.5: Added basic insert/remove keyframes from UI buttons.

- I key over a button inserts a keyframe.
- Alt+I removes a keyframe.
- With right mouse button a menu with these options pops up.
- Buttons are colored green if the property is animated, yellow
  if it is on a keyframe. I followed the colors from the UI
  mockups, but the flicker on keyframes seems too distracting in
  practice?

- This only works for properties on the ID itself at the moment,
  path callbacks need to be filled in for all structs but mesh
  still.
- It doesn't work when you're over a related label, that needs to
  be made to work.
- I made it insert keyframes outside of any keyingset. Not sure
  how this is supposed to integrate?
This commit is contained in:
2009-04-03 23:30:32 +00:00
parent 30568b9e4e
commit 3906a62cc1
14 changed files with 382 additions and 12 deletions

View File

@@ -116,6 +116,9 @@ void copy_fcurves(ListBase *dst, ListBase *src);
/* find matching F-Curve in the given list of F-Curves */
struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
/* test if there is a keyframe at cfra */
int on_keyframe_fcurve(struct FCurve *fcu, float cfra);
/* get the time extents for F-Curve */
void calc_fcurve_range(struct FCurve *fcu, float *min, float *max);

View File

@@ -171,6 +171,19 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array
return NULL;
}
int on_keyframe_fcurve(FCurve *fcu, float cfra)
{
BezTriple *bezt;
int i;
bezt= fcu->bezt;
for (i=0; i<fcu->totvert; i++, bezt++)
if(IS_EQ(bezt->vec[1][0], cfra))
return 1;
return 0;
}
/* Calculate the extents of F-Curve's data */
void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax)
{

View File

@@ -382,6 +382,8 @@ void ED_operatortypes_anim(void)
WM_operatortype_append(ANIM_OT_delete_keyframe);
WM_operatortype_append(ANIM_OT_insert_keyframe_menu);
//WM_operatortype_append(ANIM_OT_delete_keyframe_menu);
WM_operatortype_append(ANIM_OT_insert_keyframe_button);
WM_operatortype_append(ANIM_OT_delete_keyframe_button);
WM_operatortype_append(ANIM_OT_delete_keyframe_old); // xxx remove?
WM_operatortype_append(ANIM_OT_keyingset_add_new);

View File

@@ -2367,6 +2367,134 @@ void ANIM_OT_delete_keyframe_old (wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* Insert Key Button Operator ------------------------ */
static int insert_key_button_exec (bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
PointerRNA ptr;
PropertyRNA *prop;
char *path;
float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success= 0;
int a, index, length, all= RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
uiAnimContextProperty(C, &ptr, &prop, &index);
if(ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
path= RNA_path_from_ID_to_property(&ptr, prop);
if(path) {
if(all) {
length= RNA_property_array_length(&ptr, prop);
if(length) index= 0;
else length= 1;
}
else
length= 1;
for(a=0; a<length; a++)
success+= insertkey(ptr.id.data, NULL, path, index+a, cfra, 0);
MEM_freeN(path);
}
}
if(success) {
/* send updates */
ED_anim_dag_flush_update(C);
/* for now, only send ND_KEYS for KeyingSets */
WM_event_add_notifier(C, ND_KEYS, NULL);
}
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
}
void ANIM_OT_insert_keyframe_button (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Insert Keyframe";
ot->idname= "ANIM_OT_insert_keyframe_button";
/* callbacks */
ot->exec= insert_key_button_exec;
ot->poll= modify_key_op_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array.");
}
/* Delete Key Button Operator ------------------------ */
static int delete_key_button_exec (bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
PointerRNA ptr;
PropertyRNA *prop;
char *path;
float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success= 0;
int a, index, length, all= RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
uiAnimContextProperty(C, &ptr, &prop, &index);
if(ptr.data && prop) {
path= RNA_path_from_ID_to_property(&ptr, prop);
if(path) {
if(all) {
length= RNA_property_array_length(&ptr, prop);
if(length) index= 0;
else length= 1;
}
else
length= 1;
for(a=0; a<length; a++)
success+= deletekey(ptr.id.data, NULL, path, index+a, cfra, 0);
MEM_freeN(path);
}
}
if(success) {
/* send updates */
ED_anim_dag_flush_update(C);
/* for now, only send ND_KEYS for KeyingSets */
WM_event_add_notifier(C, ND_KEYS, NULL);
}
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
}
void ANIM_OT_delete_keyframe_button (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete Keyframe";
ot->idname= "ANIM_OT_delete_keyframe_button";
/* callbacks */
ot->exec= delete_key_button_exec;
ot->poll= modify_key_op_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyfames from all elements of the array.");
}
/* ******************************************* */
/* KEYFRAME DETECTION */

View File

@@ -94,6 +94,11 @@ void ANIM_OT_insert_keyframe_menu(struct wmOperatorType *ot);
void ANIM_OT_delete_keyframe_menu(struct wmOperatorType *ot); // xxx unimplemented yet
void ANIM_OT_delete_keyframe_old(struct wmOperatorType *ot); // xxx rename and keep?
/* Keyframe managment operators for UI buttons. */
void ANIM_OT_insert_keyframe_button(struct wmOperatorType *ot);
void ANIM_OT_delete_keyframe_button(struct wmOperatorType *ot);
/* ************ Auto-Keyframing ********************** */
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)

View File

@@ -131,6 +131,8 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
#define UI_BUT_DISABLED (1<<18)
/* dont draw hilite on mouse over */
#define UI_NO_HILITE (1<<19)
#define UI_BUT_ANIMATED (1<<20)
#define UI_BUT_ANIMATED_KEY (1<<21)
/* Button types, bits stored in 1 value... and a short even!
- bits 0-4: bitnr (0-31)
@@ -626,5 +628,9 @@ typedef void (*uiPanelCreateFunc)(const struct bContext *C, uiLayout *layout);
void uiRegionPanelLayout(const struct bContext *C, struct ARegion *ar, int vertical, char *context);
void uiRegionHeaderLayout(const struct bContext *C, struct ARegion *ar);
/* Animation */
void uiAnimContextProperty(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
#endif /* UI_INTERFACE_H */

View File

@@ -33,6 +33,7 @@
#include "DNA_ID.h"
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_userdef_types.h"
@@ -591,6 +592,7 @@ void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
void uiEndBlock(const bContext *C, uiBlock *block)
{
uiBut *but;
Scene *scene= CTX_data_scene(C);
/* inherit flags from 'old' buttons that was drawn here previous, based
* on matching buttons, we need this to make button event handling non
@@ -612,6 +614,8 @@ void uiEndBlock(const bContext *C, uiBlock *block)
/* only update soft range while not editing */
if(but->rnaprop && !(but->editval || but->editstr || but->editvec))
ui_set_but_soft_range(but, ui_get_but_val(but));
ui_but_anim_flag(but, (scene)? scene->r.cfra: 0.0f);
}
if(block->oldblock) {

View File

@@ -0,0 +1,121 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BLI_listbase.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "RNA_access.h"
#include "RNA_types.h"
#include "UI_interface.h"
#include "WM_api.h"
#include "WM_types.h"
#include "interface_intern.h"
void ui_but_anim_flag(uiBut *but, float cfra)
{
but->flag &= ~(UI_BUT_ANIMATED|UI_BUT_ANIMATED_KEY);
if(but->rnaprop && but->rnapoin.id.data) {
AnimData *adt= BKE_animdata_from_id(but->rnapoin.id.data);
FCurve *fcu;
char *path;
if(adt && adt->action && adt->action->curves.first) {
/* XXX this function call can become a performance bottleneck */
path= RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
if(path) {
fcu= list_find_fcurve(&adt->action->curves, path, but->rnaindex);
if(fcu) {
but->flag |= UI_BUT_ANIMATED;
if(on_keyframe_fcurve(fcu, cfra))
but->flag |= UI_BUT_ANIMATED_KEY;
}
MEM_freeN(path);
}
}
}
}
void uiAnimContextProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
{
ARegion *ar= CTX_wm_region(C);
uiBlock *block;
uiBut *but;
if(ar) {
for(block=ar->uiblocks.first; block; block=block->next) {
for(but=block->buttons.first; but; but= but->next) {
if(but->active && but->rnapoin.id.data) {
*ptr= but->rnapoin;
*prop= but->rnaprop;
*index= but->rnaindex;
return;
}
}
}
}
}
void ui_but_anim_insert_keyframe(bContext *C)
{
/* this operator calls uiAnimContextProperty above */
WM_operator_name_call(C, "ANIM_OT_insert_keyframe_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_delete_keyframe(bContext *C)
{
/* this operator calls uiAnimContextProperty above */
WM_operator_name_call(C, "ANIM_OT_delete_keyframe_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_menu(bContext *C, uiBut *but)
{
uiMenuItem *head;
int length;
if(but->rnapoin.data && but->rnaprop) {
head= uiPupMenuBegin(RNA_property_ui_name(&but->rnapoin, but->rnaprop), 0);
length= RNA_property_array_length(&but->rnapoin, but->rnaprop);
if(but->flag & UI_BUT_ANIMATED_KEY) {
if(length) {
uiMenuItemBooleanO(head, "Delete Keyframes", 0, "ANIM_OT_delete_keyframe_button", "all", 1);
uiMenuItemBooleanO(head, "Delete Single Keyframe", 0, "ANIM_OT_delete_keyframe_button", "all", 0);
}
else {
uiMenuItemBooleanO(head, "Delete Keyframe", 0, "ANIM_OT_delete_keyframe_button", "all", 0);
}
}
else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
if(length) {
uiMenuItemBooleanO(head, "Insert Keyframes", 0, "ANIM_OT_insert_keyframe_button", "all", 1);
uiMenuItemBooleanO(head, "Insert Single Keyframe", 0, "ANIM_OT_insert_keyframe_button", "all", 0);
}
else {
uiMenuItemBooleanO(head, "Insert Keyframe", 0, "ANIM_OT_insert_keyframe_button", "all", 0);
}
}
uiPupMenuEnd(C, head);
}
}

View File

@@ -2593,12 +2593,28 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
if(but->flag & UI_BUT_DISABLED)
return WM_UI_HANDLER_BREAK;
/* handle copy-paste */
if(data->state == BUTTON_STATE_HIGHLIGHT) {
/* handle copy-paste */
if(ELEM(event->type, CKEY, VKEY) && event->val==KM_PRESS && (event->ctrl || event->oskey)) {
ui_but_copy_paste(C, but, data, (event->type == CKEY)? 'c': 'v');
return WM_UI_HANDLER_BREAK;
}
/* handle keyframeing */
else if(event->type == IKEY && event->val == KM_PRESS) {
if(event->alt)
ui_but_anim_delete_keyframe(C);
else
ui_but_anim_insert_keyframe(C);
ED_region_tag_redraw(CTX_wm_region(C));
return WM_UI_HANDLER_BREAK;
}
/* handle menu */
else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) {
ui_but_anim_menu(C, but);
return WM_UI_HANDLER_BREAK;
}
}
/* verify if we can edit this button */

View File

@@ -350,5 +350,11 @@ extern void ui_button_active_cancel(const struct bContext *C, uiBut *but);
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
void ui_draw_menu_back(uiBlock *block);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
void ui_but_anim_insert_keyframe(struct bContext *C);
void ui_but_anim_delete_keyframe(struct bContext *C);
void ui_but_anim_menu(struct bContext *C, uiBut *but);
#endif

View File

@@ -910,7 +910,7 @@ void uiLayoutEnd(const bContext *C, uiBlock *block, uiLayout *layout, int *x, in
ui_layout_free(layout);
}
/* Utilities */
/************************ Utilities ************************/
void uiRegionPanelLayout(const bContext *C, ARegion *ar, int vertical, char *context)
{

View File

@@ -115,12 +115,9 @@ static int panels_re_align(ScrArea *sa, ARegion *ar)
if(sa->spacetype==SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
SpaceButs *sbuts= sa->spacedata.first;
if(sbuts->align) {
if(sbuts->re_align || sbuts->mainbo!=sbuts->mainb || sbuts->tabo!=sbuts->tab[sbuts->mainb]) {
sbuts->re_align= 0;
if(sbuts->align)
if(sbuts->re_align || sbuts->mainbo!=sbuts->mainb || sbuts->tabo!=sbuts->tab[sbuts->mainb])
return 1;
}
}
return 0;
}

View File

@@ -91,6 +91,10 @@ typedef struct uiWidgetColors {
float outline[3];
float inner[4];
float inner_sel[4];
float inner_anim[4];
float inner_anim_sel[4];
float inner_key[4];
float inner_key_sel[4];
float item[3];
float text[3];
float text_sel[3];
@@ -805,8 +809,12 @@ static void widget_draw_text_icon(uiBut *but, rcti *rect, float *col)
/*
float outline[3];
float inner[3];
float inner_sel[3];
float inner[4];
float inner_sel[4];
float inner_anim[4];
float inner_anim_sel[4];
float inner_key[4];
float inner_key_sel[4];
float item[3];
float text[3];
float text_sel[3];
@@ -819,6 +827,10 @@ static struct uiWidgetColors wcol_num= {
{0.1f, 0.1f, 0.1f},
{0.7f, 0.7f, 0.7f, 1.0f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{0.35f, 0.35f, 0.35f},
{0.0f, 0.0f, 0.0f},
@@ -832,6 +844,10 @@ static struct uiWidgetColors wcol_numslider= {
{0.1f, 0.1f, 0.1f},
{0.7f, 0.7f, 0.7f, 1.0f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{0.5f, 0.5f, 0.5f},
{0.0f, 0.0f, 0.0f},
@@ -845,6 +861,10 @@ static struct uiWidgetColors wcol_text= {
{0.1f, 0.1f, 0.1f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{0.35f, 0.35f, 0.35f},
{0.0f, 0.0f, 0.0f},
@@ -858,6 +878,10 @@ static struct uiWidgetColors wcol_option= {
{0.0f, 0.0f, 0.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 0.0f},
@@ -872,6 +896,10 @@ static struct uiWidgetColors wcol_menu= {
{0.0f, 0.0f, 0.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
@@ -886,6 +914,10 @@ static struct uiWidgetColors wcol_pulldown= {
{0.0f, 0.0f, 0.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.18f, 0.48f, 0.85f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
@@ -900,6 +932,10 @@ static struct uiWidgetColors wcol_menu_item= {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.3},
{0.23f, 0.53f, 0.9f, 0.9f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
@@ -914,6 +950,10 @@ static struct uiWidgetColors wcol_menu_back= {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.6},
{0.18f, 0.48f, 0.85f, 0.8f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
@@ -928,6 +968,10 @@ static struct uiWidgetColors wcol_radio= {
{0.0f, 0.0f, 0.0f},
{0.25f, 0.25f, 0.25f, 1.0f},
{0.34f, 0.5f, 0.76f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
@@ -941,6 +985,10 @@ static struct uiWidgetColors wcol_regular= {
{0.1f, 0.1f, 0.1f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.4f, 0.4f, 0.4f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{0.1f, 0.1f, 0.1f},
{0.0f, 0.0f, 0.0f},
@@ -954,6 +1002,10 @@ static struct uiWidgetColors wcol_regular_shade= {
{0.1f, 0.1f, 0.1f},
{0.6f, 0.6f, 0.6f, 1.0f},
{0.4f, 0.4f, 0.4f, 1.0f},
{0.45, 0.75, 0.3f, 1.0f},
{0.35, 0.65, 0.2f, 1.0f},
{0.95, 0.9, 0.4f, 1.0f},
{0.85, 0.8, 0.3f, 1.0f},
{0.1f, 0.1f, 0.1f},
{0.0f, 0.0f, 0.0f},
@@ -971,7 +1023,13 @@ static void widget_state(uiWidgetType *wt, int state)
wt->wcol= *(wt->wcol_theme);
if(state & UI_SELECT) {
QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
if(state & UI_BUT_ANIMATED_KEY)
QUATCOPY(wt->wcol.inner, wt->wcol.inner_key_sel)
else if(state & UI_BUT_ANIMATED)
QUATCOPY(wt->wcol.inner, wt->wcol.inner_anim_sel)
else
QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel)
VECCOPY(wt->wcol.text, wt->wcol.text_sel);
/* only flip shade if it's not "pushed in" already */
@@ -979,8 +1037,15 @@ static void widget_state(uiWidgetType *wt, int state)
SWAP(float, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
else if(state & UI_ACTIVE) /* mouse over? */
VecMulf(wt->wcol.inner, 1.1f);
else {
if(state & UI_BUT_ANIMATED_KEY)
QUATCOPY(wt->wcol.inner, wt->wcol.inner_key)
else if(state & UI_BUT_ANIMATED)
QUATCOPY(wt->wcol.inner, wt->wcol.inner_anim)
if(state & UI_ACTIVE) /* mouse over? */
VecMulf(wt->wcol.inner, 1.1f);
}
}
/* special case, button that calls pulldown */

View File

@@ -197,6 +197,10 @@ static void buttons_main_area_draw(const bContext *C, ARegion *ar)
/* scrollers? */
}
sbuts->re_align= 0;
sbuts->mainbo= sbuts->mainb;
sbuts->tabo= sbuts->tab[sbuts->mainb];
}
void buttons_operatortypes(void)