UI: Animation editor scrubbing area
authorJacques Lucke <mail@jlucke.com>
Tue, 7 May 2019 13:09:14 +0000 (15:09 +0200)
committerJacques Lucke <mail@jlucke.com>
Tue, 7 May 2019 13:09:14 +0000 (15:09 +0200)
The main reason for this change is to allow setting the
active frame with the left mouse button, while still being
able to select e.g. keyframes with the same mouse button.

The solution is to introduce a new scrubbing region with
a specialized keymap. There are a couple of related todos,
that will be handled in separate commits.
Those are listed in D4654.

This solves T63193.

Differential Revision: https://developer.blender.org/D4654

Reviewers: brecht, billreynish

29 files changed:
release/datafiles/userdef/userdef_default_theme.c
release/scripts/presets/keyconfig/keymap_data/blender_default.py
release/scripts/startup/bl_ui/space_dopesheet.py
source/blender/blenloader/intern/versioning_userdef.c
source/blender/editors/animation/CMakeLists.txt
source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_scrubbing.c [new file with mode: 0644]
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_screen.h
source/blender/editors/include/ED_scrubbing.h [new file with mode: 0644]
source/blender/editors/include/UI_resources.h
source/blender/editors/include/UI_view2d.h
source/blender/editors/interface/resources.c
source/blender/editors/interface/view2d.c
source/blender/editors/screen/area.c
source/blender/editors/space_action/action_select.c
source/blender/editors/space_action/space_action.c
source/blender/editors/space_clip/space_clip.c
source/blender/editors/space_graph/space_graph.c
source/blender/editors/space_nla/nla_channels.c
source/blender/editors/space_nla/nla_draw.c
source/blender/editors/space_nla/nla_edit.c
source/blender/editors/space_nla/nla_select.c
source/blender/editors/space_nla/space_nla.c
source/blender/editors/space_sequencer/sequencer_draw.c
source/blender/editors/space_sequencer/space_sequencer.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_userdef.c

