diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h index 37f2f4f051d..3ea5dfba65c 100644 --- a/source/blender/editors/include/ED_screen_types.h +++ b/source/blender/editors/include/ED_screen_types.h @@ -33,6 +33,7 @@ typedef struct ScreenAnimData { ARegion *ar; /* do not read from this, only for comparing if region exists */ int redraws; + int reverse; } ScreenAnimData; diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 4e08310240c..6da00f12a25 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1460,7 +1460,9 @@ void ED_screen_full_prevspace(bContext *C) ed_screen_fullarea(C, sa); } -/* redraws: uses defines from stime->redraws */ +/* redraws: uses defines from stime->redraws + * enable: 1 - forward on, -1 - backwards on, 0 - off + */ void ED_screen_animation_timer(bContext *C, int redraws, int enable) { bScreen *screen= CTX_wm_screen(C); @@ -1477,6 +1479,7 @@ void ED_screen_animation_timer(bContext *C, int redraws, int enable) screen->animtimer= WM_event_add_window_timer(win, TIMER0, (1.0/FPS)); sad->ar= CTX_wm_region(C); sad->redraws= redraws; + sad->reverse= (enable < 0); screen->animtimer->customdata= sad; } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 5bf090e459b..80526dbdb6e 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2067,19 +2067,40 @@ static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event) if(scene->audio.flag & AUDIO_SYNC) { int step = floor(wt->duration * FPS); - scene->r.cfra += step; + if (sad->reverse) // XXX does this option work with audio? + scene->r.cfra -= step; + else + scene->r.cfra += step; wt->duration -= ((float)step)/FPS; } - else - scene->r.cfra++; + else { + if (sad->reverse) + scene->r.cfra--; + else + scene->r.cfra++; + } - if (scene->r.psfra) { - if(scene->r.cfra > scene->r.pefra) - scene->r.cfra= scene->r.psfra; + if (sad->reverse) { + /* jump back to end */ + if (scene->r.psfra) { + if(scene->r.cfra < scene->r.psfra) + scene->r.cfra= scene->r.pefra; + } + else { + if(scene->r.cfra < scene->r.sfra) + scene->r.cfra= scene->r.efra; + } } else { - if(scene->r.cfra > scene->r.efra) - scene->r.cfra= scene->r.sfra; + /* jump back to start */ + if (scene->r.psfra) { + if(scene->r.cfra > scene->r.pefra) + scene->r.cfra= scene->r.psfra; + } + else { + if(scene->r.cfra > scene->r.efra) + scene->r.cfra= scene->r.sfra; + } } /* since we follow drawflags, we can't send notifier but tag regions ourselves */ @@ -2127,8 +2148,9 @@ static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event) ED_screen_animation_timer(C, 0, 0); } else { - /* todo: RNA properties to define play types */ - ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1); + int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1; + + ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode); if(screen->animtimer) { wmTimer *wt= screen->animtimer; @@ -2152,7 +2174,7 @@ void SCREEN_OT_animation_play(wmOperatorType *ot) ot->poll= ED_operator_screenactive; - + RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards"); } /* ************** border select operator (template) ***************************** */ diff --git a/source/blender/editors/space_time/time_header.c b/source/blender/editors/space_time/time_header.c index da99849e594..9ffce53e572 100644 --- a/source/blender/editors/space_time/time_header.c +++ b/source/blender/editors/space_time/time_header.c @@ -373,6 +373,7 @@ static uiBlock *time_framemenu(bContext *C, ARegion *ar, void *arg_unused) #define B_REDRAWALL 750 #define B_TL_REW 751 #define B_TL_PLAY 752 +#define B_TL_RPLAY 760 #define B_TL_FF 753 #define B_TL_PREVKEY 754 #define B_TL_NEXTKEY 755 @@ -415,6 +416,18 @@ void do_time_buttons(bContext *C, void *arg, int event) sad->ar= time_top_left_3dwindow(screen); } + break; + case B_TL_RPLAY: + ED_screen_animation_timer(C, stime->redraws, -1); + + /* update region if TIME_REGION was set, to leftmost 3d window */ + if(screen->animtimer && (stime->redraws & TIME_REGION)) { + wmTimer *wt= screen->animtimer; + ScreenAnimData *sad= wt->customdata; + + sad->ar= time_top_left_3dwindow(screen); + } + break; case B_TL_STOP: ED_screen_animation_timer(C, 0, 0); @@ -553,14 +566,27 @@ void time_header_buttons(const bContext *C, ARegion *ar) xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Skip to previous keyframe (Ctrl PageDown)"); xco+= XIC+4; - if(CTX_wm_screen(C)->animtimer) + if(CTX_wm_screen(C)->animtimer) { + /* pause button is drawn centered between the two other buttons for now (saves drawing 2 buttons, or having position changes) */ + xco+= XIC/2 + 2; + uiDefIconBut(block, BUT, B_TL_STOP, ICON_PAUSE, xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Stop Playing Timeline"); - else + + xco+= XIC/2 + 2; + } + else { + // FIXME: the icon for this is crap + uiDefIconBut(block, BUT, B_TL_RPLAY, ICON_REW/*ICON_PLAY*/, + xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Play Timeline in Reverse"); + + xco+= XIC+4; + uiDefIconBut(block, BUT, B_TL_PLAY, ICON_PLAY, xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Play Timeline "); - + } xco+= XIC+4; + uiDefIconBut(block, BUT, B_TL_NEXTKEY, ICON_NEXT_KEYFRAME, xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Skip to next keyframe (Ctrl PageUp)"); xco+= XIC+4;