Zoom to frame options, requested by the Hwoozeberry (dutch translation)

team.

There are 3 options here:

1) Keep range (previous behaviour)
2) Seconds - allows a specified offset in seconds around current frame
3) keyframes - zoom to include a number of keyframes around the cursor

Options 2 and 3 have their own properties to tweak the behaviour and all
options can be found in User Preferences->Interface under the 2D
viewports section.

Number 3 will probably need some refinement so commiting here for the
hwoozeberry team to test first.
This commit is contained in:
Antony Riakiotakis 2015-05-13 20:30:53 +02:00
parent c86a6f3efb
commit e4c93dc7db
9 changed files with 184 additions and 21 deletions

@ -200,6 +200,11 @@ class USERPREF_PT_interface(Panel):
col.label(text="2D Viewports:")
col.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
col.prop(view, "timecode_style")
col.prop(view, "view_frame_type")
if (view.view_frame_type == 'SECONDS'):
col.prop(view, "view_frame_seconds")
elif (view.view_frame_type == 'KEYFRAMES'):
col.prop(view, "view_frame_keyframes")
row.separator()
row.separator()

@ -34,17 +34,25 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
#include "BLI_rect.h"
#include "BLI_dlrbTree.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_mask.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_keyframes_draw.h"
#include "RNA_access.h"
@ -381,4 +389,136 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag
return 1.0f;
}
static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra) {
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
Mask *mask = CTX_data_edit_mask(C);
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
ActKeyColumn *aknext, *akprev;
float cfranext, cfraprev;
bool donenext = false, doneprev = false;
int nextcount = 0, prevcount = 0;
cfranext = cfraprev = (float)(CFRA);
/* init binarytree-list for getting keyframes */
BLI_dlrbTree_init(&keys);
/* seed up dummy dopesheet context with flags to perform necessary filtering */
if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
/* only selected channels are included */
ads.filterflag |= ADS_FILTER_ONLYSEL;
}
/* populate tree with keyframe nodes */
scene_to_keylist(&ads, scene, &keys, NULL);
if (ob)
ob_to_keylist(&ads, ob, &keys, NULL);
gpencil_to_keylist(&ads, gpd, &keys);
if (mask) {
MaskLayer *masklay = BKE_mask_layer_active(mask);
mask_to_keylist(&ads, masklay, &keys);
}
/* build linked-list for searching */
BLI_dlrbTree_linkedlist_sync(&keys);
/* find matching keyframe in the right direction */
do {
aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
if (aknext) {
if (CFRA == (int)aknext->cfra) {
/* make this the new starting point for the search and ignore */
cfranext = aknext->cfra;
}
else {
/* this changes the frame, so set the frame and we're done */
if (++nextcount == U.view_frame_keyframes)
donenext = true;
}
cfranext = aknext->cfra;
}
} while ((aknext != NULL) && (donenext == false));
do {
akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
if (akprev) {
if (CFRA == (int)akprev->cfra) {
/* make this the new starting point for the search */
}
else {
/* this changes the frame, so set the frame and we're done */
if (++prevcount == U.view_frame_keyframes)
doneprev = true;
}
cfraprev = akprev->cfra;
}
} while ((akprev != NULL) && (doneprev == false));
/* free temp stuff */
BLI_dlrbTree_free(&keys);
/* any success? */
if (doneprev || donenext) {
if (doneprev)
*prevfra = cfraprev;
else
*prevfra = CFRA - (cfranext - CFRA);
if (donenext)
*nextfra = cfranext;
else
*nextfra = CFRA + (CFRA - cfraprev);
return true;
}
return false;
}
void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
float w = BLI_rctf_size_x(&ar->v2d.cur);
rctf newrct;
int nextfra, prevfra;
switch (U.view_frame_type) {
case ZOOM_FRAME_MODE_SECONDS:
newrct.xmax = scene->r.cfra + U.view_frame_seconds * FPS + 1;
newrct.xmin = scene->r.cfra - U.view_frame_seconds * FPS - 1;
newrct.ymax = ar->v2d.cur.ymax;
newrct.ymin = ar->v2d.cur.ymin;
break;
/* hardest case of all, look for all keyframes around frame and display those */
case ZOOM_FRAME_MODE_KEYFRAMES:
if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
newrct.xmax = nextfra;
newrct.xmin = prevfra;
newrct.ymax = ar->v2d.cur.ymax;
newrct.ymin = ar->v2d.cur.ymin;
break;
}
/* else drop through, keep range instead */
case ZOOM_FRAME_MODE_KEEP_RANGE:
default:
newrct.xmax = scene->r.cfra + (w / 2);
newrct.xmin = scene->r.cfra - (w / 2);
newrct.ymax = ar->v2d.cur.ymax;
newrct.ymin = ar->v2d.cur.ymin;
break;
}
UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
}
/* *************************************************** */