index d1e2fa8..c93e484 100644 (file)
@@ -397,7 +397,7 @@ const bTheme U_theme_default = {
        .space_graph = {
                .back = RGBA(0x42424200),
                .title = RGBA(0xffffffff),
-               .text = RGBA(0x000000ff),
+               .text = RGBA(0xa6a6a6ff),
                .text_hi = RGBA(0xffffffff),
                .header = RGBA(0x2e2e2eff),
                .header_text = RGBA(0xeeeeeeff),
@@ -427,6 +427,7 @@ const bTheme U_theme_default = {
                .vertex = RGBA(0x000000ff),
                .vertex_select = RGBA(0xff8500ff),
                .cframe = RGBA(0x5680c2ff),
+               .scrubbing_background = RGBA(0x29292999),
                .lastsel_point = RGBA(0xffffffff),
                .handle_auto = RGBA(0x909000ff),
                .handle_vect = RGBA(0x409030ff),
@@ -482,7 +483,7 @@ const bTheme U_theme_default = {
        .space_action = {
                .back = RGBA(0x42424200),
                .title = RGBA(0xeeeeeeff),
-               .text = RGBA(0x000000ff),
+               .text = RGBA(0xa6a6a6ff),
                .text_hi = RGBA(0xffffffff),
                .header = RGBA(0x424242ff),
                .header_text = RGBA(0xeeeeeeff),
@@ -513,6 +514,7 @@ const bTheme U_theme_default = {
                .strip = RGBA(0x1a151580),
                .strip_select = RGBA(0xff8c00cc),
                .cframe = RGBA(0x5680c2ff),
+               .scrubbing_background = RGBA(0x29292999),
                .ds_channel = RGBA(0x0f2c4d24),
                .ds_subchannel = RGBA(0x143e6624),
                .ds_ipoline = RGBA(0x94e575cc),
@@ -539,7 +541,7 @@ const bTheme U_theme_default = {
        .space_nla = {
                .back = RGBA(0x42424200),
                .title = RGBA(0xffffffff),
-               .text = RGBA(0x000000ff),
+               .text = RGBA(0xa6a6a6ff),
                .text_hi = RGBA(0xffffffff),
                .header = RGBA(0x424242ff),
                .header_text = RGBA(0xeeeeeeff),
@@ -566,6 +568,7 @@ const bTheme U_theme_default = {
                .strip = RGBA(0x0c0a0a80),
                .strip_select = RGBA(0xff8c00ff),
                .cframe = RGBA(0x5680c2ff),
+               .scrubbing_background = RGBA(0x29292999),
                .ds_channel = RGBA(0x5a85b2ff),
                .ds_subchannel = RGBA(0x7d98b3ff),
                .keyborder = RGBA(0x000000ff),
@@ -589,7 +592,7 @@ const bTheme U_theme_default = {
        .space_sequencer = {
                .back = RGBA(0x42424200),
                .title = RGBA(0xeeeeeeff),
-               .text = RGBA(0x000000ff),
+               .text = RGBA(0xa6a6a6ff),
                .text_hi = RGBA(0xffffffff),
                .header = RGBA(0x424242ff),
                .header_text = RGBA(0xeeeeeeff),
@@ -612,6 +615,7 @@ const bTheme U_theme_default = {
                .vertex_select = RGBA(0xff8500ff),
                .bone_pose = RGBA(0x50c8ff50),
                .cframe = RGBA(0x5680c2ff),
+               .scrubbing_background = RGBA(0x29292999),
                .vertex_size = 3,
                .outline_width = 1,
                .facedot_size = 4,
@@ -861,7 +865,7 @@ const bTheme U_theme_default = {
        .space_clip = {
                .back = RGBA(0x42424200),
                .title = RGBA(0xeeeeeeff),
-               .text = RGBA(0xe6e6e6ff),
+               .text = RGBA(0xa6a6a6ff),
                .text_hi = RGBA(0xffffffff),
                .header = RGBA(0x424242ff),
                .header_text = RGBA(0xeeeeeeff),
@@ -885,6 +889,7 @@ const bTheme U_theme_default = {
                .strip = RGBA(0x0c0a0a80),
                .strip_select = RGBA(0xff8c00ff),
                .cframe = RGBA(0x5680c2ff),
+               .scrubbing_background = RGBA(0x29292999),
                .handle_auto = RGBA(0x909000ff),
                .handle_align = RGBA(0x803060ff),
                .handle_sel_auto = RGBA(0xf0ff40ff),
index 376e27d..b0c5ec7 100644 (file)
@@ -1307,6 +1307,22 @@ def km_markers(params):
     return keymap
 
 
+def km_scrubbing(params):
+    items = []
+    keymap = (
+        "Scrubbing",
+        {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+        {"items": items},
+    )
+
+    items.extend([
+        ("anim.change_frame", {"type": "LEFTMOUSE", "value": 'PRESS'}, None),
+        ("graph.cursor_set", {"type": "LEFTMOUSE", "value": 'PRESS'}, None),
+    ])
+
+    return keymap
+
+
 def km_graph_editor_generic(_params):
     items = []
     keymap = (
@@ -6105,6 +6121,7 @@ def generate_keymaps(params=None):
         km_view3d(params),
         km_mask_editing(params),
         km_markers(params),
+        km_scrubbing(params),
         km_graph_editor_generic(params),
         km_graph_editor(params),
         km_image_generic(params),
index 70d37c9..db69a99 100644 (file)
@@ -31,7 +31,7 @@ from bpy.types import (
 # used for DopeSheet, NLA, and Graph Editors
 
 
-def dopesheet_filter(layout, context, generic_filters_only=False):
+def dopesheet_filter(layout, context):
     dopesheet = context.space_data.dopesheet
     is_nla = context.area.type == 'NLA_EDITOR'
 
@@ -44,18 +44,6 @@ def dopesheet_filter(layout, context, generic_filters_only=False):
     else:  # graph and dopesheet editors - F-Curves and drivers only
         row.prop(dopesheet, "show_only_errors", text="")
 
-    if not generic_filters_only:
-        if bpy.data.collections:
-            row = layout.row(align=True)
-            row.prop(dopesheet, "filter_collection", text="")
-
-    if not is_nla:
-        row = layout.row(align=True)
-        row.prop(dopesheet, "filter_fcurve_name", text="")
-    else:
-        row = layout.row(align=True)
-        row.prop(dopesheet, "filter_text", text="")
-
 #######################################
 # Dopesheet Filtering Popovers
 
@@ -260,9 +248,7 @@ class DOPESHEET_HT_editor_buttons(Header):
         if st.mode == 'DOPESHEET':
             dopesheet_filter(layout, context)
         elif st.mode == 'ACTION':
-            # 'generic_filters_only' limits the options to only the relevant 'generic' subset of
-            # filters which will work here and are useful (especially for character animation)
-            dopesheet_filter(layout, context, generic_filters_only=True)
+            dopesheet_filter(layout, context)
         elif st.mode == 'GPENCIL':
             row = layout.row(align=True)
             row.prop(st.dopesheet, "show_gpencil_3d_only", text="Active Only")
index 46fd58e..6638e8c 100644 (file)
@@ -120,6 +120,18 @@ static void do_versions_theme(UserDef *userdef, bTheme *btheme)
     if (btheme->space_view3d.obcenter_dia == 0) {
       btheme->space_view3d.obcenter_dia = U_theme_default.space_view3d.obcenter_dia;
     }
+
+    FROM_DEFAULT_V4_UCHAR(space_graph.text);
+    FROM_DEFAULT_V4_UCHAR(space_action.text);
+    FROM_DEFAULT_V4_UCHAR(space_nla.text);
+    FROM_DEFAULT_V4_UCHAR(space_sequencer.text);
+    FROM_DEFAULT_V4_UCHAR(space_clip.text);
+
+    FROM_DEFAULT_V4_UCHAR(space_graph.scrubbing_background);
+    FROM_DEFAULT_V4_UCHAR(space_action.scrubbing_background);
+    FROM_DEFAULT_V4_UCHAR(space_nla.scrubbing_background);
+    FROM_DEFAULT_V4_UCHAR(space_sequencer.scrubbing_background);
+    FROM_DEFAULT_V4_UCHAR(space_clip.scrubbing_background);
   }
 
 #undef FROM_DEFAULT_V4_UCHAR
index 978bd77..098c871 100644 (file)
@@ -44,6 +44,7 @@ set(SRC
   anim_markers.c
   anim_motion_paths.c
   anim_ops.c
+  anim_scrubbing.c
   drivers.c
   fmodifier_ui.c
   keyframes_draw.c
index 6d1ee08..0002511 100644 (file)
@@ -485,16 +485,10 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
 static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name)
 {
   if (name) {
-    BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE);
+    BLI_strncpy(name, IFACE_("Summary"), ANIM_CHAN_NAME_SIZE);
   }
 }
 
-// FIXME: this is really a temp icon I think
-static int acf_summary_icon(bAnimListElem *UNUSED(ale))
-{
-  return ICON_BORDERMOVE;
-}
-
 /* check if some setting exists for this channel */
 static bool acf_summary_setting_valid(bAnimContext *UNUSED(ac),
                                       bAnimListElem *UNUSED(ale),
@@ -557,7 +551,7 @@ static bAnimChannelType ACF_SUMMARY = {
 
     acf_summary_name, /* name */
     NULL,             /* name prop */
-    acf_summary_icon, /* icon */
+    NULL,             /* icon */
 
     acf_summary_setting_valid, /* has setting */
     acf_summary_setting_flag,  /* flag for setting */
index adc6ec3..9e09fc4 100644 (file)
@@ -55,6 +55,7 @@
 #include "DEG_depsgraph_build.h"
 
 #include "UI_view2d.h"
+#include "UI_interface.h"
 
 #include "ED_anim_api.h"
 #include "ED_armature.h"
@@ -2542,7 +2543,7 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm
 
   float ymax;
   if (ac->datatype == ANIMCONT_NLA) {
-    ymax = NLACHANNEL_FIRST_TOP(snla);
+    ymax = NLACHANNEL_FIRST_TOP(ac);
   }
   else {
     ymax = ACHANNEL_FIRST_TOP(ac);
@@ -2735,7 +2736,7 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
     UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH,
                                     NLACHANNEL_STEP(snla),
                                     0,
-                                    NLACHANNEL_FIRST_TOP(snla),
+                                    NLACHANNEL_FIRST_TOP(ac),
                                     x,
                                     y,
                                     NULL,
diff --git a/source/blender/editors/animation/anim_scrubbing.c b/source/blender/editors/animation/anim_scrubbing.c
new file mode 100644 (file)
index 0000000..a22d1b4
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edanimation
+ */
+
+#include "BKE_context.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "ED_scrubbing.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_interface_icons.h"
+#include "UI_view2d.h"
+#include "UI_resources.h"
+
+#include "DNA_scene_types.h"
+
+#include "BLI_rect.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_timecode.h"
+
+#include "RNA_access.h"
+
+static void get_scrubbing_region_rect(const ARegion *ar, rcti *rect)
+{
+  rect->xmin = 0;
+  rect->xmax = ar->winx;
+  rect->ymax = ar->winy;
+  rect->ymin = rect->ymax - UI_SCRUBBING_MARGIN_Y;
+}
+
+static int get_centered_text_y(const rcti *rect)
+{
+  return BLI_rcti_cent_y(rect) - UI_DPI_FAC * 4;
+}
+
+static void draw_background(const rcti *rect)
+{
+  uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+  immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+  immUniformThemeColor(TH_SCRUBBING_BACKGROUND);
+
+  GPU_blend(true);
+  GPU_blend_set_func_separate(
+      GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+  immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+
+  GPU_blend(false);
+
+  immUnbindProgram();
+}
+
+static void get_current_time_str(
+    const Scene *scene, bool display_seconds, int frame, uint max_len, char *r_str)
+{
+  if (display_seconds) {
+    BLI_timecode_string_from_time(r_str, max_len, 0, FRA2TIME(frame), FPS, U.timecode_style);
+  }
+  else {
+    BLI_snprintf(r_str, max_len, "%d", frame);
+  }
+}
+
+static void draw_current_frame(const Scene *scene,
+                               bool display_seconds,
+                               const View2D *v2d,
+                               const rcti *scrubbing_region_rect,
+                               int current_frame)
+{
+  const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+  const unsigned char color[] = {255, 255, 255, 255};
+  int frame_x = UI_view2d_view_to_region_x(v2d, current_frame);
+
+  char frame_str[64];
+  get_current_time_str(scene, display_seconds, current_frame, sizeof(frame_str), frame_str);
+  float text_width = UI_fontstyle_string_width(fstyle, frame_str);
+  float box_width = text_width + 10 * UI_DPI_FAC;
+  float box_padding = 3 * UI_DPI_FAC;
+
+  float bg_color[4];
+  UI_GetThemeColor4fv(TH_CFRAME, bg_color);
+  bg_color[3] = 8.0f;
+
+  UI_draw_roundbox_corner_set(UI_CNR_ALL);
+  UI_draw_roundbox_aa(true,
+                      frame_x - box_width / 2,
+                      scrubbing_region_rect->ymin + box_padding,
+                      frame_x + box_width / 2,
+                      scrubbing_region_rect->ymax - box_padding,
+                      5 * UI_DPI_FAC,
+                      bg_color);
+
+  UI_fontstyle_draw_simple(fstyle,
+                           frame_x - text_width / 2,
+                           get_centered_text_y(scrubbing_region_rect),
+                           frame_str,
+                           color);
+}
+
+void ED_scrubbing_draw(const ARegion *ar,
+                       const Scene *scene,
+                       bool display_seconds,
+                       bool discrete_frames)
+{
+  const View2D *v2d = &ar->v2d;
+
+  GPU_matrix_push_projection();
+  wmOrtho2_region_pixelspace(ar);
+
+  rcti scrubbing_region_rect;
+  get_scrubbing_region_rect(ar, &scrubbing_region_rect);
+
+  draw_background(&scrubbing_region_rect);
+
+  rcti numbers_rect = scrubbing_region_rect;
+  numbers_rect.ymin = get_centered_text_y(&scrubbing_region_rect) - 4 * UI_DPI_FAC;
+  if (discrete_frames) {
+    UI_view2d_draw_scale_x__discrete_frames_or_seconds(
+        ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT);
+  }
+  else {
+    UI_view2d_draw_scale_x__frames_or_seconds(
+        ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT);
+  }
+
+  draw_current_frame(scene, display_seconds, v2d, &scrubbing_region_rect, scene->r.cfra);
+
+  GPU_matrix_pop_projection();
+}
+
+void ED_channel_search_draw(const bContext *C, ARegion *ar, bDopeSheet *dopesheet)
+{
+  GPU_matrix_push_projection();
+  wmOrtho2_region_pixelspace(ar);
+
+  rcti rect;
+  rect.xmin = 0;
+  rect.xmax = ceilf(ar->sizex * UI_DPI_FAC);
+  rect.ymin = ar->sizey * UI_DPI_FAC - UI_SCRUBBING_MARGIN_Y;
+  rect.ymax = ceilf(ar->sizey * UI_DPI_FAC);
+
+  uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+  immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+  immUniformThemeColor(TH_BACK);
+  immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+  immUnbindProgram();
+
+  uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+
+  PointerRNA ptr;
+  RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet, &ptr);
+  PropertyRNA *prop = RNA_struct_find_property(&ptr, "filter_text");
+
+  int padding = 2 * UI_DPI_FAC;
+  uiDefAutoButR(block,
+                &ptr,
+                prop,
+                -1,
+                "",
+                ICON_NONE,
+                rect.xmin + padding,
+                rect.ymin + padding,
+                BLI_rcti_size_x(&rect) - 2 * padding,
+                BLI_rcti_size_y(&rect) - 2 * padding);
+
+  UI_block_end(C, block);
+  UI_block_draw(C, block);
+
+  GPU_matrix_pop_projection();
+}
index 6342a8b..cd68981 100644 (file)
@@ -403,7 +403,8 @@ typedef enum eAnimFilter_Flags {
 /* -------------- Channel Defines -------------- */
 
 /* channel heights */
-#define ACHANNEL_FIRST_TOP(ac) (-0.4f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_FIRST_TOP(ac) \
+  (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - ACHANNEL_SKIP)
 #define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit)
 #define ACHANNEL_SKIP (0.1f * U.widget_unit)
 #define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP)
@@ -420,14 +421,15 @@ typedef enum eAnimFilter_Flags {
 /* -------------- NLA Channel Defines -------------- */
 
 /* NLA channel heights */
-#define NLACHANNEL_FIRST_TOP(snla) (-0.4f * U.widget_unit)
+#define NLACHANNEL_FIRST_TOP(ac) \
+  (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - NLACHANNEL_SKIP)
 #define NLACHANNEL_HEIGHT(snla) \
   ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit))
 #define NLACHANNEL_SKIP (0.1f * U.widget_unit)
 #define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP)
 /* Additional offset to give some room at the end. */
-#define NLACHANNEL_TOT_HEIGHT(snla, item_amount) \
-  (-NLACHANNEL_FIRST_TOP(snla) + NLACHANNEL_STEP(snla) * (item_amount + 1))
+#define NLACHANNEL_TOT_HEIGHT(ac, item_amount) \
+  (-NLACHANNEL_FIRST_TOP(ac) + NLACHANNEL_STEP(((SpaceNla *)(ac)->sl)) * (item_amount + 1))
 
 /* channel widths */
 #define NLACHANNEL_NAMEWIDTH (10 * U.widget_unit)
index 264eb6a..6734342 100644 (file)
@@ -436,12 +436,11 @@ enum {
   ED_KEYMAP_GIZMO = (1 << 2),
   ED_KEYMAP_TOOL = (1 << 3),
   ED_KEYMAP_VIEW2D = (1 << 4),
-  ED_KEYMAP_MARKERS = (1 << 5),
-  ED_KEYMAP_ANIMATION = (1 << 6),
-  ED_KEYMAP_FRAMES = (1 << 7),
-  ED_KEYMAP_HEADER = (1 << 8),
-  ED_KEYMAP_GPENCIL = (1 << 9),
-  ED_KEYMAP_FOOTER = (1 << 10),
+  ED_KEYMAP_ANIMATION = (1 << 5),
+  ED_KEYMAP_FRAMES = (1 << 6),
+  ED_KEYMAP_HEADER = (1 << 7),
+  ED_KEYMAP_GPENCIL = (1 << 8),
+  ED_KEYMAP_FOOTER = (1 << 9),
 };
 
 /* SCREEN_OT_space_context_cycle direction */
diff --git a/source/blender/editors/include/ED_scrubbing.h b/source/blender/editors/include/ED_scrubbing.h
new file mode 100644 (file)
index 0000000..cc22572
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#ifndef __ED_SCRUBBING_H__
+#define __ED_SCRUBBING_H__
+
+struct bContext;
+struct View2DGrid;
+struct bDopeSheet;
+
+void ED_scrubbing_draw(const struct ARegion *ar,
+                       const struct Scene *scene,
+                       bool display_seconds,
+                       bool discrete_frames);
+
+void ED_channel_search_draw(const struct bContext *C,
+                            struct ARegion *ar,
+                            struct bDopeSheet *dopesheet);
+
+#endif /* __ED_SCRUBBING_H__ */
index af94889..0c2090b 100644 (file)
@@ -105,6 +105,7 @@ typedef enum ThemeColorID {
   TH_FACE_DOT,
   TH_FACEDOT_SIZE,
   TH_CFRAME,
+  TH_SCRUBBING_BACKGROUND,
   TH_TIME_KEYFRAME,
   TH_TIME_GP_KEYFRAME,
   TH_NURB_ULINE,
@@ -267,6 +268,8 @@ typedef enum ThemeColorID {
   TH_ICON_MODIFIER,
   TH_ICON_SHADING,
 
+  TH_SCROLL_TEXT,
+
   TH_NLA_TWEAK,       /* 'tweaking' track in NLA */
   TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */
 
index 064951d..6e9675f 100644 (file)
@@ -258,6 +258,8 @@ void UI_view2d_smooth_view(struct bContext *C,
                            struct ARegion *ar,
                            const struct rctf *cur,
                            const int smooth_viewtx);
+
 #define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
+#define UI_SCRUBBING_MARGIN_Y (23 * UI_DPI_FAC)
 
 #endif /* __UI_VIEW2D_H__ */
index 6958b82..41d0fda 100644 (file)
@@ -309,6 +309,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
         case TH_GRID:
           cp = ts->grid;
           break;
+        case TH_SCRUBBING_BACKGROUND:
+          cp = ts->scrubbing_background;
+          break;
         case TH_VIEW_OVERLAY:
           cp = ts->view_overlay;
           break;
@@ -881,6 +884,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
           cp = btheme->tui.icon_shading;
           break;
 
+        case TH_SCROLL_TEXT:
+          cp = btheme->tui.wcol_scroll.text;
+          break;
+
         case TH_INFO_SELECTED:
           cp = ts->info_selected;
           break;
index 9de7a33..fc9f88a 100644 (file)
@@ -185,6 +185,13 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
       v2d->vert.xmin = v2d->vert.xmax - scroll_width;
     }
 
+    /* Currently, all regions that have vertical scale text,
+     * also have the scrubbing area at the top.
+     * So the scrollbar has to move down a bit. */
+    if (scroll & V2D_SCROLL_SCALE_VERTICAL) {
+      v2d->vert.ymax -= UI_SCRUBBING_MARGIN_Y;
+    }
+
     /* horizontal scroller */
     if (scroll & (V2D_SCROLL_BOTTOM)) {
       /* on bottom edge of region */
index 8c73f4c..6fe2b5e 100644 (file)
@@ -1566,6 +1566,13 @@ static bool event_in_markers_region(const ARegion *ar, const wmEvent *event)
   return BLI_rcti_isect_pt(&rect, event->x, event->y);
 }
 
+static bool event_in_scrubbing_region(const ARegion *ar, const wmEvent *event)
+{
+  rcti rect = ar->winrct;
+  rect.ymin = rect.ymax - UI_SCRUBBING_MARGIN_Y;
+  return BLI_rcti_isect_pt(&rect, event->x, event->y);
+}
+
 /**
  * \param ar: Region, may be NULL when adding handlers for \a sa.
  */
@@ -1604,14 +1611,19 @@ static void ed_default_handlers(
     wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0);
     WM_event_add_keymap_handler(handlers, keymap);
   }
-  if (flag & ED_KEYMAP_MARKERS) {
+  if (flag & ED_KEYMAP_ANIMATION) {
+    wmKeyMap *keymap;
+
     /* time-markers */
-    wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0);
+    keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0);
     WM_event_add_keymap_handler_poll(handlers, keymap, event_in_markers_region);
-  }
-  if (flag & ED_KEYMAP_ANIMATION) {
+
+    /* time-scrubbing */
+    keymap = WM_keymap_ensure(wm->defaultconf, "Scrubbing", 0, 0);
+    WM_event_add_keymap_handler_poll(handlers, keymap, event_in_scrubbing_region);
+
     /* frame changing and timeline operators (for time spaces) */
-    wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0);
+    keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0);
     WM_event_add_keymap_handler(handlers, keymap);
   }
   if (flag & ED_KEYMAP_FRAMES) {
index 8ecd25b..1371305 100644 (file)
@@ -47,6 +47,7 @@
 #include "BKE_gpencil.h"
 
 #include "UI_view2d.h"
+#include "UI_interface.h"
 
 #include "ED_anim_api.h"
 #include "ED_gpencil.h"
index 5ac6297..aba75f9 100644 (file)
 
 #include "UI_resources.h"
 #include "UI_view2d.h"
+#include "UI_interface.h"
 
 #include "ED_space_api.h"
 #include "ED_screen.h"
 #include "ED_anim_api.h"
 #include "ED_markers.h"
+#include "ED_scrubbing.h"
 
 #include "action_intern.h" /* own include */
 #include "GPU_framebuffer.h"
@@ -234,20 +236,13 @@ static void action_main_region_draw(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  /* scrubbing region */
+  ED_scrubbing_draw(ar, scene, saction->flag & SACTION_DRAWTIME, true);
+
   /* scrollers */
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
   UI_view2d_scrollers_draw(v2d, scrollers);
   UI_view2d_scrollers_free(scrollers);
-
-  /* frame numbers */
-  UI_view2d_draw_scale_x__discrete_frames_or_seconds(
-      ar, v2d, &v2d->hor, scene, saction->flag & SACTION_DRAWTIME, TH_TEXT);
-
-  /* draw current frame number-indicator on top of scrollers */
-  if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) {
-    UI_view2d_view_orthoSpecial(ar, v2d, 1);
-    ANIM_draw_cfra_number(C, v2d, cfra_flag);
-  }
 }
 
 /* add handlers, stuff you only do once or on area/region changes */
@@ -285,6 +280,9 @@ static void action_channel_region_draw(const bContext *C, ARegion *ar)
     draw_channel_names((bContext *)C, &ac, ar);
   }
 
+  /* channel filter next to scrubbing area */
+  ED_channel_search_draw(C, ar, ac.ads);
+
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
@@ -869,7 +867,7 @@ void ED_spacetype_action(void)
   art->draw = action_main_region_draw;
   art->listener = action_main_region_listener;
   art->message_subscribe = saction_main_region_message_subscribe;
-  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
+  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
 
   BLI_addhead(&st->regiontypes, art);
 
index 5364c4b..3397c52 100644 (file)
@@ -47,6 +47,7 @@
 #include "ED_mask.h"
 #include "ED_space_api.h"
 #include "ED_screen.h"
+#include "ED_scrubbing.h"
 #include "ED_select_utils.h"
 #include "ED_clip.h"
 #include "ED_transform.h"
@@ -1041,22 +1042,16 @@ static void graph_region_draw(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  /* time-scrubbing */
+  ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true);
+
   /* scrollers */
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
   UI_view2d_scrollers_draw(v2d, scrollers);
   UI_view2d_scrollers_free(scrollers);
 
   /* scale indicators */
-  UI_view2d_draw_scale_x__discrete_frames_or_seconds(
-      ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS, TH_TEXT);
   UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert, TH_TEXT);
-
-  /* current frame indicator */
-  if (sc->flag & SC_SHOW_SECONDS) {
-    cfra_flag |= DRAWCFRA_UNIT_SECONDS;
-  }
-  UI_view2d_view_orthoSpecial(ar, v2d, 1);
-  ANIM_draw_cfra_number(C, v2d, cfra_flag);
 }
 
 static void dopesheet_region_draw(const bContext *C, ARegion *ar)
@@ -1093,18 +1088,13 @@ static void dopesheet_region_draw(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  /* time-scrubbing */
+  ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true);
+
   /* scrollers */
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
   UI_view2d_scrollers_draw(v2d, scrollers);
   UI_view2d_scrollers_free(scrollers);
-
-  /* frame numbers */
-  UI_view2d_draw_scale_x__discrete_frames_or_seconds(
-      ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS, TH_TEXT);
-
-  /* current frame number indicator */
-  UI_view2d_view_orthoSpecial(ar, v2d, 1);
-  ANIM_draw_cfra_number(C, v2d, cfra_flag);
 }
 
 static void clip_preview_region_draw(const bContext *C, ARegion *ar)
index 390ea0c..ee9b303 100644 (file)
@@ -42,6 +42,7 @@
 #include "ED_screen.h"
 #include "ED_anim_api.h"
 #include "ED_markers.h"
+#include "ED_scrubbing.h"
 
 #include "GPU_immediate.h"
 #include "GPU_state.h"
@@ -309,6 +310,9 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  /* time-scrubbing */
+  ED_scrubbing_draw(ar, scene, display_seconds, false);
+
   /* scrollers */
   // FIXME: args for scrollers depend on the type of data being shown...
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
@@ -316,14 +320,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
   UI_view2d_scrollers_free(scrollers);
 
   /* scale numbers */
-  UI_view2d_draw_scale_x__frames_or_seconds(ar, v2d, &v2d->hor, scene, display_seconds, TH_TEXT);
-  UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert, TH_TEXT);
-
-  /* draw current frame number-indicator on top of scrollers */
-  if ((sipo->mode != SIPO_MODE_DRIVERS) && ((sipo->flag & SIPO_NODRAWCFRANUM) == 0)) {
-    UI_view2d_view_orthoSpecial(ar, v2d, 1);
-    ANIM_draw_cfra_number(C, v2d, cfra_flag);
-  }
+  UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert, TH_SCROLL_TEXT);
 }
 
 static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar)
@@ -367,6 +364,9 @@ static void graph_channel_region_draw(const bContext *C, ARegion *ar)
     graph_draw_channel_names((bContext *)C, &ac, ar);
   }
 
+  /* channel filter next to scrubbing area */
+  ED_channel_search_draw(C, ar, ac.ads);
+
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
@@ -849,7 +849,7 @@ void ED_spacetype_ipo(void)
   art->draw = graph_main_region_draw;
   art->listener = graph_region_listener;
   art->message_subscribe = graph_region_message_subscribe;
-  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
+  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
 
   BLI_addhead(&st->regiontypes, art);
 
index 3e4eb6a..e5c116e 100644 (file)
@@ -52,6 +52,8 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "UI_interface.h"
+
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_build.h"
 
@@ -389,7 +391,7 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv
   UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH,
                                   NLACHANNEL_STEP(snla),
                                   0,
-                                  NLACHANNEL_FIRST_TOP(snla),
+                                  NLACHANNEL_FIRST_TOP(&ac),
                                   x,
                                   y,
                                   NULL,
index b821a24..68cbfd7 100644 (file)
@@ -689,11 +689,11 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
    * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
    *   start of list offset, and the second is as a correction for the scrollers.
    */
-  int height = NLACHANNEL_TOT_HEIGHT(snla, items);
+  int height = NLACHANNEL_TOT_HEIGHT(ac, items);
   v2d->tot.ymin = -height;
 
   /* loop through channels, and set up drawing depending on their type  */
-  float ymax = NLACHANNEL_FIRST_TOP(snla);
+  float ymax = NLACHANNEL_FIRST_TOP(ac);
 
   for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) {
     float ymin = ymax - NLACHANNEL_HEIGHT(snla);
@@ -822,7 +822,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
    * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
    *  start of list offset, and the second is as a correction for the scrollers.
    */
-  int height = NLACHANNEL_TOT_HEIGHT(snla, items);
+  int height = NLACHANNEL_TOT_HEIGHT(ac, items);
   v2d->tot.ymin = -height;
 
   /* need to do a view-sync here, so that the keys area doesn't jump around
@@ -832,7 +832,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
   /* draw channels */
   { /* first pass: just the standard GL-drawing for backdrop + text */
     size_t channel_index = 0;
-    float ymax = NLACHANNEL_FIRST_TOP(snla);
+    float ymax = NLACHANNEL_FIRST_TOP(ac);
 
     for (ale = anim_data.first; ale;
          ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++) {
@@ -849,7 +849,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
   { /* second pass: UI widgets */
     uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
     size_t channel_index = 0;
-    float ymax = NLACHANNEL_FIRST_TOP(snla);
+    float ymax = NLACHANNEL_FIRST_TOP(ac);
 
     /* set blending again, as may not be set in previous step */
     GPU_blend_set_func_separate(
index 07853e5..cf1794c 100644 (file)
@@ -429,7 +429,7 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa
   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 
   /* loop through all channels, finding the first one that's selected */
-  float ymax = NLACHANNEL_FIRST_TOP(snla);
+  float ymax = NLACHANNEL_FIRST_TOP(ac);
 
   for (ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) {
     const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
index accd825..0de9acf 100644 (file)
@@ -47,6 +47,7 @@
 #include "WM_types.h"
 
 #include "UI_view2d.h"
+#include "UI_interface.h"
 
 #include "nla_intern.h"  // own include
 
@@ -542,7 +543,7 @@ static void mouse_nla_strips(
    * (i.e a row in the list) where keyframe was */
   UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
   UI_view2d_listview_view_to_cell(
-      0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(snla), x, y, NULL, &channel_index);
+      0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index);
 
   /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click
    * (that is the size of keyframe icons, so user should be expecting similar tolerances)
index ba66094..123f34a 100644 (file)
@@ -40,6 +40,7 @@
 #include "ED_anim_api.h"
 #include "ED_markers.h"
 #include "ED_screen.h"
+#include "ED_scrubbing.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -201,6 +202,9 @@ static void nla_channel_region_draw(const bContext *C, ARegion *ar)
     draw_nla_channel_list(C, &ac, ar);
   }
 
+  /* channel filter next to scrubbing area */
+  ED_channel_search_draw(C, ar, ac.ads);
+
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
@@ -284,20 +288,12 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  ED_scrubbing_draw(ar, scene, snla->flag & SNLA_DRAWTIME, true);
+
   /* scrollers */
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
   UI_view2d_scrollers_draw(v2d, scrollers);
   UI_view2d_scrollers_free(scrollers);
-
-  /* frame numbers */
-  UI_view2d_draw_scale_x__discrete_frames_or_seconds(
-      ar, v2d, &v2d->hor, scene, snla->flag & SNLA_DRAWTIME, TH_TEXT);
-
-  /* draw current frame number-indicator on top of scrollers */
-  if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) {
-    UI_view2d_view_orthoSpecial(ar, v2d, 1);
-    ANIM_draw_cfra_number(C, v2d, cfra_flag);
-  }
 }
 
 /* add handlers, stuff you only do once or on area/region changes */
@@ -614,7 +610,7 @@ void ED_spacetype_nla(void)
   art->draw = nla_main_region_draw;
   art->listener = nla_main_region_listener;
   art->message_subscribe = nla_main_region_message_subscribe;
-  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
+  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
 
   BLI_addhead(&st->regiontypes, art);
 
index a3b0240..efae873 100644 (file)
@@ -60,6 +60,7 @@
 #include "ED_mask.h"
 #include "ED_sequencer.h"
 #include "ED_screen.h"
+#include "ED_scrubbing.h"
 #include "ED_space_api.h"
 
 #include "BIF_glutil.h"
@@ -2085,19 +2086,14 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
   /* reset view matrix */
   UI_view2d_view_restore(C);
 
+  /* scrubbing region */
+  ED_scrubbing_draw(ar, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
+
   /* scrollers */
   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
   UI_view2d_scrollers_draw(v2d, scrollers);
   UI_view2d_scrollers_free(scrollers);
 
-  /* scale numbers */
-  UI_view2d_draw_scale_x__discrete_frames_or_seconds(
-      ar, v2d, &v2d->hor, scene, !(sseq->flag & SEQ_DRAWFRAMES), TH_TEXT);
-  UI_view2d_draw_scale_y__block(ar, v2d, &v2d->vert, TH_TEXT);
-
-  /* draw current frame number-indicator on top of scrollers */
-  if ((sseq->flag & SEQ_NO_DRAW_CFRANUM) == 0) {
-    UI_view2d_view_orthoSpecial(ar, v2d, 1);
-    ANIM_draw_cfra_number(C, v2d, cfra_flag);
-  }
+  /* channel numbers */
+  UI_view2d_draw_scale_y__block(ar, v2d, &v2d->vert, TH_SCROLL_TEXT);
 }
index 2b0c29a..daeaf96 100644 (file)
@@ -816,7 +816,7 @@ void ED_spacetype_sequencer(void)
   art->draw = sequencer_main_region_draw;
   art->listener = sequencer_main_region_listener;
   art->message_subscribe = sequencer_main_region_message_subscribe;
-  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
+  art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
 
   BLI_addhead(&st->regiontypes, art);
 
index e3773e8..e3e7543 100644 (file)
@@ -283,6 +283,8 @@ typedef struct ThemeSpace {
   char cframe[4];
   char time_keyframe[4], time_gp_keyframe[4];
   char freestyle_edge_mark[4], freestyle_face_mark[4];
+  char scrubbing_background[4];
+  char _pad5[4];
 
   char nurb_uline[4], nurb_vline[4];
   char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4];
index a9bec82..011658e 100644 (file)
@@ -2065,6 +2065,11 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
   RNA_def_property_ui_text(prop, "Current Frame", "");
   RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
 
+  prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA);
+  RNA_def_property_array(prop, 4);
+  RNA_def_property_ui_text(prop, "Scrubbing Region", "");
+  RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
   prop = RNA_def_property(srna, "window_sliders", PROP_FLOAT, PROP_COLOR_GAMMA);
   RNA_def_property_float_sdna(prop, NULL, "shade1");
   RNA_def_property_array(prop, 3);
@@ -2759,6 +2764,11 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
   RNA_def_property_ui_text(prop, "Current Frame", "");
   RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
 
+  prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA);
+  RNA_def_property_array(prop, 4);
+  RNA_def_property_ui_text(prop, "Scrubbing Region", "");
+  RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
   prop = RNA_def_property(srna, "keyframe", PROP_FLOAT, PROP_COLOR_GAMMA);
   RNA_def_property_float_sdna(prop, NULL, "vertex_select");
   RNA_def_property_array(prop, 3);
@@ -2816,6 +2826,11 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
   RNA_def_property_ui_text(prop, "Current Frame", "");
   RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
 
+  prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA);
+  RNA_def_property_array(prop, 4);
+  RNA_def_property_ui_text(prop, "Scrubbing Region", "");
+  RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
   prop = RNA_def_property(srna, "value_sliders", PROP_FLOAT, PROP_COLOR_GAMMA);
   RNA_def_property_float_sdna(prop, NULL, "face");
   RNA_def_property_array(prop, 3);
@@ -3108,6 +3123,11 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
   RNA_def_property_array(prop, 3);
   RNA_def_property_ui_text(prop, "Current Frame", "");
   RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+  prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA);
+  RNA_def_property_array(prop, 4);
+  RNA_def_property_ui_text(prop, "Scrubbing Region", "");
+  RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
 }
 
 static void rna_def_userdef_theme_colorset(BlenderRNA *brna)
@@ -3215,6 +3235,11 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
   RNA_def_property_ui_text(prop, "Current Frame", "");
   RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
 
+  prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA);
+  RNA_def_property_array(prop, 4);
+  RNA_def_property_ui_text(prop, "Scrubbing Region", "");
+  RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
   prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
   RNA_def_property_float_sdna(prop, NULL, "strip");
   RNA_def_property_array(prop, 3);