VSE: Story Tools: Add Scene Strip Menu improvements

- Show unassigned scene assets directly under Assets.
- Use Icons for Assets label.
- Only show "Scenes" when there are Assets.
- Don't show scene assets on the "Scenes" list.

The design about changing the operator default behaviour will be
addressed separately. This patch only changes the UI.

Design ref: #145522
Ref: !146574
This commit is contained in:
Dalai Felinto
2025-09-22 17:19:03 +02:00
parent 4253687a9f
commit 851e5b55af
6 changed files with 82 additions and 62 deletions

View File

@@ -798,36 +798,6 @@ class SEQUENCER_MT_add(Menu):
col.enabled = total >= 1
class SEQUENCER_MT_add_scene(Menu):
bl_label = "Scene"
bl_translation_context = i18n_contexts.operator_default
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("sequencer.scene_strip_add_new", text="Empty Scene", icon='ADD').type = 'EMPTY'
layout.menu_contents("SEQUENCER_MT_scene_add_root_catalogs")
bpy_data_scenes_len = len(bpy.data.scenes)
if bpy_data_scenes_len > 10:
layout.label(text="Scenes", icon='NONE')
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("sequencer.scene_strip_add", text="Scene...", icon='SCENE_DATA')
elif bpy_data_scenes_len > 1:
layout.label(text="Scenes", icon='NONE')
scene = context.sequencer_scene
for sc_item in bpy.data.scenes:
if sc_item == scene:
continue
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("sequencer.scene_strip_add", text=sc_item.name, translate=False).scene = sc_item.name
del bpy_data_scenes_len
class SEQUENCER_MT_add_empty(Menu):
bl_label = "Empty"
@@ -3209,7 +3179,6 @@ classes = (
SEQUENCER_MT_marker,
SEQUENCER_MT_navigation,
SEQUENCER_MT_add,
SEQUENCER_MT_add_scene,
SEQUENCER_MT_add_effect,
SEQUENCER_MT_add_transitions,
SEQUENCER_MT_add_empty,

View File

@@ -15,7 +15,7 @@ set(INC_SYS
set(SRC
sequencer_add.cc
sequencer_add_menu_scene_assets.cc
sequencer_add_menu_scene.cc
sequencer_buttons.cc
sequencer_channels_draw.cc
sequencer_channels_edit.cc

View File

@@ -7,6 +7,7 @@
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "BLI_listbase.h"
#include "BLI_multi_value_map.hh"
#include "BLI_string.h"
@@ -15,6 +16,7 @@
#include "BKE_asset.hh"
#include "BKE_idprop.hh"
#include "BKE_main.hh"
#include "BKE_screen.hh"
#include "BLT_translation.hh"
@@ -130,43 +132,81 @@ static void sequencer_add_unassigned_assets_draw(const bContext *C, Menu *menu)
}
}
static void sequencer_add_root_catalogs_draw(const bContext *C, Menu *menu)
static void sequencer_add_scene_draw(const bContext *C, Menu *menu)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (!sseq || !ELEM(sseq->view, SEQ_VIEW_SEQUENCE, SEQ_VIEW_SEQUENCE_PREVIEW)) {
return;
}
uiLayout *layout = menu->layout;
layout->operator_context_set(blender::wm::OpCallContext::InvokeRegionWin);
/* New scene. */
{
PointerRNA op_ptr = layout->op(
"SEQUENCER_OT_scene_strip_add_new", IFACE_("Empty Scene"), ICON_ADD);
RNA_string_set(&op_ptr, "type", "EMPTY");
}
/* Handle the assets. */
sseq->runtime->assets_for_menu = std::make_shared<asset::AssetItemTree>(build_catalog_tree(*C));
const bool loading_finished = all_loading_finished();
asset::AssetItemTree &tree = *sseq->runtime->assets_for_menu;
if (tree.catalogs.is_empty() && loading_finished && tree.unassigned_assets.is_empty()) {
return;
}
uiLayout *layout = menu->layout;
layout->separator();
layout->label(IFACE_("Assets"), ICON_NONE);
if (!loading_finished) {
layout->label(IFACE_("Loading Asset Libraries"), ICON_INFO);
}
tree.catalogs.foreach_root_item([&](const asset_system::AssetCatalogTreeItem &item) {
asset::draw_menu_for_catalog(item, "SEQUENCER_MT_scene_add_catalog_assets", *layout);
});
if (!tree.unassigned_assets.is_empty()) {
const bool show_assets = !(tree.catalogs.is_empty() && loading_finished &&
tree.unassigned_assets.is_empty());
if (show_assets) {
layout->separator();
layout->label(IFACE_("Assets"), ICON_ASSET_MANAGER);
if (!loading_finished) {
layout->label(IFACE_("Loading Asset Libraries"), ICON_INFO);
}
tree.catalogs.foreach_root_item([&](const asset_system::AssetCatalogTreeItem &item) {
asset::draw_menu_for_catalog(item, "SEQUENCER_MT_scene_add_catalog_assets", *layout);
});
if (!tree.unassigned_assets.is_empty()) {
layout->menu_contents("SEQUENCER_MT_scene_add_unassigned_assets");
}
layout->separator();
layout->menu(
"SEQUENCER_MT_scene_add_unassigned_assets", IFACE_("Unassigned"), ICON_FILE_HIDDEN);
}
/* We expect this to be drawn before another section in the menu. */
layout->separator();
/* Show existing scenes. */
Main *bmain = CTX_data_main(C);
const int scenes_len = BLI_listbase_count(&bmain->scenes);
if (scenes_len > 10) {
layout->op("SEQUENCER_OT_scene_strip_add",
IFACE_("Scenes..."),
ICON_SCENE_DATA,
blender::wm::OpCallContext::InvokeDefault,
UI_ITEM_NONE);
}
else if (scenes_len > 1) {
if (show_assets) {
layout->label(IFACE_("Scenes"), ICON_SCENE_DATA);
}
const Scene *active_scene = CTX_data_scene(C);
int i = 0;
LISTBASE_FOREACH_INDEX (Scene *, scene, &bmain->scenes, i) {
if (scene == active_scene) {
continue;
}
if (scene->id.asset_data) {
continue;
}
PointerRNA op_ptr = layout->op("SEQUENCER_OT_scene_strip_add",
scene->id.name + 2,
ICON_NONE,
blender::wm::OpCallContext::InvokeRegionWin,
UI_ITEM_NONE);
RNA_enum_set(&op_ptr, "scene", i);
}
}
}
MenuType add_catalog_assets_menu_type()
@@ -194,12 +234,12 @@ MenuType add_unassigned_assets_menu_type()
return type;
}
MenuType add_root_catalogs_menu_type()
MenuType add_scene_menu_type()
{
MenuType type{};
STRNCPY(type.idname, "SEQUENCER_MT_scene_add_root_catalogs");
STRNCPY(type.idname, "SEQUENCER_MT_add_scene");
type.poll = sequencer_add_menu_poll;
type.draw = sequencer_add_root_catalogs_draw;
type.draw = sequencer_add_scene_draw;
type.listener = asset::list::asset_reading_region_listen_fn;
return type;
}

