UI: remove the Timeline

This adds versioning code that replaces any timeline with a
dopesheet where the footer is shown, AND it removes the
timeline from the menu options.

If the area is too small to show both, the footer and the
header then only the footer is shown.
This assumes that users created the small timeline
just for the playback controls

Any uses of `SACTCONT_TIMELINE` (except for versioning) have been removed.

part of #145577

Pull Request: https://projects.blender.org/blender/blender/pulls/147058
This commit is contained in:
Christoph Lendenfeld
2025-10-02 09:44:53 +02:00
committed by Christoph Lendenfeld
parent 116efa1b32
commit 2ae953d7f5
12 changed files with 48 additions and 236 deletions

View File

@@ -205,16 +205,10 @@ class DOPESHEET_HT_header(Header):
st = context.space_data
layout.template_header()
layout.prop(st, "ui_mode", text="")
if st.mode == 'TIMELINE':
from bl_ui.space_time import TIME_MT_editor_menus
TIME_MT_editor_menus.draw_collapsible(context, layout)
playback_controls(layout, context)
else:
layout.prop(st, "ui_mode", text="")
DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
DOPESHEET_HT_editor_buttons.draw_header(context, layout)
DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
DOPESHEET_HT_editor_buttons.draw_header(context, layout)
# Header for "normal" dopesheet editor modes (e.g. Dope Sheet, Action, Shape Keys, etc.)

View File

