From 35bcbad7e9cab11d04858fb1e36e712c1a8e56c7 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Thu, 19 Jun 2025 15:54:53 +0200 Subject: [PATCH] UI: Add Footer to Animation & VSE Editors Add a footer region which contains essentially the playback and frame range buttons from the Timeline Editor, to the following editors: - Dope Sheet - Graph - NLA - Sequencer Available in the View menu in each editor, hidden by default. The motivation is to provide a convenient way to access these often used controls, and in the near future adjust these footers to add more playback functionality related to each editor. See PR for details and screenshots. Pull Request: https://projects.blender.org/blender/blender/pulls/135697 --- scripts/startup/bl_ui/space_dopesheet.py | 21 ++- scripts/startup/bl_ui/space_graph.py | 38 +++++ scripts/startup/bl_ui/space_nla.py | 13 ++ scripts/startup/bl_ui/space_sequencer.py | 13 ++ scripts/startup/bl_ui/space_time.py | 147 ++++++++---------- .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_500.cc | 21 +++ source/blender/editors/screen/screen_ops.cc | 6 + .../editors/space_action/space_action.cc | 41 +++++ .../editors/space_graph/space_graph.cc | 18 +++ source/blender/editors/space_nla/space_nla.cc | 42 +++++ .../space_sequencer/space_sequencer.cc | 41 +++++ source/blender/makesrna/intern/rna_space.cc | 21 +-- 13 files changed, 328 insertions(+), 96 deletions(-) diff --git a/scripts/startup/bl_ui/space_dopesheet.py b/scripts/startup/bl_ui/space_dopesheet.py index 77027621fac..7e82e222942 100644 --- a/scripts/startup/bl_ui/space_dopesheet.py +++ b/scripts/startup/bl_ui/space_dopesheet.py @@ -16,9 +16,11 @@ from bl_ui.properties_data_grease_pencil import ( GreasePencil_LayerAdjustmentsPanel, GreasePencil_LayerDisplayPanel, ) + from bl_ui.utils import ( PlayheadSnappingPanel, ) +from bl_ui.space_time import playback_controls from rna_prop_ui import PropertyPanel @@ -206,12 +208,9 @@ class DOPESHEET_HT_header(Header): layout.template_header() if st.mode == 'TIMELINE': - from bl_ui.space_time import ( - TIME_MT_editor_menus, - TIME_HT_editor_buttons, - ) + from bl_ui.space_time import TIME_MT_editor_menus TIME_MT_editor_menus.draw_collapsible(context, layout) - TIME_HT_editor_buttons.draw_header(context, layout) + playback_controls(layout, context) else: layout.prop(st, "ui_mode", text="") @@ -337,6 +336,16 @@ class DOPESHEET_HT_editor_buttons: return context.object +class DOPESHEET_HT_playback_controls(Header): + bl_space_type = 'DOPESHEET_EDITOR' + bl_region_type = 'FOOTER' + + def draw(self, context): + layout = self.layout + + playback_controls(layout, context) + + class DOPESHEET_PT_snapping(Panel): bl_space_type = 'DOPESHEET_EDITOR' bl_region_type = 'HEADER' @@ -403,6 +412,7 @@ class DOPESHEET_MT_view(Menu): layout.prop(st, "show_region_ui") layout.prop(st, "show_region_hud") layout.prop(st, "show_region_channels") + layout.prop(st, "show_region_footer") layout.separator() layout.operator("action.view_selected") @@ -987,6 +997,7 @@ class DOPESHEET_PT_grease_pencil_layer_display( classes = ( DOPESHEET_HT_header, + DOPESHEET_HT_playback_controls, DOPESHEET_PT_proportional_edit, DOPESHEET_MT_editor_menus, DOPESHEET_MT_view, diff --git a/scripts/startup/bl_ui/space_graph.py b/scripts/startup/bl_ui/space_graph.py index 7e25bba60d5..8ae6f2503e7 100644 --- a/scripts/startup/bl_ui/space_graph.py +++ b/scripts/startup/bl_ui/space_graph.py @@ -8,6 +8,7 @@ from bl_ui.space_dopesheet import ( DopesheetFilterPopoverBase, dopesheet_filter, ) +from bl_ui.space_time import playback_controls from bl_ui.utils import ( PlayheadSnappingPanel, ) @@ -17,6 +18,27 @@ class GRAPH_PT_playhead_snapping(PlayheadSnappingPanel, Panel): bl_space_type = 'GRAPH_EDITOR' +def drivers_editor_footer(layout, context): + act_fcurve = context.active_editable_fcurve + if not act_fcurve: + return + + act_driver = act_fcurve.driver + if not act_driver: + return + + layout.separator_spacer() + layout.label(text="Driver: {!s} ({!s})".format(act_fcurve.id_data.name, act_fcurve.data_path)) + + if act_driver.variables: + layout.separator(type='LINE') + layout.label(text="Variables: %i" % len(act_driver.variables)) + + if act_driver.type == 'SCRIPTED' and act_driver.expression: + layout.separator(type='LINE') + layout.label(text="Expression: %s" % act_driver.expression) + + class GRAPH_HT_header(Header): bl_space_type = 'GRAPH_EDITOR' @@ -87,6 +109,20 @@ class GRAPH_HT_header(Header): ) +class GRAPH_HT_playback_controls(Header): + bl_space_type = 'GRAPH_EDITOR' + bl_region_type = 'FOOTER' + + def draw(self, context): + layout = self.layout + is_drivers_editor = context.space_data.mode == 'DRIVERS' + + if is_drivers_editor: + drivers_editor_footer(layout, context) + else: + playback_controls(layout, context) + + class GRAPH_PT_proportional_edit(Panel): bl_space_type = 'GRAPH_EDITOR' bl_region_type = 'HEADER' @@ -178,6 +214,7 @@ class GRAPH_MT_view(Menu): layout.prop(st, "show_region_ui") layout.prop(st, "show_region_hud") layout.prop(st, "show_region_channels") + layout.prop(st, "show_region_footer") layout.separator() layout.operator("graph.view_selected") @@ -549,6 +586,7 @@ class GRAPH_MT_snap_pie(Menu): classes = ( GRAPH_HT_header, + GRAPH_HT_playback_controls, GRAPH_PT_proportional_edit, GRAPH_MT_editor_menus, GRAPH_MT_view, diff --git a/scripts/startup/bl_ui/space_nla.py b/scripts/startup/bl_ui/space_nla.py index e57f42adb03..2a7b129682a 100644 --- a/scripts/startup/bl_ui/space_nla.py +++ b/scripts/startup/bl_ui/space_nla.py @@ -9,6 +9,7 @@ from bl_ui.space_dopesheet import ( DopesheetActionPanelBase, dopesheet_filter, ) +from bl_ui.space_time import playback_controls from bl_ui.utils import ( PlayheadSnappingPanel, ) @@ -49,6 +50,16 @@ class NLA_HT_header(Header): layout.popover(panel="NLA_PT_playhead_snapping") +class NLA_HT_playback_controls(Header): + bl_space_type = 'NLA_EDITOR' + bl_region_type = 'FOOTER' + + def draw(self, context): + layout = self.layout + + playback_controls(layout, context) + + class NLA_PT_snapping(Panel): bl_space_type = 'NLA_EDITOR' bl_region_type = 'HEADER' @@ -121,6 +132,7 @@ class NLA_MT_view(Menu): layout.prop(st, "show_region_ui") layout.prop(st, "show_region_hud") layout.prop(st, "show_region_channels") + layout.prop(st, "show_region_footer") layout.separator() layout.operator("nla.view_selected") @@ -400,6 +412,7 @@ class NLA_MT_channel_context_menu(Menu): classes = ( NLA_HT_header, + NLA_HT_playback_controls, NLA_MT_editor_menus, NLA_MT_view, NLA_MT_select, diff --git a/scripts/startup/bl_ui/space_sequencer.py b/scripts/startup/bl_ui/space_sequencer.py index 071778f9b22..bf5ec0f92ff 100644 --- a/scripts/startup/bl_ui/space_sequencer.py +++ b/scripts/startup/bl_ui/space_sequencer.py @@ -24,6 +24,7 @@ from bl_ui.utils import ( ) from rna_prop_ui import PropertyPanel +from bl_ui.space_time import playback_controls def _space_view_types(st): @@ -215,6 +216,16 @@ class SEQUENCER_HT_header(Header): sub.active = st.show_overlays +class SEQUENCER_HT_playback_controls(Header): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'FOOTER' + + def draw(self, context): + layout = self.layout + + playback_controls(layout, context) + + class SEQUENCER_MT_editor_menus(Menu): bl_idname = "SEQUENCER_MT_editor_menus" bl_label = "" @@ -468,6 +479,7 @@ class SEQUENCER_MT_view(Menu): layout.prop(st, "show_region_hud") if is_sequencer_only: layout.prop(st, "show_region_channels") + layout.prop(st, "show_region_footer") layout.separator() if is_preview: @@ -3135,6 +3147,7 @@ classes = ( SEQUENCER_MT_change, SEQUENCER_HT_tool_header, SEQUENCER_HT_header, + SEQUENCER_HT_playback_controls, SEQUENCER_MT_editor_menus, SEQUENCER_MT_range, SEQUENCER_MT_view, diff --git a/scripts/startup/bl_ui/space_time.py b/scripts/startup/bl_ui/space_time.py index 4c9d41bb96e..8e6bb3215fd 100644 --- a/scripts/startup/bl_ui/space_time.py +++ b/scripts/startup/bl_ui/space_time.py @@ -7,67 +7,82 @@ from bpy.types import Menu, Panel from bpy.app.translations import contexts as i18n_contexts -# Header buttons for timeline header (play, etc.) -class TIME_HT_editor_buttons: +def playback_controls(layout, context): + scene = context.scene + tool_settings = context.tool_settings + screen = context.screen + st = context.space_data + is_graph_editor = st.type == 'GRAPH_EDITOR' - @staticmethod - def draw_header(context, layout): - scene = context.scene - tool_settings = context.tool_settings - screen = context.screen + row = layout.row(align=True) + row.popover( + panel="TIME_PT_playback", + text="Playback", + ) + row.popover( + panel="TIME_PT_keyframing_settings", + text="Keying", + text_ctxt=i18n_contexts.id_windowmanager, + ) - layout.separator_spacer() + layout.separator_spacer() - row = layout.row(align=True) - row.prop(tool_settings, "use_keyframe_insert_auto", text="", toggle=True) - sub = row.row(align=True) - sub.active = tool_settings.use_keyframe_insert_auto - sub.popover( - panel="TIME_PT_auto_keyframing", - text="", - ) + row = layout.row(align=True) + row.prop(tool_settings, "use_keyframe_insert_auto", text="", toggle=True) + sub = row.row(align=True) + sub.active = tool_settings.use_keyframe_insert_auto + sub.popover( + panel="TIME_PT_auto_keyframing", + text="", + ) - row = layout.row(align=True) - row.operator("screen.frame_jump", text="", icon='REW').end = False - row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False - if not screen.is_animation_playing: - # if using JACK and A/V sync: - # hide the play-reversed button - # since JACK transport doesn't support reversed playback - if scene.sync_mode == 'AUDIO_SYNC' and context.preferences.system.audio_device == 'JACK': - row.scale_x = 2 - row.operator("screen.animation_play", text="", icon='PLAY') - row.scale_x = 1 - else: - row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True - row.operator("screen.animation_play", text="", icon='PLAY') - else: + row = layout.row(align=True) + row.operator("screen.frame_jump", text="", icon='REW').end = False + row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False + + if not screen.is_animation_playing: + # if using JACK and A/V sync: + # hide the play-reversed button + # since JACK transport doesn't support reversed playback + if scene.sync_mode == 'AUDIO_SYNC' and context.preferences.system.audio_device == 'JACK': row.scale_x = 2 - row.operator("screen.animation_play", text="", icon='PAUSE') + row.operator("screen.animation_play", text="", icon='PLAY') row.scale_x = 1 + else: + row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True + row.operator("screen.animation_play", text="", icon='PLAY') + else: + row.scale_x = 2 + row.operator("screen.animation_play", text="", icon='PAUSE') + row.scale_x = 1 + + if is_graph_editor: + row.operator("graph.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True + else: row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True - row.operator("screen.frame_jump", text="", icon='FF').end = True - layout.separator_spacer() + row.operator("screen.frame_jump", text="", icon='FF').end = True - row = layout.row() - if scene.show_subframe: - row.scale_x = 1.15 - row.prop(scene, "frame_float", text="") - else: - row.scale_x = 0.95 - row.prop(scene, "frame_current", text="") + layout.separator_spacer() - row = layout.row(align=True) - row.prop(scene, "use_preview_range", text="", toggle=True) - sub = row.row(align=True) - sub.scale_x = 0.8 - if not scene.use_preview_range: - sub.prop(scene, "frame_start", text="Start") - sub.prop(scene, "frame_end", text="End") - else: - sub.prop(scene, "frame_preview_start", text="Start") - sub.prop(scene, "frame_preview_end", text="End") + row = layout.row() + if scene.show_subframe: + row.scale_x = 1.15 + row.prop(scene, "frame_float", text="") + else: + row.scale_x = 0.95 + row.prop(scene, "frame_current", text="") + + row = layout.row(align=True) + row.prop(scene, "use_preview_range", text="", toggle=True) + sub = row.row(align=True) + sub.scale_x = 0.8 + if not scene.use_preview_range: + sub.prop(scene, "frame_start", text="Start") + sub.prop(scene, "frame_end", text="End") + else: + sub.prop(scene, "frame_preview_start", text="Start") + sub.prop(scene, "frame_preview_end", text="End") class TIME_MT_editor_menus(Menu): @@ -84,22 +99,6 @@ class TIME_MT_editor_menus(Menu): else: sub = layout - sub.popover( - panel="TIME_PT_playback", - text="Playback", - ) - sub.popover( - panel="TIME_PT_keyframing_settings", - text="Keying", - text_ctxt=i18n_contexts.id_windowmanager, - ) - - # Add a separator to keep the popover button from aligning with the menu button. - sub.separator(factor=0.4) - - if horizontal: - sub = row.row(align=True) - sub.menu("TIME_MT_view") if st.show_markers: sub.menu("TIME_MT_marker") @@ -224,10 +223,6 @@ class TimelinePanelButtons: bl_space_type = 'DOPESHEET_EDITOR' bl_region_type = 'UI' - @staticmethod - def has_timeline(context): - return context.space_data.mode == 'TIMELINE' - class TIME_PT_playback(TimelinePanelButtons, Panel): bl_label = "Playback" @@ -277,11 +272,6 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel): bl_options = {'HIDE_HEADER'} bl_region_type = 'HEADER' - @classmethod - def poll(cls, context): - # only for timeline editor - return cls.has_timeline(context) - def draw(self, context): layout = self.layout @@ -308,11 +298,6 @@ class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel): bl_region_type = 'HEADER' bl_ui_units_x = 9 - @classmethod - def poll(cls, context): - # Only for timeline editor. - return cls.has_timeline(context) - def draw(self, context): layout = self.layout diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 1fbee3e2be6..e5faf05f045 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 19 +#define BLENDER_FILE_SUBVERSION 20 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_500.cc b/source/blender/blenloader/intern/versioning_500.cc index ecf613016dd..dfdf2052836 100644 --- a/source/blender/blenloader/intern/versioning_500.cc +++ b/source/blender/blenloader/intern/versioning_500.cc @@ -10,6 +10,7 @@ #include "DNA_ID.h" #include "DNA_mesh_types.h" +#include "DNA_screen_types.h" #include "BLI_listbase.h" #include "BLI_set.hh" @@ -472,6 +473,26 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 20)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (ELEM(sl->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ)) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + ARegion *new_footer = do_versions_add_region_if_not_found( + regionbase, RGN_TYPE_FOOTER, "footer for animation editors", RGN_TYPE_HEADER); + if (new_footer != nullptr) { + new_footer->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : + RGN_ALIGN_BOTTOM; + new_footer->flag |= RGN_FLAG_HIDDEN; + } + } + } + } + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/editors/screen/screen_ops.cc b/source/blender/editors/screen/screen_ops.cc index c25b54cb6f9..020aa5688e7 100644 --- a/source/blender/editors/screen/screen_ops.cc +++ b/source/blender/editors/screen/screen_ops.cc @@ -5409,6 +5409,12 @@ static bool match_region_with_redraws(const ScrArea *area, return saction->mode == SACTCONT_TIMELINE; } } + else if (regiontype == RGN_TYPE_FOOTER) { + /* The footer region in animation editors shows the current frame. */ + if (ELEM(spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_SEQ, SPACE_NLA)) { + return true; + } + } else if (regiontype == RGN_TYPE_PREVIEW) { switch (spacetype) { case SPACE_SEQ: diff --git a/source/blender/editors/space_action/space_action.cc b/source/blender/editors/space_action/space_action.cc index 8739fec89f4..f3e371b4e2f 100644 --- a/source/blender/editors/space_action/space_action.cc +++ b/source/blender/editors/space_action/space_action.cc @@ -78,6 +78,14 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene) region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + /* footer */ + region = BKE_area_region_new(); + + BLI_addtail(&saction->regionbase, region); + region->regiontype = RGN_TYPE_FOOTER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; + region->flag = RGN_FLAG_HIDDEN; + /* channel list region */ region = BKE_area_region_new(); BLI_addtail(&saction->regionbase, region); @@ -758,6 +766,28 @@ static void action_header_region_listener(const wmRegionListenerParams *params) } } +static void action_footer_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + const wmNotifier *wmn = params->notifier; + + /* context changes */ + switch (wmn->category) { + case NC_SCREEN: + if (wmn->data == ND_ANIMPLAY) { + ED_region_tag_redraw(region); + } + break; + case NC_SCENE: + switch (wmn->data) { + case ND_FRAME: + ED_region_tag_redraw(region); + break; + } + break; + } +} + /* add handlers, stuff you only do once or on area/region changes */ static void action_buttons_area_init(wmWindowManager *wm, ARegion *region) { @@ -978,6 +1008,17 @@ void ED_spacetype_action() BLI_addhead(&st->regiontypes, art); + /* regions: footer */ + art = MEM_callocN("spacetype action region"); + art->regionid = RGN_TYPE_FOOTER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER; + art->init = action_header_region_init; + art->draw = action_header_region_draw; + art->listener = action_footer_region_listener; + + BLI_addhead(&st->regiontypes, art); + /* regions: channels */ art = MEM_callocN("spacetype action region"); art->regionid = RGN_TYPE_CHANNELS; diff --git a/source/blender/editors/space_graph/space_graph.cc b/source/blender/editors/space_graph/space_graph.cc index 5f81ae55b3b..7c8bc324a07 100644 --- a/source/blender/editors/space_graph/space_graph.cc +++ b/source/blender/editors/space_graph/space_graph.cc @@ -79,6 +79,14 @@ static SpaceLink *graph_create(const ScrArea * /*area*/, const Scene *scene) region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + /* footer */ + region = BKE_area_region_new(); + + BLI_addtail(&sipo->regionbase, region); + region->regiontype = RGN_TYPE_FOOTER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; + region->flag = RGN_FLAG_HIDDEN; + /* channels */ region = BKE_area_region_new(); @@ -976,6 +984,16 @@ void ED_spacetype_ipo() BLI_addhead(&st->regiontypes, art); + /* regions: footer */ + art = static_cast(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region")); + art->regionid = RGN_TYPE_FOOTER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER; + art->init = graph_header_region_init; + art->draw = graph_header_region_draw; + + BLI_addhead(&st->regiontypes, art); + /* regions: channels */ art = MEM_callocN("spacetype graphedit region"); art->regionid = RGN_TYPE_CHANNELS; diff --git a/source/blender/editors/space_nla/space_nla.cc b/source/blender/editors/space_nla/space_nla.cc index fba8e41399a..75070319412 100644 --- a/source/blender/editors/space_nla/space_nla.cc +++ b/source/blender/editors/space_nla/space_nla.cc @@ -68,6 +68,14 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene) region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + /* footer */ + region = BKE_area_region_new(); + + BLI_addtail(&snla->regionbase, region); + region->regiontype = RGN_TYPE_FOOTER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; + region->flag = RGN_FLAG_HIDDEN; + /* track list region */ region = BKE_area_region_new(); BLI_addtail(&snla->regionbase, region); @@ -325,6 +333,28 @@ static void nla_header_region_draw(const bContext *C, ARegion *region) ED_region_header(C, region); } +static void nla_footer_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + const wmNotifier *wmn = params->notifier; + + /* context changes */ + switch (wmn->category) { + case NC_SCREEN: + if (wmn->data == ND_ANIMPLAY) { + ED_region_tag_redraw(region); + } + break; + case NC_SCENE: + switch (wmn->data) { + case ND_FRAME: + ED_region_tag_redraw(region); + break; + } + break; + } +} + /* add handlers, stuff you only do once or on area/region changes */ static void nla_buttons_region_init(wmWindowManager *wm, ARegion *region) { @@ -664,6 +694,18 @@ void ED_spacetype_nla() BLI_addhead(&st->regiontypes, art); + /* regions: footer */ + art = MEM_callocN("spacetype nla region"); + art->regionid = RGN_TYPE_FOOTER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER; + + art->init = nla_header_region_init; + art->draw = nla_header_region_draw; + art->listener = nla_footer_region_listener; + + BLI_addhead(&st->regiontypes, art); + /* regions: tracks */ art = MEM_callocN("spacetype nla region"); art->regionid = RGN_TYPE_CHANNELS; diff --git a/source/blender/editors/space_sequencer/space_sequencer.cc b/source/blender/editors/space_sequencer/space_sequencer.cc index f34e417480d..afcae693eb6 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.cc +++ b/source/blender/editors/space_sequencer/space_sequencer.cc @@ -125,6 +125,14 @@ static SpaceLink *sequencer_create(const ScrArea * /*area*/, const Scene *scene) region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; region->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER; + /* Footer. */ + region = BKE_area_region_new(); + + BLI_addtail(&sseq->regionbase, region); + region->regiontype = RGN_TYPE_FOOTER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; + region->flag = RGN_FLAG_HIDDEN; + /* Buttons/list view. */ region = BKE_area_region_new(); @@ -752,6 +760,28 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *region) ED_region_header(C, region); } +static void sequencer_footer_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + const wmNotifier *wmn = params->notifier; + + /* context changes */ + switch (wmn->category) { + case NC_SCREEN: + if (wmn->data == ND_ANIMPLAY) { + ED_region_tag_redraw(region); + } + break; + case NC_SCENE: + switch (wmn->data) { + case ND_FRAME: + ED_region_tag_redraw(region); + break; + } + break; + } +} + /* *********************** toolbar region ************************ */ /* Add handlers, stuff you only do once or on area/region changes. */ static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *region) @@ -1212,6 +1242,17 @@ void ED_spacetype_sequencer() art->listener = sequencer_main_region_listener; BLI_addhead(&st->regiontypes, art); + /* Footer. */ + art = MEM_callocN("spacetype sequencer region"); + art->regionid = RGN_TYPE_FOOTER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER; + + art->init = sequencer_header_region_init; + art->draw = sequencer_header_region_draw; + art->listener = sequencer_footer_region_listener; + BLI_addhead(&st->regiontypes, art); + /* HUD. */ art = ED_area_type_hud(st->spaceid); BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index 2d591e272e7..1788094112d 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -6382,9 +6382,9 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data"); rna_def_space_generic_show_region_toggles(srna, - (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_UI) | - (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_HUD) | - (1 << RGN_TYPE_CHANNELS)); + (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_FOOTER) | + (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_TOOLS) | + (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); /* view type, fairly important */ prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE); @@ -6714,8 +6714,9 @@ static void rna_def_space_dopesheet(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceAction"); RNA_def_struct_ui_text(srna, "Space Dope Sheet Editor", "Dope Sheet space data"); - rna_def_space_generic_show_region_toggles( - srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); + rna_def_space_generic_show_region_toggles(srna, + (1 << RGN_TYPE_FOOTER) | (1 << RGN_TYPE_UI) | + (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); /* data */ prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); @@ -6883,8 +6884,9 @@ static void rna_def_space_graph(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceGraph"); RNA_def_struct_ui_text(srna, "Space Graph Editor", "Graph Editor space data"); - rna_def_space_generic_show_region_toggles( - srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); + rna_def_space_generic_show_region_toggles(srna, + (1 << RGN_TYPE_FOOTER) | (1 << RGN_TYPE_UI) | + (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); /* mode */ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); @@ -7016,8 +7018,9 @@ static void rna_def_space_nla(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceNla"); RNA_def_struct_ui_text(srna, "Space Nla Editor", "NLA editor space data"); - rna_def_space_generic_show_region_toggles( - srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); + rna_def_space_generic_show_region_toggles(srna, + (1 << RGN_TYPE_FOOTER) | (1 << RGN_TYPE_UI) | + (1 << RGN_TYPE_HUD) | (1 << RGN_TYPE_CHANNELS)); /* display */ prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);