diff options
author | Joshua Leung <aligorith@gmail.com> | 2009-08-24 08:31:13 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2009-08-24 08:31:13 +0400 |
commit | b33b6babbd2e5b87dcf0dee35074120cbcf5f934 (patch) | |
tree | 13da5696dcdfbf6f715b2cc7c43895b98e69e924 /source/blender/editors | |
parent | 365783cad4e4b6c2e7d554e71d3ebac4b3d1922c (diff) |
2.5 - Sliders in Animation Editors
The 'Show Sliders' option for DopeSheet and Graph Editors now works again. When this option is enabled (it is disabled by default), a slider (or combobox) is shown beside the mute/lock toggles for F-Curves. Editing the slider will result in a new keyframe being added on the current frame.
So, for all the (ex)-Maya animators out there, you can now animate in a channelbox-like way. :)
Also in this commit:
* Fixed some warnings in modifier.c from previous commits there
* Fixed some refresh problems with DopeSheet channel list (which were only obvious after adding back the sliders)
* Removed the old/unrestored and nasty slider code used in the past by the Action Editor only.
Diffstat (limited to 'source/blender/editors')
6 files changed, 119 insertions, 367 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index acf7467713b..b16420a7094 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -79,6 +79,7 @@ #include "UI_view2d.h" #include "ED_anim_api.h" +#include "ED_keyframing.h" #include "ED_keyframes_edit.h" // XXX move the select modes out of there! #include "ED_screen.h" #include "ED_space_api.h" @@ -1869,13 +1870,14 @@ void ANIM_channel_setting_set (bAnimContext *ac, bAnimListElem *ale, int setting // XXX hardcoded size of icons #define ICON_WIDTH 17 +// XXX hardcoded width of sliders +#define SLIDER_WIDTH 70 /* Draw the given channel */ // TODO: make this use UI controls for the buttons void ANIM_channel_draw (bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) { bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale); - View2D *v2d= &ac->ar->v2d; short selected, offset; float y, ymid, ytext; @@ -1970,26 +1972,6 @@ void ANIM_channel_draw (bAnimContext *ac, bAnimListElem *ale, float yminc, float offset += 3; UI_DrawString(offset, ytext, name); } - - /* step 6) draw mute+protection toggles + (sliders) ....................... */ - /* reset offset - now goes from RHS of panel */ - offset = 0; - - // TODO: we need a mechanism of drawing over (and hiding) stuff from here... - // TODO: when drawing sliders, make those draw instead of these toggles if not enough space - - if (v2d) { - /* protect... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) { - /* just skip - drawn as widget now */ - offset += ICON_WIDTH; - } - /* mute... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { - /* just skip - drawn as widget now */ - offset += ICON_WIDTH; - } - } } /* ------------------ */ @@ -2000,6 +1982,44 @@ static void achannel_setting_widget_cb(bContext *C, void *poin, void *poin2) WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL); } +/* callback for widget sliders - insert keyframes */ +static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin) +{ + ID *id= (ID *)id_poin; + FCurve *fcu= (FCurve *)fcu_poin; + + Scene *scene= CTX_data_scene(C); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + short flag=0, done=0; + float cfra; + + /* get current frame */ + // NOTE: this will do for now... + cfra= (float)CFRA; + + /* get flags for keyframing */ + if (IS_AUTOKEY_FLAG(INSERTNEEDED)) + flag |= INSERTKEY_NEEDED; + if (IS_AUTOKEY_FLAG(AUTOMATKEY)) + flag |= INSERTKEY_MATRIX; + + + /* get RNA pointer, and resolve the path */ + RNA_id_pointer_create(id, &id_ptr); + + /* try to resolve the path stored in the F-Curve */ + if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) { + /* insert a keyframe for this F-Curve */ + done= insert_keyframe_direct(ptr, prop, fcu, cfra, flag); + + if (done) + WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL); + } +} + + + /* Draw a widget for some setting */ static void draw_setting_widget (bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf, uiBlock *block, int xpos, int ypos, int setting) { @@ -2164,15 +2184,75 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b // TODO: when drawing sliders, make those draw instead of these toggles if not enough space if (v2d) { - /* protect... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) { - offset += ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax-offset, ymid, ACHANNEL_SETTING_PROTECT); + short draw_sliders = 0; + + /* check if we need to show the sliders */ + if ((ac->sa) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { + switch (ac->spacetype) { + case SPACE_ACTION: + { + SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + draw_sliders= (saction->flag & SACTION_SLIDERS); + } + break; + case SPACE_IPO: + { + SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; + draw_sliders= (sipo->flag & SIPO_SLIDERS); + } + break; + } } - /* mute... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { - offset += ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax-offset, ymid, ACHANNEL_SETTING_MUTE); + + /* check if there's enough space for the toggles if the sliders are drawn too */ + if ( !(draw_sliders) || ((v2d->mask.xmax-v2d->mask.xmin) > ACHANNEL_BUTTON_WIDTH/2) ) { + /* protect... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) { + offset += ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax-offset, ymid, ACHANNEL_SETTING_PROTECT); + } + /* mute... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { + offset += ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax-offset, ymid, ACHANNEL_SETTING_MUTE); + } + } + + /* draw slider + * - even if we can draw sliders for this view, we must also check that the channel-type supports them + * (only only F-Curves really can support them for now) + * - to make things easier, we use RNA-autobuts for this so that changes are reflected immediately, + * whereever they occurred. BUT, we don't use the layout engine, otherwise we'd get wrong alignment, + * and wouldn't be able to auto-keyframe... + * - slider should start before the toggles (if they're visible) to keep a clean line down the side + */ + if ((draw_sliders) && (ale->type == ANIMTYPE_FCURVE)) { + /* adjust offset */ + offset += SLIDER_WIDTH; + + /* need backdrop behind sliders... */ + uiBlockSetEmboss(block, UI_EMBOSS); + + if (ale->id) { /* Slider using RNA Access -------------------- */ + FCurve *fcu= (FCurve *)ale->data; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + /* get RNA pointer, and resolve the path */ + RNA_id_pointer_create(ale->id, &id_ptr); + + /* try to resolve the path */ + if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) { + uiBut *but; + + /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ + but= uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", 0, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc); + uiButSetFunc(but, achannel_setting_slider_cb, ale->id, fcu); + } + } + else { /* Special Slider for stuff without RNA Access ---------- */ + // TODO: only implement this case when we really need it... + } } } } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 394cc53dda2..ecf0bdbf285 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -93,9 +93,8 @@ int geticon_anim_blocktype(short blocktype) } /* Write into "name" buffer, the name of the property (retrieved using RNA from the curve's settings) - * WARNING: name buffer we're writing to cannot exceed 128 chars (check action_draw.c for details) + * WARNING: name buffer we're writing to cannot exceed 256 chars (check anim_channels_defines.c for details) */ -// TODO: have an extra var to indicate if prop was valid? void getname_anim_fcurve(char *name, ID *id, FCurve *fcu) { /* sanity checks */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index ba0d1900344..a55b11afe48 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2050,7 +2050,7 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int state, int rou widget_init(&wtb); /* half rounded */ - round_box_edges(&wtb, roundboxalign, rect, 4.0f); + round_box_edges(&wtb, roundboxalign, rect, 5.0f); widgetbase_draw(&wtb, wcol); } diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 4fb22064c17..4288cc10a26 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -92,306 +92,6 @@ #include "ED_screen.h" #include "ED_space_api.h" -#if 0 // XXX old includes for reference only - #include "BIF_editaction.h" - #include "BIF_editkey.h" - #include "BIF_editnla.h" - #include "BIF_drawgpencil.h" - #include "BIF_keyframing.h" - #include "BIF_language.h" - #include "BIF_space.h" - - #include "BDR_editcurve.h" - #include "BDR_gpencil.h" - - #include "BSE_drawnla.h" - #include "BSE_drawipo.h" - #include "BSE_drawview.h" - #include "BSE_editaction_types.h" - #include "BSE_editipo.h" - #include "BSE_headerbuttons.h" - #include "BSE_time.h" - #include "BSE_view.h" -#endif // XXX old defines for reference only - -/* XXX */ -extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); - -/********************************** Slider Stuff **************************** */ - -#if 0 // XXX all of this slider stuff will need a rethink! -/* sliders for shapekeys */ -static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key) -{ - int i; - char str[64]; - float x, y; - uiBlock *block; - uiBut *but; - - /* lets make the shapekey sliders */ - - /* reset the damn myortho2 or the sliders won't draw/redraw - * correctly *grumble* - */ - mywinset(curarea->win); - myortho2(-0.375f, curarea->winx-0.375f, G.v2d->cur.ymin, G.v2d->cur.ymax); - - sprintf(str, "actionbuttonswin %d", curarea->win); - block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSS); - - x = ACHANNEL_NAMEWIDTH + 1; - y = 0.0f; - - uiBlockSetEmboss(block, UI_EMBOSSN); - - if (!(G.saction->flag & SACTION_SLIDERS)) { - ACTWIDTH = ACHANNEL_NAMEWIDTH; - but=uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, - ICON_DISCLOSURE_TRI_RIGHT, - ACHANNEL_NAMEWIDTH - XIC - 5, (short)y + CHANNELHEIGHT, - XIC,YIC-2, - &(G.saction->flag), 0, 0, 0, 0, - "Show action window sliders"); - /* no hilite, the winmatrix is not correct later on... */ - uiButSetFlag(but, UI_NO_HILITE); - } - else { - but= uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, - ICON_DISCLOSURE_TRI_DOWN, - ACHANNEL_NAMEWIDTH - XIC - 5, (short)y + CHANNELHEIGHT, - XIC,YIC-2, - &(G.saction->flag), 0, 0, 0, 0, - "Hide action window sliders"); - /* no hilite, the winmatrix is not correct later on... */ - uiButSetFlag(but, UI_NO_HILITE); - - ACTWIDTH = ACHANNEL_NAMEWIDTH + SLIDERWIDTH; - - /* sliders are open so draw them */ - BIF_ThemeColor(TH_FACE); - - glRects(ACHANNEL_NAMEWIDTH, 0, ACHANNEL_NAMEWIDTH+SLIDERWIDTH, curarea->winy); - uiBlockSetEmboss(block, UI_EMBOSS); - for (i=1; i < key->totkey; i++) { - make_rvk_slider(block, ob, i, - (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys"); - - y-=CHANNELHEIGHT+CHANNELSKIP; - - /* see sliderval array in editkey.c */ - if (i >= 255) break; - } - } - uiDrawBlock(C, block); -} - -static void icu_slider_func(void *voidicu, void *voidignore) -{ - /* the callback for the icu sliders ... copies the - * value from the icu->curval into a bezier at the - * right frame on the right ipo curve (creating both the - * ipo curve and the bezier if needed). - */ - IpoCurve *icu= voidicu; - BezTriple *bezt=NULL; - float cfra, icuval; - - cfra = frame_to_float(CFRA); - if (G.saction->pin==0 && OBACT) - cfra= get_action_frame(OBACT, cfra); - - /* if the ipocurve exists, try to get a bezier - * for this frame - */ - bezt = get_bezt_icu_time(icu, &cfra, &icuval); - - /* create the bezier triple if one doesn't exist, - * otherwise modify it's value - */ - if (bezt == NULL) { - insert_vert_icu(icu, cfra, icu->curval, 0); - } - else { - bezt->vec[1][1] = icu->curval; - } - - /* make sure the Ipo's are properly processed and - * redraw as necessary - */ - sort_time_ipocurve(icu); - testhandles_ipocurve(icu); - - /* nla-update (in case this affects anything) */ - synchronize_action_strips(); - - /* do redraw pushes, and also the depsgraph flushes */ - if (OBACT->pose || ob_get_key(OBACT)) - DAG_object_flush_update(G.scene, OBACT, OB_RECALC); - else - DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB); - - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWACTION, 0); - allqueue(REDRAWNLA, 0); - allqueue(REDRAWIPO, 0); - allspace(REMAKEIPO, 0); - allqueue(REDRAWBUTSALL, 0); -} - -static void make_icu_slider(uiBlock *block, IpoCurve *icu, - int x, int y, int w, int h, char *tip) -{ - /* create a slider for the ipo-curve*/ - uiBut *but; - - if(icu == NULL) return; - - if (IS_EQ(icu->slide_max, icu->slide_min)) { - if (IS_EQ(icu->ymax, icu->ymin)) { - if (ELEM(icu->blocktype, ID_CO, ID_KE)) { - /* hack for constraints and shapekeys (and maybe a few others) */ - icu->slide_min= 0.0; - icu->slide_max= 1.0; - } - else { - icu->slide_min= -100; - icu->slide_max= 100; - } - } - else { - icu->slide_min= icu->ymin; - icu->slide_max= icu->ymax; - } - } - if (icu->slide_min >= icu->slide_max) { - SWAP(float, icu->slide_min, icu->slide_max); - } - - but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "", - x, y , w, h, - &(icu->curval), icu->slide_min, icu->slide_max, - 10, 2, tip); - - uiButSetFunc(but, icu_slider_func, icu, NULL); - - // no hilite, the winmatrix is not correct later on... - uiButSetFlag(but, UI_NO_HILITE); -} - -/* sliders for ipo-curves of active action-channel */ -static void action_icu_buts(SpaceAction *saction) -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - int filter; - void *data; - short datatype; - - char str[64]; - float x, y; - uiBlock *block; - - /* lets make the action sliders */ - - /* reset the damn myortho2 or the sliders won't draw/redraw - * correctly *grumble* - */ - mywinset(curarea->win); - myortho2(-0.375f, curarea->winx-0.375f, G.v2d->cur.ymin, G.v2d->cur.ymax); - - sprintf(str, "actionbuttonswin %d", curarea->win); - block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSS); - - x = (float)ACHANNEL_NAMEWIDTH + 1; - y = 0.0f; - - uiBlockSetEmboss(block, UI_EMBOSSN); - - if (G.saction->flag & SACTION_SLIDERS) { - /* sliders are open so draw them */ - - /* get editor data */ - data= get_action_context(&datatype); - if (data == NULL) return; - - /* build list of channels to draw */ - filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS); - actdata_filter(&act_data, filter, data, datatype); - - /* draw backdrop first */ - BIF_ThemeColor(TH_FACE); // change this color... it's ugly - glRects(ACHANNEL_NAMEWIDTH, (short)G.v2d->cur.ymin, ACHANNEL_NAMEWIDTH+SLIDERWIDTH, (short)G.v2d->cur.ymax); - - uiBlockSetEmboss(block, UI_EMBOSS); - for (ale= act_data.first; ale; ale= ale->next) { - const float yminc= y-CHANNELHEIGHT/2; - const float ymaxc= y+CHANNELHEIGHT/2; - - /* check if visible */ - if ( IN_RANGE(yminc, G.v2d->cur.ymin, G.v2d->cur.ymax) || - IN_RANGE(ymaxc, G.v2d->cur.ymin, G.v2d->cur.ymax) ) - { - /* determine what needs to be drawn */ - switch (ale->type) { - case ACTTYPE_CONCHAN: /* constraint channel */ - { - bActionChannel *achan = (bActionChannel *)ale->owner; - IpoCurve *icu = (IpoCurve *)ale->key_data; - - /* only show if owner is selected */ - if ((ale->ownertype == ACTTYPE_OBJECT) || SEL_ACHAN(achan)) { - make_icu_slider(block, icu, - (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, - "Slider to control current value of Constraint Influence"); - } - } - break; - case ACTTYPE_ICU: /* ipo-curve channel */ - { - bActionChannel *achan = (bActionChannel *)ale->owner; - IpoCurve *icu = (IpoCurve *)ale->key_data; - - /* only show if owner is selected */ - if ((ale->ownertype == ACTTYPE_OBJECT) || SEL_ACHAN(achan)) { - make_icu_slider(block, icu, - (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, - "Slider to control current value of IPO-Curve"); - } - } - break; - case ACTTYPE_SHAPEKEY: /* shapekey channel */ - { - Object *ob= (Object *)ale->id; - IpoCurve *icu= (IpoCurve *)ale->key_data; - - // TODO: only show if object is active - if (icu) { - make_icu_slider(block, icu, - (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, - "Slider to control ShapeKey"); - } - else if (ob && ale->index) { - make_rvk_slider(block, ob, ale->index, - (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys"); - } - } - break; - } - } - - /* adjust y-position for next one */ - y-=CHANNELHEIGHT+CHANNELSKIP; - } - - /* free tempolary channels */ - BLI_freelistN(&act_data); - } - uiDrawBlock(C, block); -} - -#endif // XXX all of this slider stuff will need a rethink - /* ************************************************************************* */ /* Channel List */ @@ -518,7 +218,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) adt= ANIM_nla_mapping_get(ac, NULL); /* start and end of action itself */ - // TODO: this has not had scaling applied calc_action_range(ac->data, &act_start, &act_end, 0); } @@ -550,43 +249,14 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) { + bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale); int sel=0; /* determine if any need to draw channel */ if (ale->datatype != ALE_NONE) { /* determine if channel is selected */ - switch (ale->type) { - case ANIMTYPE_SCENE: - { - Scene *sce= (Scene *)ale->data; - sel = SEL_SCEC(sce); - } - break; - case ANIMTYPE_OBJECT: - { - Base *base= (Base *)ale->data; - sel = SEL_OBJC(base); - } - break; - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)ale->data; - sel = SEL_AGRP(agrp); - } - break; - case ANIMTYPE_FCURVE: - { - FCurve *fcu = (FCurve *)ale->data; - sel = SEL_FCU(fcu); - } - break; - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - sel = SEL_GPL(gpl); - } - break; - } + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) + sel= ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { switch (ale->type) { diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 275ac4ea4c1..2977d07d845 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -243,7 +243,7 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* data */ if (ANIM_animdata_get_context(C, &ac)) { - draw_channel_names(C, &ac, saction, ar); + draw_channel_names((bContext *)C, &ac, saction, ar); } /* reset view matrix */ @@ -294,6 +294,7 @@ static void action_channel_area_listener(ARegion *ar, wmNotifier *wmn) case NC_SCENE: switch(wmn->data) { case ND_OB_ACTIVE: + case ND_FRAME: ED_region_tag_redraw(ar); break; } diff --git a/source/blender/editors/space_graph/graph_header.c b/source/blender/editors/space_graph/graph_header.c index fc02cadb475..06d48fe20f3 100644 --- a/source/blender/editors/space_graph/graph_header.c +++ b/source/blender/editors/space_graph/graph_header.c @@ -81,6 +81,8 @@ static void graph_viewmenu(bContext *C, uiLayout *layout, void *arg_unused) uiItemS(layout); uiItemR(layout, NULL, 0, &spaceptr, "show_cframe_indicator", 0); + uiItemR(layout, NULL, 0, &spaceptr, "show_sliders", 0); + uiItemR(layout, NULL, 0, &spaceptr, "automerge_keyframes", 0); if (sipo->flag & SIPO_NOHANDLES) uiItemO(layout, "Show Handles", ICON_CHECKBOX_DEHLT, "GRAPH_OT_handles_view_toggle"); @@ -88,7 +90,7 @@ static void graph_viewmenu(bContext *C, uiLayout *layout, void *arg_unused) uiItemO(layout, "Show Handles", ICON_CHECKBOX_HLT, "GRAPH_OT_handles_view_toggle"); uiItemR(layout, NULL, 0, &spaceptr, "only_selected_curves_handles", 0); - uiItemR(layout, NULL, 0, &spaceptr, "automerge_keyframes", 0); + if (sipo->flag & SIPO_DRAWTIME) uiItemO(layout, "Show Frames", 0, "ANIM_OT_time_toggle"); |