@ -659,6 +659,7 @@ void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
/* ************************************************* */
/* OPERATORS */

@ -233,7 +233,6 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar,
const struct rctf *cur, const int smooth_viewtx);
void UI_view2d_center_frame(struct bContext *C, int smooth_viewtx);
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#endif /* __UI_VIEW2D_H__ */

@ -1468,21 +1468,6 @@ void UI_view2d_smooth_view(
}
}
void UI_view2d_center_frame(struct bContext *C, int smooth_viewtx)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
float w = BLI_rctf_size_x(&ar->v2d.cur);
rctf newrct;
newrct.xmax = scene->r.cfra + (w / 2);
newrct.xmin = scene->r.cfra - (w / 2);
newrct.ymax = ar->v2d.cur.ymax;
newrct.ymin = ar->v2d.cur.ymin;
UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
}
/* only meant for timer usage */
static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{

@ -429,7 +429,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
{
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
UI_view2d_center_frame(C, smooth_viewtx);
ANIM_center_frame(C, smooth_viewtx);
return OPERATOR_FINISHED;
}

@ -261,7 +261,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
{
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
UI_view2d_center_frame(C, smooth_viewtx);
ANIM_center_frame(C, smooth_viewtx);
return OPERATOR_FINISHED;
}

@ -503,7 +503,10 @@ typedef struct UserDef {
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
char pad1;
char view_frame_type;
int view_frame_keyframes; /* number of keyframes to zoom around current frame */
float view_frame_seconds; /* seconds to zoom around current frame */
short scrcastfps; /* frame rate for screencast to be played back */
short scrcastwait; /* milliseconds between screencast snapshots */
@ -686,6 +689,13 @@ typedef enum eAutokey_Mode {
AUTOKEY_MODE_EDITKEYS = 5
} eAutokey_Mode;
/* Zoom to frame mode */
typedef enum eZoomFrame_Mode {
ZOOM_FRAME_MODE_KEEP_RANGE = 0,
ZOOM_FRAME_MODE_SECONDS = 1,
ZOOM_FRAME_MODE_KEYFRAMES = 2
} eZoomFrame_Mode;
/* Auto-Keying flag
* U.autokey_flag (not strictly used when autokeying only - is also used when keyframing these days)
* note: AUTOKEY_FLAG_* is used with a macro, search for lines like IS_AUTOKEY_FLAG(INSERTAVAIL)

@ -3264,6 +3264,13 @@ static void rna_def_userdef_view(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem zoom_frame_modes[] = {
{ZOOM_FRAME_MODE_KEEP_RANGE, "KEEP_RANGE", 0, "Keep Range", ""},
{ZOOM_FRAME_MODE_SECONDS, "SECONDS", 0, "Seconds", ""},
{ZOOM_FRAME_MODE_KEYFRAMES, "KEYFRAMES", 0, "Keyframes", ""},
{0, NULL, 0, NULL, NULL}
};
PropertyRNA *prop;
StructRNA *srna;
@ -3505,6 +3512,22 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "TimeCode Style",
"Format of Time Codes displayed when not displaying timing in terms of frames");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "view_frame_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, zoom_frame_modes);
RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
RNA_def_property_ui_text(prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 500);
RNA_def_property_ui_text(prop, "Zoom Keyframes",
"Keyframes around cursor that we zoom around");
prop = RNA_def_property(srna, "view_frame_seconds", PROP_FLOAT, PROP_TIME);
RNA_def_property_range(prop, 0.0, 10000.0);
RNA_def_property_ui_text(prop, "Zoom Seconds",
"Seconds around cursor that we zoom around");
}
static void rna_def_userdef_edit(BlenderRNA *brna)