@@ -126,71 +126,6 @@ def playback_controls(layout, context):
sub.prop(scene, "frame_preview_end", text="End")
class TIME_MT_editor_menus(Menu):
bl_idname = "TIME_MT_editor_menus"
bl_label = ""
def draw(self, context):
layout = self.layout
horizontal = (layout.direction == 'VERTICAL')
st = context.space_data
if horizontal:
row = layout.row()
sub = row.row(align=True)
else:
sub = layout
sub.menu("TIME_MT_view")
if st.show_markers:
sub.menu("TIME_MT_marker")
class TIME_MT_marker(Menu):
bl_label = "Marker"
def draw(self, context):
layout = self.layout
marker_menu_generic(layout, context)
class TIME_MT_view(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
scene = context.scene
st = context.space_data
layout.prop(st, "show_region_hud")
layout.prop(st, "show_region_channels")
layout.separator()
# NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor
layout.operator("action.view_all")
if context.scene.use_preview_range:
layout.operator("anim.scene_range_frame", text="Frame Preview Range")
else:
layout.operator("anim.scene_range_frame", text="Frame Scene Range")
layout.operator("action.view_frame")
layout.separator()
layout.prop(st, "show_markers")
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
layout.separator()
layout.prop(scene, "show_keys_from_selected_only")
layout.prop(st.dopesheet, "show_only_errors")
layout.separator()
layout.menu("DOPESHEET_MT_cache")
layout.separator()
layout.menu("INFO_MT_area")
def marker_menu_generic(layout, context):
# layout.operator_context = 'EXEC_REGION_WIN'
@@ -357,9 +292,6 @@ class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
###################################
classes = (
TIME_MT_editor_menus,
TIME_MT_marker,
TIME_MT_view,
TIME_PT_playback,
TIME_PT_keyframing_settings,
TIME_PT_auto_keyframing,

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 99
#define BLENDER_FILE_SUBVERSION 100
/* 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

View File

@@ -3778,6 +3778,35 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 100)) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (!ELEM(sl->spacetype, SPACE_ACTION)) {
continue;
}
SpaceAction *saction = reinterpret_cast<SpaceAction *>(sl);
if (saction->mode != SACTCONT_TIMELINE) {
continue;
}
/* Switching to dopesheet since that is the closest to the timeline view. */
saction->mode = SACTCONT_DOPESHEET;
/* The multiplication by 2 assumes that the time control footer has the same size as the
* header. The header is only shown if there is enough space for both. */
const bool show_header = area->winy > (HEADERY * UI_SCALE_FAC) * 2;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (!show_header && region->regiontype == RGN_TYPE_HEADER) {
region->flag |= RGN_FLAG_HIDDEN;
}
if (region->regiontype == RGN_TYPE_FOOTER) {
region->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.

View File

@@ -140,11 +140,13 @@ bAction *ANIM_active_action_from_area(Scene *scene,
case SACTCONT_DOPESHEET:
case SACTCONT_MASK:
case SACTCONT_CACHEFILE:
case SACTCONT_TIMELINE:
if (r_action_user) {
*r_action_user = nullptr;
}
return nullptr;
case SACTCONT_TIMELINE:
BLI_assert_unreachable();
break;
}
BLI_assert_unreachable();
@@ -247,29 +249,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->data = &saction->ads;
return true;
case SACTCONT_TIMELINE: /* Timeline */
/* update scene-pointer (no need to check for pinning yet, as not implemented) */
saction->ads.source = reinterpret_cast<ID *>(ac->scene);
/* sync scene's "selected keys only" flag with our "only selected" flag
*
* XXX: This is a workaround for #55525. We shouldn't really be syncing the flags like this,
* but it's a simpler fix for now than also figuring out how the next/prev keyframe
* tools should work in the 3D View if we allowed full access to the timeline's
* dopesheet filters (i.e. we'd have to figure out where to host those settings,
* to be on a scene level like this flag currently is, along with several other unknowns).
*/
if (ac->scene->flag & SCE_KEYS_NO_SELONLY) {
saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL;
}
else {
saction->ads.filterflag |= ADS_FILTER_ONLYSEL;
}
ac->datatype = ANIMCONT_TIMELINE;
ac->data = &saction->ads;
return true;
default: /* unhandled yet */
ac->datatype = ANIMCONT_NONE;
ac->data = nullptr;

View File

@@ -624,10 +624,7 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
SPACE_MENU_MAP(SPACE_ACTION,
(((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ?
"TIME_MT_editor_menus" :
"DOPESHEET_MT_editor_menus");
SPACE_MENU_MAP(SPACE_ACTION, "DOPESHEET_MT_editor_menus");
SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");

View File

@@ -5584,12 +5584,8 @@ static bool match_region_with_redraws(const ScrArea *area,
}
}
else if (regiontype == RGN_TYPE_HEADER) {
if (spacetype == SPACE_ACTION) {
/* The timeline shows the current frame in the header. Other headers
* don't need to be updated. */
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
return saction->mode == SACTCONT_TIMELINE;
}
/* Since the timeline does not exist anymore, this doesn't need updating. */
return false;
}
else if (regiontype == RGN_TYPE_FOOTER) {
/* The footer region in animation editors shows the current frame. */

View File

@@ -319,10 +319,6 @@ static void draw_keyframes(bAnimContext *ac,
int action_flag = saction->flag;
bDopeSheet *ads = &saction->ads;
if (saction->mode == SACTCONT_TIMELINE) {
action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES);
}
const float channel_step = ANIM_UI_get_channel_step();
float ymax = ANIM_UI_get_first_channel_top(v2d);

View File

@@ -564,7 +564,7 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
switch (wmn->category) {
case NC_GPENCIL:
/* only handle these events for containers in which GPencil frames are displayed */
if (ELEM(saction->mode, SACTCONT_GPENCIL, SACTCONT_DOPESHEET, SACTCONT_TIMELINE)) {
if (ELEM(saction->mode, SACTCONT_GPENCIL, SACTCONT_DOPESHEET)) {
if (wmn->action == NA_EDITED) {
ED_area_tag_redraw(area);
}
@@ -626,10 +626,8 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
}
break;
default:
if (saction->mode != SACTCONT_TIMELINE) {
/* Just redrawing the view will do. */
ED_area_tag_redraw(area);
}
/* Just redrawing the view will do. */
ED_area_tag_redraw(area);
break;
}
break;
@@ -647,11 +645,6 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
case ND_POINTCACHE:
case ND_MODIFIER:
case ND_PARTICLE:
/* only needed in timeline mode */
if (saction->mode == SACTCONT_TIMELINE) {
ED_area_tag_refresh(area);
ED_area_tag_redraw(area);
}
break;
default: /* just redrawing the view will do */
ED_area_tag_redraw(area);
@@ -710,39 +703,18 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
static void action_header_region_listener(const wmRegionListenerParams *params)
{
ScrArea *area = params->area;
ARegion *region = params->region;
const wmNotifier *wmn = params->notifier;
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
if (saction->mode == SACTCONT_TIMELINE) {
if (wmn->data == ND_ANIMPLAY) {
ED_region_tag_redraw(region);
}
}
break;
case NC_SCENE:
if (saction->mode == SACTCONT_TIMELINE) {
switch (wmn->data) {
case ND_RENDER_RESULT:
case ND_OB_SELECT:
case ND_FRAME:
case ND_FRAME_RANGE:
case ND_KEYINGSET:
case ND_RENDER_OPTIONS:
ED_region_tag_redraw(region);
break;
}
}
else {
switch (wmn->data) {
case ND_OB_ACTIVE:
ED_region_tag_redraw(region);
break;
}
switch (wmn->data) {
case ND_OB_ACTIVE:
ED_region_tag_redraw(region);
break;
}
break;
case NC_ID:
@@ -898,54 +870,6 @@ static void action_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
}
}
/**
* \note Used for splitting out a subset of modes is more involved,
* The previous non-timeline mode is stored so switching back to the
* dope-sheet doesn't always reset the sub-mode.
*/
static int action_space_subtype_get(ScrArea *area)
{
SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET;
}
static void action_space_subtype_set(ScrArea *area, int value)
{
SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
if (value == SACTCONT_TIMELINE) {
if (sact->mode != SACTCONT_TIMELINE) {
sact->mode_prev = sact->mode;
}
sact->mode = value;
}
else {
sact->mode = sact->mode_prev;
}
}
static void action_space_subtype_item_extend(bContext * /*C*/,
EnumPropertyItem **item,
int *totitem)
{
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
}
static blender::StringRefNull action_space_name_get(const ScrArea *area)
{
SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
const int index = max_ii(0, RNA_enum_from_value(rna_enum_space_action_mode_items, sact->mode));
const EnumPropertyItem item = rna_enum_space_action_mode_items[index];
return item.name;
}
static int action_space_icon_get(const ScrArea *area)
{
SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
const int index = max_ii(0, RNA_enum_from_value(rna_enum_space_action_mode_items, sact->mode));
const EnumPropertyItem item = rna_enum_space_action_mode_items[index];
return item.icon;
}
static void action_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
{
SpaceAction *saction = (SpaceAction *)sl;
@@ -975,11 +899,6 @@ void ED_spacetype_action()
st->refresh = action_refresh;
st->id_remap = action_id_remap;
st->foreach_id = action_foreach_id;
st->space_subtype_item_extend = action_space_subtype_item_extend;
st->space_subtype_get = action_space_subtype_get;
st->space_subtype_set = action_space_subtype_set;
st->space_name_get = action_space_name_get;
st->space_icon_get = action_space_icon_get;
st->blend_read_data = action_space_blend_read_data;
st->blend_read_after_liblink = nullptr;
st->blend_write = action_space_blend_write;

View File

@@ -38,7 +38,6 @@ DEF_ENUM(rna_enum_space_sequencer_view_type_items)
DEF_ENUM(rna_enum_space_type_items)
DEF_ENUM(rna_enum_space_image_mode_items)
DEF_ENUM(rna_enum_space_image_mode_all_items)
DEF_ENUM(rna_enum_space_action_mode_items)
DEF_ENUM(rna_enum_fileselect_params_sort_items)
DEF_ENUM(rna_enum_region_type_items)
DEF_ENUM(rna_enum_object_modifier_type_items)

View File

@@ -1507,7 +1507,6 @@ bool rna_Action_actedit_assign_poll(PointerRNA *ptr, PointerRNA value)
case SACTCONT_DOPESHEET:
case SACTCONT_MASK:
case SACTCONT_CACHEFILE:
case SACTCONT_TIMELINE:
break;
}

View File

@@ -212,10 +212,6 @@ const EnumPropertyItem rna_enum_space_file_browse_mode_items[] = {
{ \
SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \
}
#define SACT_ITEM_TIMELINE \
{ \
SACTCONT_TIMELINE, "TIMELINE", ICON_TIME, "Timeline", "Timeline and playback controls" \
}
#define SACT_ITEM_ACTION \
{ \
SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", \
@@ -246,7 +242,6 @@ const EnumPropertyItem rna_enum_space_file_browse_mode_items[] = {
* so show that using object-icon hint */
static EnumPropertyItem rna_enum_space_action_mode_all_items[] = {
SACT_ITEM_DOPESHEET,
SACT_ITEM_TIMELINE,
SACT_ITEM_ACTION,
SACT_ITEM_SHAPEKEY,
SACT_ITEM_GPENCIL,
@@ -256,7 +251,6 @@ static EnumPropertyItem rna_enum_space_action_mode_all_items[] = {
};
static EnumPropertyItem rna_enum_space_action_ui_mode_items[] = {
SACT_ITEM_DOPESHEET,
/* SACT_ITEM_TIMELINE, */
SACT_ITEM_ACTION,
SACT_ITEM_SHAPEKEY,
SACT_ITEM_GPENCIL,
@@ -266,16 +260,7 @@ static EnumPropertyItem rna_enum_space_action_ui_mode_items[] = {
};
#endif
/* Expose as `ui_mode`. */
const EnumPropertyItem rna_enum_space_action_mode_items[] = {
SACT_ITEM_DOPESHEET,
SACT_ITEM_TIMELINE,
{0, nullptr, 0, nullptr, nullptr},
};
#undef SACT_ITEM_DOPESHEET
#undef SACT_ITEM_TIMELINE
#undef SACT_ITEM_ACTION
#undef SACT_ITEM_SHAPEKEY
#undef SACT_ITEM_GPENCIL
@@ -2349,21 +2334,10 @@ static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
SpaceAction *saction = (SpaceAction *)(ptr->data);
ScrArea *area = CTX_wm_area(C);
/* Collapse (and show) summary channel and hide channel list for timeline */
if (saction->mode == SACTCONT_TIMELINE) {
saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
saction->ads.filterflag |= ADS_FILTER_SUMMARY;
}
if (area && area->spacedata.first == saction) {
ARegion *channels_region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
if (channels_region) {
if (saction->mode == SACTCONT_TIMELINE) {
channels_region->flag |= RGN_FLAG_HIDDEN;
}
else {
channels_region->flag &= ~RGN_FLAG_HIDDEN;
}
channels_region->flag &= ~RGN_FLAG_HIDDEN;
ED_region_visibility_change_update(C, area, channels_region);
}
}
@@ -2373,9 +2347,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
/* store current mode as "old mode",
* so that returning from other editors doesn't always reset to "Action Editor" */
if (saction->mode != SACTCONT_TIMELINE) {
saction->mode_prev = saction->mode;
}
saction->mode_prev = saction->mode;
}
/* Space Graph Editor */