View File

@@ -424,6 +424,6 @@ wmOperatorStatus sequencer_clipboard_paste_invoke(bContext *C,
/* `sequencer_add_menu_scene_assets.cc` */
MenuType add_catalog_assets_menu_type();
MenuType add_unassigned_assets_menu_type();
MenuType add_root_catalogs_menu_type();
MenuType add_scene_menu_type();
} // namespace blender::ed::vse

View File

@@ -1286,7 +1286,7 @@ void ED_spacetype_sequencer()
WM_menutype_add(MEM_dupallocN<MenuType>(__func__, add_catalog_assets_menu_type()));
WM_menutype_add(MEM_dupallocN<MenuType>(__func__, add_unassigned_assets_menu_type()));
WM_menutype_add(MEM_dupallocN<MenuType>(__func__, add_root_catalogs_menu_type()));
WM_menutype_add(MEM_dupallocN<MenuType>(__func__, add_scene_menu_type()));
BKE_spacetype_register(std::move(st));

View File

@@ -4498,6 +4498,17 @@ static bool rna_id_enum_filter_single(const ID *id, void *user_data)
return (id != user_data);
}
static bool rna_id_enum_filter_single_and_assets(const ID *id, void *user_data)
{
if (!rna_id_enum_filter_single(id, user_data)) {
return false;
}
if (id->asset_data != nullptr) {
return false;
}
return true;
}
/* Generic itemf's for operators that take library args. */
static const EnumPropertyItem *rna_id_itemf(bool *r_free,
ID *id,
@@ -4616,7 +4627,7 @@ const EnumPropertyItem *RNA_scene_without_sequencer_scene_itemf(bContext *C,
return rna_id_itemf(r_free,
C ? (ID *)CTX_data_main(C)->scenes.first : nullptr,
false,
rna_id_enum_filter_single,
rna_id_enum_filter_single_and_assets,
sequencer_scene);
}
const EnumPropertyItem *RNA_movieclip_itemf(bContext *C,