diff options
46 files changed, 1118 insertions, 99 deletions
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index 08f91781aa0..19798e3f165 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -665,6 +665,10 @@ const bTheme U_theme_default = { .row_alternate = RGBA(0xffffff05), .anim_preview_range = RGBA(0xa14d0066), .metadatatext = RGBA(0xffffffff), + .list = RGBA(0x18181800), + .list_title = RGBA(0xffffffff), + .list_text = RGBA(0xffffffff), + .list_text_hi = RGBA(0xffffffff), }, .space_image = { .back = RGBA(0x30303000), diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index d05e9f8b7f8..262d341e885 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -2998,6 +2998,22 @@ def km_sequencerpreview(params): return keymap +def km_sequencer_channels(params): + items = [] + keymap = ( + "Sequencer Channels", + {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Rename. + ("sequencer.rename_channel", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.rename_channel", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ]) + return keymap + + # ------------------------------------------------------------------------------ # Editor (Console) @@ -7844,6 +7860,7 @@ def generate_keymaps(params=None): km_sequencercommon(params), km_sequencer(params), km_sequencerpreview(params), + km_sequencer_channels(params), km_console(params), km_clip(params), km_clip_editor(params), diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 6661031552e..4c1b905ac05 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -1865,6 +1865,22 @@ def km_sequencerpreview(params): return keymap +def km_sequencer_channels(params): + items = [] + keymap = ( + "Sequencer Channels", + {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Rename. + ("sequencer.rename_channel", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.rename_channel", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ]) + return keymap + + def km_console(params): items = [] keymap = ( @@ -4090,6 +4106,7 @@ def generate_keymaps_impl(params=None): km_sequencercommon(params), km_sequencer(params), km_sequencerpreview(params), + km_sequencer_channels(params), km_console(params), km_clip(params), km_clip_editor(params), diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 96ac62fb502..56a63215dcb 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -418,6 +418,7 @@ class SEQUENCER_MT_view(Menu): if is_sequencer_view: layout.prop(st, "show_region_hud") + layout.prop(st, "show_region_channels") layout.separator() diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 604c8cb7a06..1f3b0606dfd 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 8 +#define BLENDER_FILE_SUBVERSION 9 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 685d24cee38..cc1204abbfb 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -321,6 +321,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int &scene_src->ed->seqbase, SEQ_DUPE_ALL, flag_subdata); + BLI_duplicatelist(&scene_dst->ed->channels, &scene_src->ed->channels); } if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { @@ -990,6 +991,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres BLO_write_struct(writer, Editing, ed); SEQ_blend_write(writer, &ed->seqbase); + LISTBASE_FOREACH (SeqTimelineChannel *, channel, &ed->channels) { + BLO_write_struct(writer, SeqTimelineChannel, channel); + } /* new; meta stack too, even when its nasty restore code */ LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) { BLO_write_struct(writer, MetaStack, ms); @@ -1174,6 +1178,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) if (sce->ed) { ListBase *old_seqbasep = &sce->ed->seqbase; + ListBase *old_displayed_channels = &sce->ed->channels; BLO_read_data_address(reader, &sce->ed); Editing *ed = sce->ed; @@ -1188,32 +1193,53 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) /* Read in sequence member data. */ SEQ_blend_read(reader, &ed->seqbase); + BLO_read_list(reader, &ed->channels); /* link metastack, slight abuse of structs here, * have to restore pointer to internal part in struct */ { Sequence temp; - void *poin; - intptr_t offset; + void *seqbase_poin; + void *channels_poin; + intptr_t seqbase_offset; + intptr_t channels_offset; - offset = ((intptr_t) & (temp.seqbase)) - ((intptr_t)&temp); + seqbase_offset = ((intptr_t) & (temp.seqbase)) - ((intptr_t)&temp); + channels_offset = ((intptr_t) & (temp.channels)) - ((intptr_t)&temp); - /* root pointer */ + /* seqbase root pointer */ if (ed->seqbasep == old_seqbasep) { ed->seqbasep = &ed->seqbase; } else { - poin = POINTER_OFFSET(ed->seqbasep, -offset); + seqbase_poin = POINTER_OFFSET(ed->seqbasep, -seqbase_offset); - poin = BLO_read_get_new_data_address(reader, poin); + seqbase_poin = BLO_read_get_new_data_address(reader, seqbase_poin); - if (poin) { - ed->seqbasep = (ListBase *)POINTER_OFFSET(poin, offset); + if (seqbase_poin) { + ed->seqbasep = (ListBase *)POINTER_OFFSET(seqbase_poin, seqbase_offset); } else { ed->seqbasep = &ed->seqbase; } } + + /* Active channels root pointer. */ + if (ed->displayed_channels == old_displayed_channels || ed->displayed_channels == NULL) { + ed->displayed_channels = &ed->channels; + } + else { + channels_poin = POINTER_OFFSET(ed->displayed_channels, -channels_offset); + channels_poin = BLO_read_get_new_data_address(reader, channels_poin); + + if (channels_poin) { + ed->displayed_channels = (ListBase *)POINTER_OFFSET(channels_poin, channels_offset); + } + else { + ed->displayed_channels = &ed->channels; + } + } + /* stack */ BLO_read_list(reader, &(ed->metastack)); @@ -1224,15 +1250,30 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) ms->oldbasep = &ed->seqbase; } else { - poin = POINTER_OFFSET(ms->oldbasep, -offset); - poin = BLO_read_get_new_data_address(reader, poin); - if (poin) { - ms->oldbasep = (ListBase *)POINTER_OFFSET(poin, offset); + seqbase_poin = POINTER_OFFSET(ms->oldbasep, -seqbase_offset); + seqbase_poin = BLO_read_get_new_data_address(reader, seqbase_poin); + if (seqbase_poin) { + ms->oldbasep = (ListBase *)POINTER_OFFSET(seqbase_poin, seqbase_offset); } else { ms->oldbasep = &ed->seqbase; } } + + if (ms->old_channels == old_displayed_channels || ms->old_channels == NULL) { + ms->old_channels = &ed->channels; + } + else { + channels_poin = POINTER_OFFSET(ms->old_channels, -channels_offset); + channels_poin = BLO_read_get_new_data_address(reader, channels_poin); + + if (channels_poin) { + ms->old_channels = (ListBase *)POINTER_OFFSET(channels_poin, channels_offset); + } + else { + ms->old_channels = &ed->channels; + } + } } } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index b1c982649d2..0996b35c8ea 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -637,13 +637,6 @@ static ARegion *do_versions_find_region(ListBase *regionbase, int regiontype) return region; } -static ARegion *do_versions_add_region(int regiontype, const char *name) -{ - ARegion *region = MEM_callocN(sizeof(ARegion), name); - region->regiontype = regiontype; - return region; -} - static void do_versions_area_ensure_tool_region(Main *bmain, const short space_type, const short region_flag) diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index eee0e7fbea8..d2b8c4330bc 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -53,6 +53,7 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_node.h" +#include "BKE_screen.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -62,6 +63,7 @@ #include "MEM_guardedalloc.h" #include "readfile.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" @@ -944,6 +946,14 @@ static bool seq_transform_filter_set(Sequence *seq, void *UNUSED(user_data)) return true; } +static bool seq_meta_channels_ensure(Sequence *seq, void *UNUSED(user_data)) +{ + if (seq->type == SEQ_TYPE_META) { + SEQ_channels_ensure(&seq->channels); + } + return true; +} + static void do_version_subsurface_methods(bNode *node) { if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { @@ -2487,6 +2497,58 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 302, 9)) { + /* Sequencer channels region. */ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype != SPACE_SEQ) { + continue; + } + if (ELEM(((SpaceSeq *)sl)->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) { + continue; + } + + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS); + if (!region) { + ARegion *tools_region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS); + region = do_versions_add_region(RGN_TYPE_CHANNELS, "channels region"); + BLI_insertlinkafter(regionbase, tools_region, region); + region->alignment = RGN_ALIGN_LEFT; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + } + + ARegion *timeline_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + if (timeline_region != NULL) { + timeline_region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + } + } + } + } + + /* Initialize channels. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Editing *ed = SEQ_editing_get(scene); + if (ed == NULL) { + continue; + } + SEQ_channels_ensure(&ed->channels); + SEQ_for_each_callback(&scene->ed->seqbase, seq_meta_channels_ensure, NULL); + + ed->displayed_channels = &ed->channels; + + ListBase *previous_channels = &ed->channels; + LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) { + ms->old_channels = previous_channels; + previous_channels = &ms->parseq->channels; + /* If `MetaStack` exists, active channels must point to last link. */ + ed->displayed_channels = &ms->parseq->channels; + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index 281769410bd..d2a55f6f37e 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -225,3 +225,10 @@ void version_socket_update_is_used(bNodeTree *ntree) link->tosock->flag |= SOCK_IN_USE; } } + +ARegion *do_versions_add_region(int regiontype, const char *name) +{ + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), name); + region->regiontype = regiontype; + return region; +} diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index 939b87823d4..c8c7dcc7cff 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -88,6 +88,7 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree * the flag on all sockets after changes to the node tree. */ void version_socket_update_is_used(bNodeTree *ntree); +ARegion *do_versions_add_region(int regiontype, const char *name); #ifdef __cplusplus } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index ec76f516780..dcf2ce4438d 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -328,6 +328,14 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) if (!USER_VERSION_ATLEAST(302, 8)) { btheme->space_node.grid_levels = U_theme_default.space_node.grid_levels; } + + if (!USER_VERSION_ATLEAST(302, 9)) { + FROM_DEFAULT_V4_UCHAR(space_sequencer.list); + FROM_DEFAULT_V4_UCHAR(space_sequencer.list_title); + FROM_DEFAULT_V4_UCHAR(space_sequencer.list_text); + FROM_DEFAULT_V4_UCHAR(space_sequencer.list_text_hi); + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c0b94c46631..d718c8b0d95 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -43,8 +43,10 @@ #include "ED_clip.h" #include "ED_gpencil.h" +#include "SEQ_channels.h" #include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_transform.h" #include "UI_interface.h" #include "WM_api.h" @@ -645,9 +647,10 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C, wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { - if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) { + if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq)) { CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq); } } diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 07d696283cb..2d1785523d7 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -26,6 +26,8 @@ set(SRC sequencer_add.c sequencer_buttons.c sequencer_draw.c + sequencer_channels_draw.c + sequencer_channels_edit.c sequencer_edit.c sequencer_modifier.c sequencer_ops.c diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c new file mode 100644 index 00000000000..5a43eade999 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup sequencer + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "ED_screen.h" + +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" +#include "GPU_vertex_buffer.h" +#include "GPU_viewport.h" + +#include "RNA_access.h" +#include "RNA_prototypes.h" + +#include "SEQ_channels.h" +#include "SEQ_sequencer.h" +#include "SEQ_time.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "WM_api.h" + +/* Own include. */ +#include "sequencer_intern.h" + +static ARegion *timeline_region_get(const ScrArea *area) +{ + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW) { + return region; + } + } + + BLI_assert_unreachable(); + return NULL; +} + +static float draw_offset_get(const View2D *timeline_region_v2d) +{ + return timeline_region_v2d->cur.ymin; +} + +static float channel_height_pixelspace_get(const View2D *timeline_region_v2d) +{ + return UI_view2d_view_to_region_y(timeline_region_v2d, 1.0f) - + UI_view2d_view_to_region_y(timeline_region_v2d, 0.0f); +} + +static float frame_width_pixelspace_get(const View2D *timeline_region_v2d) +{ + + return UI_view2d_view_to_region_x(timeline_region_v2d, 1.0f) - + UI_view2d_view_to_region_x(timeline_region_v2d, 0.0f); +} + +static float icon_width_get(const SeqChannelDrawContext *context) +{ + return (U.widget_unit * 0.8 * context->scale); +} + +static float widget_y_offset(const SeqChannelDrawContext *context) +{ + return (((context->channel_height / context->scale) - icon_width_get(context))) / 2; +} + +static float channel_index_y_min(const SeqChannelDrawContext *context, const int index) +{ + float y = (index - context->draw_offset) * context->channel_height; + y /= context->scale; + return y; +} + +static void displayed_channel_range_get(const SeqChannelDrawContext *context, + int r_channel_range[2]) +{ + /* Channel 0 is not usable, so should never be drawn. */ + r_channel_range[0] = max_ii(1, floor(context->timeline_region_v2d->cur.ymin)); + r_channel_range[1] = ceil(context->timeline_region_v2d->cur.ymax); + + rctf strip_boundbox; + BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, r_channel_range[1]); + SEQ_timeline_expand_boundbox(context->seqbase, &strip_boundbox); + CLAMP(r_channel_range[0], strip_boundbox.ymin, strip_boundbox.ymax); + CLAMP(r_channel_range[1], strip_boundbox.ymin, MAXSEQ); +} + +static char *draw_channel_widget_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) +{ + char *dyn_tooltip = argN; + return BLI_strdup(dyn_tooltip); +} + +static float draw_channel_widget_mute(const SeqChannelDrawContext *context, + uiBlock *block, + const int channel_index, + const float offset) +{ + float y = channel_index_y_min(context, channel_index) + widget_y_offset(context); + + const float width = icon_width_get(context); + SeqTimelineChannel *channel = SEQ_channel_get_by_index(context->channels, channel_index); + const int icon = SEQ_channel_is_muted(channel) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT; + + PointerRNA ptr; + RNA_pointer_create(&context->scene->id, &RNA_SequenceTimelineChannel, channel, &ptr); + PropertyRNA *hide_prop = RNA_struct_type_find_property(&RNA_SequenceTimelineChannel, "mute"); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *but = uiDefIconButR_prop(block, + UI_BTYPE_TOGGLE, + 1, + icon, + context->v2d->cur.xmax / context->scale - offset, + y, + width, + width, + &ptr, + hide_prop, + 0, + 0, + 0, + 0, + 0, + NULL); + + char *tooltip = BLI_sprintfN( + "%s channel %d", SEQ_channel_is_muted(channel) ? "Unmute" : "Mute", channel_index); + UI_but_func_tooltip_set(but, draw_channel_widget_tooltip, tooltip, MEM_freeN); + + return width; +} + +static float draw_channel_widget_lock(const SeqChannelDrawContext *context, + uiBlock *block, + const int channel_index, + const float offset) +{ + + float y = channel_index_y_min(context, channel_index) + widget_y_offset(context); + const float width = icon_width_get(context); + + SeqTimelineChannel *channel = SEQ_channel_get_by_index(context->channels, channel_index); + const int icon = SEQ_channel_is_locked(channel) ? ICON_LOCKED : ICON_UNLOCKED; + + PointerRNA ptr; + RNA_pointer_create(&context->scene->id, &RNA_SequenceTimelineChannel, channel, &ptr); + PropertyRNA *hide_prop = RNA_struct_type_find_property(&RNA_SequenceTimelineChannel, "lock"); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *but = uiDefIconButR_prop(block, + UI_BTYPE_TOGGLE, + 1, + icon, + context->v2d->cur.xmax / context->scale - offset, + y, + width, + width, + &ptr, + hide_prop, + 0, + 0, + 0, + 0, + 0, + ""); + + char *tooltip = BLI_sprintfN( + "%s channel %d", SEQ_channel_is_locked(channel) ? "Unlock" : "Lock", channel_index); + UI_but_func_tooltip_set(but, draw_channel_widget_tooltip, tooltip, MEM_freeN); + + return width; +} + +static bool channel_is_being_renamed(const SpaceSeq *sseq, const int channel_index) +{ + return sseq->runtime.rename_channel_index == channel_index; +} + +static float text_size_get(const SeqChannelDrawContext *context) +{ + const uiStyle *style = UI_style_get_dpi(); + return UI_fontstyle_height_max(&style->widget) * 1.5f * context->scale; +} + +/* Todo: decide what gets priority - label or buttons */ +static rctf label_rect_init(const SeqChannelDrawContext *context, + const int channel_index, + const float used_width) +{ + float text_size = text_size_get(context); + float margin = (context->channel_height / context->scale - text_size) / 2.0f; + float y = channel_index_y_min(context, channel_index) + margin; + + float margin_x = icon_width_get(context) * 0.65; + float width = max_ff(0.0f, context->v2d->cur.xmax / context->scale - used_width); + + /* Text input has own margin. Prevent text jumping around and use as much space as possible. */ + if (channel_is_being_renamed(CTX_wm_space_seq(context->C), channel_index)) { + float input_box_margin = icon_width_get(context) * 0.5f; + margin_x -= input_box_margin; + width += input_box_margin; + } + + rctf rect; + BLI_rctf_init(&rect, margin_x, margin_x + width, y, y + text_size); + return rect; +} + +static void draw_channel_labels(const SeqChannelDrawContext *context, + uiBlock *block, + const int channel_index, + const float used_width) +{ + SpaceSeq *sseq = CTX_wm_space_seq(context->C); + rctf rect = label_rect_init(context, channel_index, used_width); + + if (BLI_rctf_size_y(&rect) <= 1.0f || BLI_rctf_size_x(&rect) <= 1.0f) { + return; + } + + if (channel_is_being_renamed(sseq, channel_index)) { + SeqTimelineChannel *channel = SEQ_channel_get_by_index(context->channels, channel_index); + PointerRNA ptr = {NULL}; + RNA_pointer_create(&context->scene->id, &RNA_SequenceTimelineChannel, channel, &ptr); + PropertyRNA *prop = RNA_struct_name_property(ptr.type); + + UI_block_emboss_set(block, UI_EMBOSS); + uiBut *but = uiDefButR(block, + UI_BTYPE_TEXT, + 1, + "", + rect.xmin, + rect.ymin, + BLI_rctf_size_x(&rect), + BLI_rctf_size_y(&rect), + &ptr, + RNA_property_identifier(prop), + -1, + 0, + 0, + 0, + 0, + NULL); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + if (UI_but_active_only(context->C, context->region, block, but) == false) { + sseq->runtime.rename_channel_index = 0; + } + + WM_event_add_notifier(context->C, NC_SCENE | ND_SEQUENCER, context->scene); + } + else { + const char *label = SEQ_channel_name_get(context->channels, channel_index); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + label, + rect.xmin, + rect.ymin, + rect.xmax - rect.xmin, + (rect.ymax - rect.ymin), + NULL, + 0, + 0, + 0, + 0, + NULL); + } +} + +/* Todo: different text/buttons alignment */ +static void draw_channel_header(const SeqChannelDrawContext *context, + uiBlock *block, + const int channel_index) +{ + float offset = icon_width_get(context) * 1.5f; + offset += draw_channel_widget_lock(context, block, channel_index, offset); + offset += draw_channel_widget_mute(context, block, channel_index, offset); + + draw_channel_labels(context, block, channel_index, offset); +} + +static void draw_channel_headers(const SeqChannelDrawContext *context) +{ + GPU_matrix_push(); + wmOrtho2_pixelspace(context->region->winx / context->scale, + context->region->winy / context->scale); + uiBlock *block = UI_block_begin(context->C, context->region, __func__, UI_EMBOSS); + + int channel_range[2]; + displayed_channel_range_get(context, channel_range); + + for (int channel = channel_range[0]; channel <= channel_range[1]; channel++) { + draw_channel_header(context, block, channel); + } + + UI_block_end(context->C, block); + UI_block_draw(context->C, block); + + GPU_matrix_pop(); +} + +static void draw_background(void) +{ + UI_ThemeClearColor(TH_BACK); +} + +void channel_draw_context_init(const bContext *C, + ARegion *region, + SeqChannelDrawContext *r_context) +{ + r_context->C = C; + r_context->area = CTX_wm_area(C); + r_context->region = region; + r_context->v2d = ®ion->v2d; + r_context->scene = CTX_data_scene(C); + r_context->ed = SEQ_editing_get(r_context->scene); + r_context->seqbase = SEQ_active_seqbase_get(r_context->ed); + r_context->channels = SEQ_channels_displayed_get(r_context->ed); + r_context->timeline_region = timeline_region_get(CTX_wm_area(C)); + r_context->timeline_region_v2d = &r_context->timeline_region->v2d; + + r_context->channel_height = channel_height_pixelspace_get(r_context->timeline_region_v2d); + r_context->frame_width = frame_width_pixelspace_get(r_context->timeline_region_v2d); + r_context->draw_offset = draw_offset_get(r_context->timeline_region_v2d); + + r_context->scale = min_ff(r_context->channel_height / (U.widget_unit * 0.6), 1); +} + +void draw_channels(const bContext *C, ARegion *region) +{ + SeqChannelDrawContext context; + channel_draw_context_init(C, region, &context); + + UI_view2d_view_ortho(context.v2d); + + draw_background(); + draw_channel_headers(&context); + + UI_view2d_view_restore(C); +} diff --git a/source/blender/editors/space_sequencer/sequencer_channels_edit.c b/source/blender/editors/space_sequencer/sequencer_channels_edit.c new file mode 100644 index 00000000000..5a9189f74a8 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_channels_edit.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup sequencer + */ + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "BKE_context.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "ED_screen.h" + +#include "UI_view2d.h" + +#include "SEQ_channels.h" +#include "SEQ_sequencer.h" +#include "SEQ_time.h" + +#include "WM_api.h" + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +/* Own include. */ +#include "sequencer_intern.h" + +static int sequencer_rename_channel_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *event) +{ + SeqChannelDrawContext context; + SpaceSeq *sseq = CTX_wm_space_seq(C); + channel_draw_context_init(C, CTX_wm_region(C), &context); + float mouse_y = UI_view2d_region_to_view_y(context.timeline_region_v2d, event->mval[1]); + + sseq->runtime.rename_channel_index = mouse_y; + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C)); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_rename_channel(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Rename Channel"; + ot->idname = "SEQUENCER_OT_rename_channel"; + + /* Api callbacks. */ + ot->invoke = sequencer_rename_channel_invoke; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 0ed366209f6..31e885d16f2 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -56,6 +56,7 @@ #include "RNA_prototypes.h" +#include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_prefetch.h" @@ -95,6 +96,9 @@ void color3ubv_from_seq(const Scene *curscene, const bool show_strip_color_tag, uchar r_col[3]) { + Editing *ed = SEQ_editing_get(curscene); + ListBase *channels = SEQ_channels_displayed_get(ed); + if (show_strip_color_tag && (uint)seq->color_tag < SEQUENCE_COLOR_TOT && seq->color_tag != SEQUENCE_COLOR_NONE) { bTheme *btheme = UI_GetTheme(); @@ -214,7 +218,7 @@ void color3ubv_from_seq(const Scene *curscene, case SEQ_TYPE_SOUND_RAM: UI_GetThemeColor3ubv(TH_SEQ_AUDIO, r_col); blendcol[0] = blendcol[1] = blendcol[2] = 128; - if (seq->flag & SEQ_MUTE) { + if (SEQ_render_is_muted(channels, seq)) { UI_GetColorPtrBlendShade3ubv(r_col, blendcol, r_col, 0.5, 20); } break; @@ -568,6 +572,8 @@ static void drawmeta_contents(Scene *scene, float y2, const bool show_strip_color_tag) { + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; uchar col[4]; @@ -625,7 +631,7 @@ static void drawmeta_contents(Scene *scene, color3ubv_from_seq(scene, seq, show_strip_color_tag, col); } - if ((seqm->flag & SEQ_MUTE) || (seq->flag & SEQ_MUTE)) { + if (SEQ_render_is_muted(channels, seqm) || SEQ_render_is_muted(channels, seq)) { col[3] = 64; } else { @@ -919,7 +925,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, } /* Draw info text on a sequence strip. */ -static void draw_seq_text_overlay(View2D *v2d, +static void draw_seq_text_overlay(Scene *scene, + View2D *v2d, Sequence *seq, SpaceSeq *sseq, float x1, @@ -928,6 +935,8 @@ static void draw_seq_text_overlay(View2D *v2d, float y2, bool seq_active) { + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); char overlay_string[FILE_MAX]; size_t overlay_string_len = draw_seq_text_get_overlay_string( sseq, seq, overlay_string, sizeof(overlay_string)); @@ -942,7 +951,7 @@ static void draw_seq_text_overlay(View2D *v2d, col[3] = 255; /* Make the text duller when the strip is muted. */ - if (seq->flag & SEQ_MUTE) { + if (SEQ_render_is_muted(channels, seq)) { if (seq_active) { UI_GetColorPtrShade3ubv(col, col, -70); } @@ -963,6 +972,8 @@ static void draw_seq_text_overlay(View2D *v2d, static void draw_sequence_extensions_overlay( Scene *scene, Sequence *seq, uint pos, float pixely, const bool show_strip_color_tag) { + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); float x1, x2, y1, y2; uchar col[4], blend_col[3]; @@ -978,7 +989,7 @@ static void draw_sequence_extensions_overlay( if (seq->flag & SELECT) { UI_GetColorPtrShade3ubv(col, col, 50); } - col[3] = seq->flag & SEQ_MUTE ? MUTE_ALPHA : 200; + col[3] = SEQ_render_is_muted(channels, seq) ? MUTE_ALPHA : 200; UI_GetColorPtrShade3ubv(col, blend_col, 10); if (seq->startofs) { @@ -1001,7 +1012,8 @@ static void draw_sequence_extensions_overlay( GPU_blend(GPU_BLEND_NONE); } -static void draw_color_strip_band(Sequence *seq, uint pos, float text_margin_y, float y1) +static void draw_color_strip_band( + ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1) { uchar col[4]; SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; @@ -1010,7 +1022,7 @@ static void draw_color_strip_band(Sequence *seq, uint pos, float text_margin_y, rgb_float_to_uchar(col, colvars->col); /* Draw muted strips semi-transparent. */ - if (seq->flag & SEQ_MUTE) { + if (SEQ_render_is_muted(channels, seq)) { col[3] = MUTE_ALPHA; } /* Draw background semi-transparent when overlapping strips. */ @@ -1047,6 +1059,8 @@ static void draw_seq_background(Scene *scene, bool is_single_image, bool show_strip_color_tag) { + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); uchar col[4]; GPU_blend(GPU_BLEND_ALPHA); @@ -1066,7 +1080,7 @@ static void draw_seq_background(Scene *scene, } /* Draw muted strips semi-transparent. */ - if (seq->flag & SEQ_MUTE) { + if (SEQ_render_is_muted(channels, seq)) { col[3] = MUTE_ALPHA; } /* Draw background semi-transparent when overlapping strips. */ @@ -1303,6 +1317,9 @@ static void draw_seq_strip(const bContext *C, float pixelx, bool seq_active) { + Editing *ed = SEQ_editing_get(CTX_data_scene(C)); + ListBase *channels = SEQ_channels_displayed_get(ed); + View2D *v2d = ®ion->v2d; float x1, x2, y1, y2; const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx); @@ -1349,7 +1366,7 @@ static void draw_seq_strip(const bContext *C, /* Draw a color band inside color strip. */ if (seq->type == SEQ_TYPE_COLOR && y_threshold) { - draw_color_strip_band(seq, pos, text_margin_y, y1); + draw_color_strip_band(channels, seq, pos, text_margin_y, y1); } /* Draw strip offsets when flag is enabled or during "solo preview". */ @@ -1398,7 +1415,7 @@ static void draw_seq_strip(const bContext *C, BLI_rctf_size_x(®ion->v2d.cur) / region->winx); } /* Draw locked state. */ - if (seq->flag & SEQ_LOCK) { + if (SEQ_transform_is_locked(channels, seq)) { draw_seq_locked(x1, y1, x2, y2); } @@ -1410,7 +1427,7 @@ static void draw_seq_strip(const bContext *C, pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if ((seq->flag & SEQ_LOCK) == 0) { + if (!SEQ_transform_is_locked(channels, seq)) { draw_seq_handle( v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold); draw_seq_handle( @@ -1437,7 +1454,7 @@ static void draw_seq_strip(const bContext *C, if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { /* Depending on the vertical space, draw text on top or in the center of strip. */ draw_seq_text_overlay( - v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); + scene, v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); } } } @@ -2218,7 +2235,10 @@ void sequencer_draw_preview(const bContext *C, } if (!draw_backdrop && scene->ed != NULL) { - SeqCollection *collection = SEQ_query_rendered_strips(scene->ed->seqbasep, timeline_frame, 0); + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *collection = SEQ_query_rendered_strips( + channels, ed->seqbasep, timeline_frame, 0); Sequence *seq; Sequence *active_seq = SEQ_select_active_get(scene); SEQ_ITERATOR_FOREACH (seq, collection) { @@ -2269,14 +2289,6 @@ static void draw_seq_timeline_channels(View2D *v2d) immUnbindProgram(); } -static void draw_seq_timeline_channel_numbers(ARegion *region) -{ - View2D *v2d = ®ion->v2d; - rcti rect; - BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); - UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT); -} - static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) { Scene *scene = CTX_data_scene(C); @@ -2695,6 +2707,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); draw_seq_timeline_channels(v2d); + if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) { U.v2d_min_gridsize *= 3; UI_view2d_draw_lines_x__discrete_frames_or_seconds( @@ -2748,8 +2761,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_restore(C); ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); - - draw_seq_timeline_channel_numbers(region); } void draw_timeline_seq_display(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 283bd99cd5d..b77f780e413 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -32,6 +32,7 @@ #include "SEQ_add.h" #include "SEQ_animation.h" +#include "SEQ_channels.h" #include "SEQ_clipboard.h" #include "SEQ_edit.h" #include "SEQ_effects.h" @@ -345,6 +346,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; int snap_frame; @@ -352,7 +354,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) /* Check meta-strips. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK) && + if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq) && SEQ_transform_sequence_can_be_translated(seq)) { if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) { SEQ_transform_translate_sequence( @@ -374,7 +376,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) /* Test for effects and overlap. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) { + if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq)) { seq->flag &= ~SEQ_OVERLAP; if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); @@ -918,13 +920,14 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; bool selected; selected = !RNA_boolean_get(op->ptr, "unselected"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if ((seq->flag & SEQ_LOCK) == 0) { + if (!SEQ_transform_is_locked(channels, seq)) { if (selected) { if (seq->flag & SELECT) { seq->flag |= SEQ_MUTE; @@ -974,13 +977,14 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; bool selected; selected = !RNA_boolean_get(op->ptr, "unselected"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if ((seq->flag & SEQ_LOCK) == 0) { + if (!SEQ_transform_is_locked(channels, seq)) { if (selected) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_MUTE; @@ -1958,6 +1962,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Enter meta-strip. */ SEQ_meta_stack_alloc(ed, active_seq); SEQ_seqbase_active_set(ed, &active_seq->seqbase); + SEQ_channels_displayed_set(ed, &active_seq->channels); SEQ_select_active_set(scene, NULL); } else { @@ -1968,6 +1973,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) MetaStack *ms = SEQ_meta_stack_active_get(ed); SEQ_seqbase_active_set(ed, ms->oldbasep); + SEQ_channels_displayed_set(ed, ms->old_channels); SEQ_select_active_set(scene, ms->parseq); SEQ_meta_stack_free(ed, ms); } @@ -3082,8 +3088,10 @@ typedef struct Seq_get_text_cb_data { static bool seq_get_text_strip_cb(Sequence *seq, void *user_data) { Seq_get_text_cb_data *cd = (Seq_get_text_cb_data *)user_data; + Editing *ed = SEQ_editing_get(cd->scene); + ListBase *channels = SEQ_channels_displayed_get(ed); /* Only text strips that are not muted and don't end with negative frame. */ - if ((seq->type == SEQ_TYPE_TEXT) && ((seq->flag & SEQ_MUTE) == 0) && + if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) && (seq->enddisp > cd->scene->r.sfra)) { BLI_addtail(cd->text_seq, MEM_dupallocN(seq)); } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 33457103ff8..194aa518cd7 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -25,9 +25,31 @@ struct View2D; struct bContext; struct rctf; struct wmOperator; +struct ScrArea; +struct Editing; +struct ListBase; #define OVERLAP_ALPHA 180 +typedef struct SeqChannelDrawContext { + const struct bContext *C; + struct ScrArea *area; + struct ARegion *region; + struct ARegion *timeline_region; + struct View2D *v2d; + struct View2D *timeline_region_v2d; + + struct Scene *scene; + struct Editing *ed; + struct ListBase *seqbase; /* Displayed seqbase. */ + struct ListBase *channels; /* Displayed channels. */ + + float draw_offset; + float channel_height; + float frame_width; + float scale; +} SeqChannelDrawContext; + /* sequencer_draw.c */ void draw_timeline_seq(const struct bContext *C, struct ARegion *region); @@ -80,6 +102,12 @@ void draw_seq_strip_thumbnail(struct View2D *v2d, float pixelx, float pixely); +/* sequencer_draw_channels.c */ +void draw_channels(const struct bContext *C, struct ARegion *region); +void channel_draw_context_init(const struct bContext *C, + struct ARegion *region, + struct SeqChannelDrawContext *r_context); + /* sequencer_edit.c */ struct View2D; @@ -242,6 +270,9 @@ void SEQUENCER_OT_view_zoom_ratio(struct wmOperatorType *ot); void SEQUENCER_OT_view_selected(struct wmOperatorType *ot); void SEQUENCER_OT_view_ghost_border(struct wmOperatorType *ot); +/* sequencer_channels_edit.c */ +void SEQUENCER_OT_rename_channel(struct wmOperatorType *ot); + /* sequencer_preview.c */ void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index e39fcfbcb24..1aa2991f07a 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -102,6 +102,9 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_view_zoom_ratio); WM_operatortype_append(SEQUENCER_OT_view_selected); WM_operatortype_append(SEQUENCER_OT_view_ghost_border); + + /* sequencer_channels_edit.c */ + WM_operatortype_append(SEQUENCER_OT_rename_channel); } void sequencer_keymap(wmKeyConfig *keyconf) @@ -114,6 +117,9 @@ void sequencer_keymap(wmKeyConfig *keyconf) /* Preview Region ----------------------------------------------------------- */ WM_keymap_ensure(keyconf, "SequencerPreview", SPACE_SEQ, 0); + + /* Channels Region ----------------------------------------------------------- */ + WM_keymap_ensure(keyconf, "Sequencer Channels", SPACE_SEQ, 0); } void ED_operatormacros_sequencer(void) diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index bd6350960f1..66df1309d54 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -25,6 +25,7 @@ #include "RNA_define.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_select.h" #include "SEQ_sequencer.h" @@ -51,11 +52,13 @@ SeqCollection *all_strips_from_context(bContext *C) { Scene *scene = CTX_data_scene(C); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); const bool is_preview = sequencer_view_has_preview_poll(C); if (is_preview) { - return SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + return SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); } return SEQ_query_all_strips(seqbase); @@ -64,11 +67,13 @@ SeqCollection *all_strips_from_context(bContext *C) SeqCollection *selected_strips_from_context(bContext *C) { Scene *scene = CTX_data_scene(C); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); const bool is_preview = sequencer_view_has_preview_poll(C); if (is_preview) { - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); return strips; } @@ -709,6 +714,7 @@ static Sequence *seq_select_seq_from_preview( Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); SpaceSeq *sseq = CTX_wm_space_seq(C); View2D *v2d = UI_view2d_fromcontext(C); @@ -718,7 +724,8 @@ static Sequence *seq_select_seq_from_preview( /* Always update the coordinates (check extended after). */ const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown); + SeqCollection *strips = SEQ_query_rendered_strips( + channels, seqbase, scene->r.cfra, sseq->chanshown); /* Allow strips this far from the closest center to be included. * This allows cycling over center points which are near enough @@ -1574,9 +1581,11 @@ static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect, const Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); SpaceSeq *sseq = CTX_wm_space_seq(C); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown); + SeqCollection *strips = SEQ_query_rendered_strips( + channels, seqbase, scene->r.cfra, sseq->chanshown); Sequence *seq; SEQ_ITERATOR_FOREACH (seq, strips) { if (!seq_box_select_rect_image_isect(scene, seq, rect)) { diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index cd4ecd1a714..0a0669e02e4 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -131,6 +131,14 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; region->flag = RGN_FLAG_HIDDEN; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + + /* Channels. */ + region = MEM_callocN(sizeof(ARegion), "channels for sequencer"); + + BLI_addtail(&sseq->regionbase, region); + region->regiontype = RGN_TYPE_CHANNELS; + region->alignment = RGN_ALIGN_LEFT; /* Preview region. */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */ @@ -182,6 +190,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); region->v2d.keepzoom = 0; region->v2d.keeptot = 0; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; region->v2d.align = V2D_ALIGN_NO_NEG_Y; sseq->runtime.last_displayed_thumbnails = NULL; @@ -977,6 +986,24 @@ static void sequencer_id_remap(ScrArea *UNUSED(area), /* ************************************* */ +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_channel_region_init(wmWindowManager *wm, ARegion *region) +{ + wmKeyMap *keymap; + + region->alignment = RGN_ALIGN_LEFT; + + UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); + + keymap = WM_keymap_ensure(wm->defaultconf, "Sequencer Channels", SPACE_SEQ, 0); + WM_event_add_keymap_handler_v2d_mask(®ion->handlers, keymap); +} + +static void sequencer_channel_region_draw(const bContext *C, ARegion *region) +{ + draw_channels(C, region); +} + void ED_spacetype_sequencer(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer"); @@ -1048,6 +1075,16 @@ void ED_spacetype_sequencer(void) art->draw = sequencer_tools_region_draw; BLI_addhead(&st->regiontypes, art); + /* Channels. */ + art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer channels"); + art->regionid = RGN_TYPE_CHANNELS; + art->prefsizex = UI_COMPACT_PANEL_WIDTH; + art->keymapflag = ED_KEYMAP_UI; + art->init = sequencer_channel_region_init; + art->draw = sequencer_channel_region_draw; + art->listener = sequencer_main_region_listener; + BLI_addhead(&st->regiontypes, art); + /* Tool header. */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region"); art->regionid = RGN_TYPE_TOOL_HEADER; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 513d45ef4bf..b355b459c1e 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -17,8 +17,10 @@ #include "BKE_report.h" #include "ED_markers.h" +#include "ED_time_scrub_ui.h" #include "SEQ_animation.h" +#include "SEQ_channels.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" @@ -66,17 +68,19 @@ typedef struct TransSeq { */ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag) { + Scene *scene = t->scene; + Editing *ed = SEQ_editing_get(t->scene); + ListBase *channels = SEQ_channels_displayed_get(ed); + /* for extend we need to do some tricks */ if (t->mode == TFM_TIME_EXTEND) { /* *** Extend Transform *** */ - - Scene *scene = t->scene; int cfra = CFRA; int left = SEQ_transform_get_left_handle_frame(seq); int right = SEQ_transform_get_right_handle_frame(seq); - if (((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { + if (((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq))) { *r_count = 0; *r_flag = 0; } @@ -115,7 +119,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag) /* Count */ /* Non nested strips (resect selection and handles) */ - if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) { + if ((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq)) { *r_count = 0; *r_flag = 0; } @@ -771,6 +775,7 @@ static void flushTransSeq(TransInfo *t) seq->flag |= SEQ_OVERLAP; } } + SEQ_collection_free(transformed_strips); } diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c index 4a7c8d74d8b..cbc2cab0a7a 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.c +++ b/source/blender/editors/transform/transform_convert_sequencer_image.c @@ -15,6 +15,7 @@ #include "BKE_context.h" #include "BKE_report.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" #include "SEQ_sequencer.h" @@ -121,7 +122,8 @@ void createTransSeqImageData(TransInfo *t) } ListBase *seqbase = SEQ_active_seqbase_get(ed); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, t->scene->r.cfra, 0); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, t->scene->r.cfra, 0); SEQ_filter_selected_strips(strips); const int count = SEQ_collection_len(strips); diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c index 3b523708872..f2fb5b26305 100644 --- a/source/blender/editors/transform/transform_gizmo_2d.c +++ b/source/blender/editors/transform/transform_gizmo_2d.c @@ -36,6 +36,7 @@ #include "ED_screen.h" #include "ED_uvedit.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" @@ -243,8 +244,10 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min } else if (area->spacetype == SPACE_SEQ) { Scene *scene = CTX_data_scene(C); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); int selected_strips = SEQ_collection_len(strips); if (selected_strips > 0) { @@ -303,7 +306,8 @@ static int gizmo2d_calc_transform_orientation(const bContext *C) Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); bool use_local_orient = SEQ_collection_len(strips) == 1; @@ -325,7 +329,8 @@ static float gizmo2d_calc_rotation(const bContext *C) Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); if (SEQ_collection_len(strips) == 1) { @@ -348,8 +353,10 @@ static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2]) { zero_v2(r_pivot); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); bool has_select = SEQ_collection_len(strips) != 0; @@ -385,8 +392,10 @@ static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2]) if (pivot_point == V3D_AROUND_CURSOR) { SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); + SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0); SEQ_filter_selected_strips(strips); has_select = SEQ_collection_len(strips) != 0; SEQ_collection_free(strips); diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index 85e20d37278..cf229c9e9ec 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -18,8 +18,10 @@ #include "UI_view2d.h" +#include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "transform.h" @@ -121,14 +123,16 @@ static SeqCollection *seq_collection_extract_effects(SeqCollection *collection) static SeqCollection *query_snap_targets(const TransInfo *t, SeqCollection *snap_sources) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene)); + Editing *ed = SEQ_editing_get(t->scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); const short snap_flag = SEQ_tool_settings_snap_flag_get(t->scene); SeqCollection *snap_targets = SEQ_collection_create(__func__); LISTBASE_FOREACH (Sequence *, seq, seqbase) { if (seq->flag & SELECT) { continue; /* Selected are being transformed. */ } - if ((seq->flag & SEQ_MUTE) && (snap_flag & SEQ_SNAP_IGNORE_MUTED)) { + if (SEQ_render_is_muted(channels, seq) && (snap_flag & SEQ_SNAP_IGNORE_MUTED)) { continue; } if (seq->type == SEQ_TYPE_SOUND_RAM && (snap_flag & SEQ_SNAP_IGNORE_SOUND)) { diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index c8dd7ca45aa..cb660619a37 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -205,6 +205,7 @@ typedef struct Sequence { /** List of strips for metastrips. */ ListBase seqbase; + ListBase channels; /* SeqTimelineChannel */ /** The linked "bSound" object. */ struct bSound *sound; @@ -254,11 +255,19 @@ typedef struct Sequence { typedef struct MetaStack { struct MetaStack *next, *prev; ListBase *oldbasep; + ListBase *old_channels; Sequence *parseq; /* the startdisp/enddisp when entering the meta */ int disp_range[2]; } MetaStack; +typedef struct SeqTimelineChannel { + struct SeqTimelineChannel *next, *prev; + char name[64]; + int index; + int flag; +} SeqTimelineChannel; + typedef struct EditingRuntime { struct SequenceLookup *sequence_lookup; } EditingRuntime; @@ -266,9 +275,12 @@ typedef struct EditingRuntime { typedef struct Editing { /** Pointer to the current list of seq's being edited (can be within a meta strip). */ ListBase *seqbasep; + ListBase *displayed_channels; + void *_pad0; /** Pointer to the top-most seq's. */ ListBase seqbase; ListBase metastack; + ListBase channels; /* SeqTimelineChannel */ /* Context vars, used to be static */ Sequence *act_seq; @@ -779,6 +791,11 @@ enum { SEQ_TRANSFORM_FILTER_BILINEAR = 1, }; +typedef enum eSeqChannelFlag { + SEQ_CHANNEL_LOCK = (1 << 0), + SEQ_CHANNEL_MUTE = (1 << 1), +} eSeqChannelFlag; + /** \} */ #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 9ac9bdbf799..806c989100d 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -617,6 +617,8 @@ typedef struct SpaceSeqRuntime { struct rctf last_thumbnail_area; /** Stores lists of most recently displayed thumbnails. */ struct GHash *last_displayed_thumbnails; + int rename_channel_index; + char _pad0[4]; } SpaceSeqRuntime; /** Sequencer. */ diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 0013131e622..a27e699ef3d 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -15,7 +15,9 @@ #include "DNA_vfont_types.h" #include "BLI_iterator.h" +#include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" @@ -34,6 +36,7 @@ #include "rna_internal.h" #include "SEQ_add.h" +#include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_modifier.h" @@ -1374,6 +1377,71 @@ static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain) WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } +/* Find channel owner. If NULL, owner is `Editing`, otherwise it's `Sequence`. */ +static Sequence *rna_SeqTimelineChannel_owner_get(Editing *ed, SeqTimelineChannel *channel) +{ + SeqCollection *strips = SEQ_query_all_strips_recursive(&ed->seqbase); + + Sequence *channel_owner = NULL; + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, strips) { + if (seq->type != SEQ_TYPE_META) { + continue; + } + if (BLI_findindex(&seq->channels, channel) >= 0) { + channel_owner = seq; + } + } + + SEQ_collection_free(strips); + return channel_owner; +} + +static void rna_SequenceTimelineChannel_name_set(PointerRNA *ptr, const char *value) +{ + SeqTimelineChannel *channel = (SeqTimelineChannel *)ptr->data; + Scene *scene = (Scene *)ptr->owner_id; + Editing *ed = SEQ_editing_get(scene); + + Sequence *channel_owner = rna_SeqTimelineChannel_owner_get(ed, channel); + ListBase *channels_base = &ed->channels; + + if (channel_owner != NULL) { + channels_base = &channel_owner->channels; + } + + BLI_strncpy_utf8(channel->name, value, sizeof(channel->name)); + BLI_uniquename(channels_base, + channel, + "Channel", + '.', + offsetof(SeqTimelineChannel, name), + sizeof(channel->name)); +} + +static char *rna_SeqTimelineChannel_path(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->owner_id; + Editing *ed = SEQ_editing_get(scene); + SeqTimelineChannel *channel = (SeqTimelineChannel *)ptr->data; + + Sequence *channel_owner = rna_SeqTimelineChannel_owner_get(ed, channel); + + char channel_name_esc[(sizeof(channel->name)) * 2]; + BLI_str_escape(channel_name_esc, channel->name, sizeof(channel_name_esc)); + + if (channel_owner == NULL) { + return BLI_sprintfN("sequence_editor.channels[\"%s\"]", channel_name_esc); + } + else { + char owner_name_esc[(sizeof(channel_owner->name) - 2) * 2]; + BLI_str_escape(owner_name_esc, channel_owner->name + 2, sizeof(owner_name_esc)); + return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].channels[\"%s\"]", + owner_name_esc, + channel_name_esc); + } +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -2081,6 +2149,33 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_api_sequence_strip(srna); } +static void rna_def_channel(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SequenceTimelineChannel", NULL); + RNA_def_struct_sdna(srna, "SeqTimelineChannel"); + RNA_def_struct_path_func(srna, "rna_SeqTimelineChannel_path"); + RNA_def_struct_ui_text(srna, "Channel", ""); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, sizeof(((SeqTimelineChannel *)NULL)->name)); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SequenceTimelineChannel_name_set"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_CHANNEL_LOCK); + RNA_def_property_ui_text(prop, "Lock channel", ""); + + prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_CHANNEL_MUTE); + RNA_def_property_ui_text(prop, "Mute channel", ""); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); +} + static void rna_def_editor(BlenderRNA *brna) { StructRNA *srna; @@ -2129,6 +2224,11 @@ static void rna_def_editor(BlenderRNA *brna) RNA_def_property_collection_funcs( prop, NULL, NULL, NULL, "rna_SequenceEditor_meta_stack_get", NULL, NULL, NULL, NULL); + prop = RNA_def_property(srna, "channels", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "channels", NULL); + RNA_def_property_struct_type(prop, "SequenceTimelineChannel"); + RNA_def_property_ui_text(prop, "Channels", ""); + prop = RNA_def_property(srna, "active_strip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "act_seq"); RNA_def_property_flag(prop, PROP_EDITABLE); @@ -2475,6 +2575,11 @@ static void rna_def_meta(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip"); RNA_api_sequences(brna, prop, true); + prop = RNA_def_property(srna, "channels", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "channels", NULL); + RNA_def_property_struct_type(prop, "SequenceTimelineChannel"); + RNA_def_property_ui_text(prop, "Channels", ""); + func = RNA_def_function(srna, "separate", "rna_Sequence_separate"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Separate meta"); @@ -3472,6 +3577,7 @@ void RNA_def_sequencer(BlenderRNA *brna) rna_def_sequence(brna); rna_def_editor(brna); + rna_def_channel(brna); rna_def_image(brna); rna_def_meta(brna); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index e21c10166ab..ff272c34c65 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -5613,7 +5613,8 @@ static void rna_def_space_sequencer(BlenderRNA *brna) 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_TOOLS) | (1 << RGN_TYPE_HUD) | + (1 << RGN_TYPE_CHANNELS)); /* view type, fairly important */ prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index fd2bb9cb7cc..bbbe98e3191 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3149,6 +3149,7 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Sequence Editor", "Theme settings for the Sequence Editor"); rna_def_userdef_theme_spaces_main(srna); + rna_def_userdef_theme_spaces_list_main(srna); prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index 58a364bad8a..30aec24a024 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -32,6 +32,7 @@ set(INC_SYS set(SRC SEQ_add.h SEQ_animation.h + SEQ_channels.h SEQ_clipboard.h SEQ_edit.h SEQ_effects.h @@ -49,6 +50,7 @@ set(SRC SEQ_utils.h intern/animation.c + intern/channels.c intern/clipboard.c intern/disk_cache.c intern/disk_cache.h diff --git a/source/blender/sequencer/SEQ_channels.h b/source/blender/sequencer/SEQ_channels.h new file mode 100644 index 00000000000..1d87875fb26 --- /dev/null +++ b/source/blender/sequencer/SEQ_channels.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Editing; +struct ListBase; +struct Scene; +struct SeqTimelineChannel; + +struct ListBase *SEQ_channels_displayed_get(struct Editing *ed); +void SEQ_channels_displayed_set(struct Editing *ed, struct ListBase *channels); +void SEQ_channels_ensure(struct ListBase *channels); +void SEQ_channels_duplicate(struct ListBase *channels_dst, struct ListBase *channels_src); +void SEQ_channels_free(struct ListBase *channels); + +struct SeqTimelineChannel *SEQ_channel_get_by_index(const struct ListBase *channels, + const int channel_index); +char *SEQ_channel_name_get(struct ListBase *channels, const int channel_index); +bool SEQ_channel_is_locked(const struct SeqTimelineChannel *channel); +bool SEQ_channel_is_muted(const struct SeqTimelineChannel *channel); +int SEQ_channel_index_get(const struct SeqTimelineChannel *channel); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h index 7465b3c42cd..8cb20d41ba2 100644 --- a/source/blender/sequencer/SEQ_iterator.h +++ b/source/blender/sequencer/SEQ_iterator.h @@ -208,7 +208,8 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase); * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied * \return strip collection */ -SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, +SeqCollection *SEQ_query_rendered_strips(ListBase *channels, + ListBase *seqbase, int timeline_frame, int displayed_channel); /** diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h index fcf9f2365e1..bfe10d3eae9 100644 --- a/source/blender/sequencer/SEQ_render.h +++ b/source/blender/sequencer/SEQ_render.h @@ -104,6 +104,11 @@ struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_f void SEQ_render_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf); void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]); +/** + * Check if `seq` is muted for rendering. + * This function also checks `SeqTimelineChannel` flag. + */ +bool SEQ_render_is_muted(const struct ListBase *channels, const struct Sequence *seq); #ifdef __cplusplus } diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index 223077894b2..eb910a5a5d1 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -11,6 +11,7 @@ extern "C" { #endif +struct Editing; struct ListBase; struct Scene; struct SeqCollection; @@ -67,6 +68,12 @@ void SEQ_transform_offset_after_frame(struct Scene *scene, int delta, int timeline_frame); +/** + * Check if `seq` can be moved. + * This function also checks `SeqTimelineChannel` flag. + */ +bool SEQ_transform_is_locked(struct ListBase *channels, struct Sequence *seq); + /* Image transformation. */ void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]); diff --git a/source/blender/sequencer/intern/channels.c b/source/blender/sequencer/intern/channels.c new file mode 100644 index 00000000000..e8e82af03f5 --- /dev/null +++ b/source/blender/sequencer/intern/channels.c @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup sequencer + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" + +#include "BLI_blenlib.h" + +#include "SEQ_channels.h" +#include "SEQ_iterator.h" +#include "SEQ_relations.h" +#include "SEQ_sequencer.h" + +ListBase *SEQ_channels_displayed_get(Editing *ed) +{ + return ed->displayed_channels; +} + +void SEQ_channels_displayed_set(Editing *ed, ListBase *channels) +{ + ed->displayed_channels = channels; +} + +void SEQ_channels_ensure(ListBase *channels) +{ + /* Allocate channels. Channel 0 is never used, but allocated to prevent off by 1 issues. */ + for (int i = 0; i < MAXSEQ + 1; i++) { + SeqTimelineChannel *channel = MEM_callocN(sizeof(SeqTimelineChannel), "seq timeline channel"); + BLI_snprintf(channel->name, sizeof(channel->name), "Channel %d", i); + channel->index = i; + BLI_addtail(channels, channel); + } +} + +void SEQ_channels_duplicate(ListBase *channels_dst, ListBase *channels_src) +{ + LISTBASE_FOREACH (SeqTimelineChannel *, channel, channels_src) { + SeqTimelineChannel *channel_duplicate = MEM_dupallocN(channel); + BLI_addtail(channels_dst, channel_duplicate); + } +} + +void SEQ_channels_free(ListBase *channels) +{ + LISTBASE_FOREACH_MUTABLE (SeqTimelineChannel *, channel, channels) { + MEM_freeN(channel); + } +} + +SeqTimelineChannel *SEQ_channel_get_by_index(const ListBase *channels, const int channel_index) +{ + return BLI_findlink(channels, channel_index); +} + +char *SEQ_channel_name_get(ListBase *channels, const int channel_index) +{ + SeqTimelineChannel *channel = SEQ_channel_get_by_index(channels, channel_index); + return channel->name; +} + +int SEQ_channel_index_get(const SeqTimelineChannel *channel) +{ + return channel->index; +} + +bool SEQ_channel_is_locked(const SeqTimelineChannel *channel) +{ + return (channel->flag & SEQ_CHANNEL_LOCK) != 0; +} + +bool SEQ_channel_is_muted(const SeqTimelineChannel *channel) +{ + return (channel->flag & SEQ_CHANNEL_MUTE) != 0; +} diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index a4ab7671eb0..70f83485bb5 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -2422,6 +2422,7 @@ static ImBuf *do_multicam(const SeqRenderData *context, ImBuf *out; Editing *ed; ListBase *seqbasep; + ListBase *channels = &seq->channels; if (seq->multicam_source == 0 || seq->multicam_source >= seq->machine) { return NULL; @@ -2436,7 +2437,8 @@ static ImBuf *do_multicam(const SeqRenderData *context, return NULL; } - out = seq_render_give_ibuf_seqbase(context, timeline_frame, seq->multicam_source, seqbasep); + out = seq_render_give_ibuf_seqbase( + context, timeline_frame, seq->multicam_source, channels, seqbasep); return out; } @@ -2462,6 +2464,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl { Editing *ed; ListBase *seqbasep; + ListBase *channels = &seq->channels; ImBuf *i = NULL; ed = context->scene->ed; @@ -2474,7 +2477,8 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl timeline_frame = clamp_i(timeline_frame, seq->startdisp, seq->enddisp - 1); if (seq->machine > 1) { - i = seq_render_give_ibuf_seqbase(context, timeline_frame, seq->machine - 1, seqbasep); + i = seq_render_give_ibuf_seqbase( + context, timeline_frame, seq->machine - 1, channels, seqbasep); } /* Found nothing? so let's work the way up the meta-strip stack, so diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 4b378738c89..a4d8cf79d1f 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -20,6 +20,7 @@ #include "BKE_scene.h" #include "SEQ_iterator.h" +#include "SEQ_render.h" #include "SEQ_time.h" #include "render.h" @@ -285,14 +286,14 @@ static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_time } /* Remove strips we don't want to render from collection. */ -static void collection_filter_rendered_strips(SeqCollection *collection) +static void collection_filter_rendered_strips(ListBase *channels, SeqCollection *collection) { Sequence *seq; /* Remove sound strips and muted strips from collection, because these are not rendered. * Function #must_render_strip() don't have to check for these strips anymore. */ SEQ_ITERATOR_FOREACH (seq, collection) { - if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) { + if (seq->type == SEQ_TYPE_SOUND_RAM || SEQ_render_is_muted(channels, seq)) { SEQ_collection_remove_strip(seq, collection); } } @@ -305,7 +306,8 @@ static void collection_filter_rendered_strips(SeqCollection *collection) } } -SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, +SeqCollection *SEQ_query_rendered_strips(ListBase *channels, + ListBase *seqbase, const int timeline_frame, const int displayed_channel) { @@ -313,7 +315,7 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, if (displayed_channel != 0) { collection_filter_channel_up_to_incl(collection, displayed_channel); } - collection_filter_rendered_strips(collection); + collection_filter_rendered_strips(channels, collection); return collection; } diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c index 0b5ab0dd86c..01f581bc6c1 100644 --- a/source/blender/sequencer/intern/prefetch.c +++ b/source/blender/sequencer/intern/prefetch.c @@ -37,6 +37,7 @@ #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_query.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_prefetch.h" #include "SEQ_relations.h" @@ -387,19 +388,20 @@ static bool seq_prefetch_seq_has_disk_cache(PrefetchJob *pfjob, } static bool seq_prefetch_scene_strip_is_rendered(PrefetchJob *pfjob, + ListBase *channels, ListBase *seqbase, SeqCollection *scene_strips, bool is_recursive_check) { float cfra = seq_prefetch_cfra(pfjob); Sequence *seq_arr[MAXSEQ + 1]; - int count = seq_get_shown_sequences(seqbase, cfra, 0, seq_arr); + int count = seq_get_shown_sequences(channels, seqbase, cfra, 0, seq_arr); /* Iterate over rendered strips. */ for (int i = 0; i < count; i++) { Sequence *seq = seq_arr[i]; if (seq->type == SEQ_TYPE_META && - seq_prefetch_scene_strip_is_rendered(pfjob, &seq->seqbase, scene_strips, true)) { + seq_prefetch_scene_strip_is_rendered(pfjob, channels, &seq->seqbase, scene_strips, true)) { return true; } @@ -433,10 +435,10 @@ static SeqCollection *query_scene_strips(ListBase *seqbase) /* Prefetch must avoid rendering scene strips, because rendering in background locks UI and can * make it unresponsive for long time periods. */ -static bool seq_prefetch_must_skip_frame(PrefetchJob *pfjob, ListBase *seqbase) +static bool seq_prefetch_must_skip_frame(PrefetchJob *pfjob, ListBase *channels, ListBase *seqbase) { SeqCollection *scene_strips = query_scene_strips(seqbase); - if (seq_prefetch_scene_strip_is_rendered(pfjob, seqbase, scene_strips, false)) { + if (seq_prefetch_scene_strip_is_rendered(pfjob, channels, seqbase, scene_strips, false)) { SEQ_collection_free(scene_strips); return true; } @@ -485,7 +487,8 @@ static void *seq_prefetch_frames(void *job) pfjob->scene_eval->ed->prefetch_job = pfjob; ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene_eval)); - if (seq_prefetch_must_skip_frame(pfjob, seqbase)) { + ListBase *channels = SEQ_channels_displayed_get(SEQ_editing_get(pfjob->scene_eval)); + if (seq_prefetch_must_skip_frame(pfjob, channels, seqbase)) { pfjob->num_frames_prefetched++; continue; } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 3f4d1e875f3..18b0794dc72 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -50,6 +50,7 @@ #include "RE_engine.h" #include "RE_pipeline.h" +#include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_modifier.h" @@ -72,6 +73,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, SeqRenderState *state, + ListBase *channels, ListBase *seqbasep, float timeline_frame, int chanshown); @@ -256,12 +258,14 @@ static int seq_channel_cmp_fn(const void *a, const void *b) return (*(Sequence **)a)->machine - (*(Sequence **)b)->machine; } -int seq_get_shown_sequences(ListBase *seqbase, +int seq_get_shown_sequences(ListBase *channels, + ListBase *seqbase, const int timeline_frame, const int chanshown, Sequence **r_seq_arr) { - SeqCollection *collection = SEQ_query_rendered_strips(seqbase, timeline_frame, chanshown); + SeqCollection *collection = SEQ_query_rendered_strips( + channels, seqbase, timeline_frame, chanshown); const int strip_count = BLI_gset_len(collection->set); if (strip_count > MAXSEQ) { @@ -1582,6 +1586,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, { ImBuf *ibuf = NULL; ListBase *seqbase = NULL; + ListBase *channels = &seq->channels; int offset; seqbase = SEQ_get_seqbase_from_sequence(seq, &offset); @@ -1594,6 +1599,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, ibuf = seq_render_strip_stack(context, state, + channels, seqbase, /* scene strips don't have their start taken into account */ frame_index + offset, @@ -1809,6 +1815,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( static ImBuf *seq_render_strip_stack(const SeqRenderData *context, SeqRenderState *state, + ListBase *channels, ListBase *seqbasep, float timeline_frame, int chanshown) @@ -1818,7 +1825,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, int i; ImBuf *out = NULL; - count = seq_get_shown_sequences(seqbasep, timeline_frame, chanshown, (Sequence **)&seq_arr); + count = seq_get_shown_sequences( + channels, seqbasep, timeline_frame, chanshown, (Sequence **)&seq_arr); if (count == 0) { return NULL; @@ -1909,6 +1917,7 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, Scene *scene = context->scene; Editing *ed = SEQ_editing_get(scene); ListBase *seqbasep; + ListBase *channels; if (ed == NULL) { return NULL; @@ -1918,9 +1927,11 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int count = BLI_listbase_count(&ed->metastack); count = max_ii(count + chanshown, 0); seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep; + channels = ((MetaStack *)BLI_findlink(&ed->metastack, count))->old_channels; } else { seqbasep = ed->seqbasep; + channels = ed->displayed_channels; } SeqRenderState state; @@ -1929,7 +1940,7 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, Sequence *seq_arr[MAXSEQ + 1]; int count; - count = seq_get_shown_sequences(seqbasep, timeline_frame, chanshown, seq_arr); + count = seq_get_shown_sequences(channels, seqbasep, timeline_frame, chanshown, seq_arr); if (count) { out = seq_cache_get(context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT); @@ -1941,7 +1952,7 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, if (count && !out) { BLI_mutex_lock(&seq_render_mutex); - out = seq_render_strip_stack(context, &state, seqbasep, timeline_frame, chanshown); + out = seq_render_strip_stack(context, &state, channels, seqbasep, timeline_frame, chanshown); if (context->is_prefetch_render) { seq_cache_put(context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out); @@ -1961,12 +1972,13 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, ImBuf *seq_render_give_ibuf_seqbase(const SeqRenderData *context, float timeline_frame, int chan_shown, + ListBase *channels, ListBase *seqbasep) { SeqRenderState state; seq_render_state_init(&state); - return seq_render_strip_stack(context, &state, seqbasep, timeline_frame, chan_shown); + return seq_render_strip_stack(context, &state, channels, seqbasep, timeline_frame, chan_shown); } ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, @@ -2135,4 +2147,11 @@ void SEQ_render_thumbnails_base_set(const SeqRenderData *context, } } +bool SEQ_render_is_muted(const ListBase *channels, const Sequence *seq) +{ + + SeqTimelineChannel *channel = SEQ_channel_get_by_index(channels, seq->machine); + return seq->flag & SEQ_MUTE || SEQ_channel_is_muted(channel); +} + /** \} */ diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index 9a41cd8888a..d41a0e3f86f 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -33,6 +33,7 @@ void seq_render_state_init(SeqRenderState *state); struct ImBuf *seq_render_give_ibuf_seqbase(const struct SeqRenderData *context, float timeline_frame, int chan_shown, + struct ListBase *channels, struct ListBase *seqbasep); struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const struct SeqRenderData *context, @@ -43,7 +44,8 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, struct ImBuf *ibuf2, struct ImBuf *ibuf3); void seq_imbuf_to_sequencer_space(struct Scene *scene, struct ImBuf *ibuf, bool make_float); -int seq_get_shown_sequences(struct ListBase *seqbase, +int seq_get_shown_sequences(struct ListBase *channels, + struct ListBase *seqbase, int timeline_frame, int chanshown, struct Sequence **r_seq_arr); diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 345d26718fd..baa06e133b7 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -27,6 +27,7 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" +#include "SEQ_channels.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" @@ -135,6 +136,10 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int seq->color_tag = SEQUENCE_COLOR_NONE; + if (seq->type == SEQ_TYPE_META) { + SEQ_channels_ensure(&seq->channels); + } + SEQ_relations_session_uuid_generate(seq); return seq; @@ -201,6 +206,9 @@ static void seq_sequence_free_ex(Scene *scene, SEQ_relations_invalidate_cache_raw(scene, seq); } } + if (seq->type == SEQ_TYPE_META) { + SEQ_channels_free(&seq->channels); + } MEM_freeN(seq); } @@ -260,6 +268,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user) BLI_freelistN(&ed->metastack); SEQ_sequence_lookup_free(scene); + SEQ_channels_free(&ed->channels); MEM_freeN(ed); scene->ed = NULL; @@ -386,6 +395,7 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta) BLI_addtail(&ed->metastack, ms); ms->parseq = seq_meta; ms->oldbasep = ed->seqbasep; + ms->old_channels = ed->displayed_channels; copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); return ms; } @@ -460,6 +470,9 @@ static Sequence *seq_dupli(const Scene *scene_src, BLI_listbase_clear(&seqn->seqbase); /* WARNING: This meta-strip is not recursively duplicated here - do this after! */ // seq_dupli_recursive(&seq->seqbase, &seqn->seqbase); + + BLI_listbase_clear(&seqn->channels); + SEQ_channels_duplicate(&seqn->channels, &seq->channels); } else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; @@ -686,6 +699,10 @@ static bool seq_write_data_cb(Sequence *seq, void *userdata) } SEQ_modifier_blend_write(writer, &seq->modifiers); + + LISTBASE_FOREACH (SeqTimelineChannel *, channel, &seq->channels) { + BLO_write_struct(writer, SeqTimelineChannel, channel); + } return true; } @@ -753,6 +770,8 @@ static bool seq_read_data_cb(Sequence *seq, void *user_data) } SEQ_modifier_blend_read_data(reader, &seq->modifiers); + + BLO_read_list(reader, &seq->channels); return true; } void SEQ_blend_read(BlendDataReader *reader, ListBase *seqbase) diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 2f76b6240cf..d678518e3b0 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -31,6 +31,7 @@ #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" #include "SEQ_transform.h" @@ -91,7 +92,10 @@ int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_ return 1; } -static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute) +static void seq_update_muting_recursive(ListBase *channels, + ListBase *seqbasep, + Sequence *metaseq, + int mute) { Sequence *seq; int seqmute; @@ -99,7 +103,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i /* For sound we go over full meta tree to update muted state, * since sound is played outside of evaluating the imbufs. */ for (seq = seqbasep->first; seq; seq = seq->next) { - seqmute = (mute || (seq->flag & SEQ_MUTE)); + seqmute = (mute || SEQ_render_is_muted(channels, seq)); if (seq->type == SEQ_TYPE_META) { /* if this is the current meta sequence, unmute because @@ -108,7 +112,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i seqmute = 0; } - seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute); + seq_update_muting_recursive(&seq->channels, &seq->seqbase, metaseq, seqmute); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { if (seq->scene_sound) { @@ -125,10 +129,10 @@ void SEQ_edit_update_muting(Editing *ed) MetaStack *ms = ed->metastack.last; if (ms) { - seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1); + seq_update_muting_recursive(&ed->channels, &ed->seqbase, ms->parseq, 1); } else { - seq_update_muting_recursive(&ed->seqbase, NULL, 0); + seq_update_muting_recursive(&ed->channels, &ed->seqbase, NULL, 0); } } } diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index ec908dcdc93..06571b7ad43 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -20,6 +20,7 @@ #include "DNA_sound_types.h" #include "IMB_imbuf.h" +#include "SEQ_channels.h" #include "SEQ_iterator.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" @@ -321,6 +322,7 @@ int SEQ_time_find_next_prev_edit(Scene *scene, const bool do_unselected) { Editing *ed = SEQ_editing_get(scene); + ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; int dist, best_dist, best_frame = timeline_frame; @@ -338,7 +340,7 @@ int SEQ_time_find_next_prev_edit(Scene *scene, for (seq = ed->seqbasep->first; seq; seq = seq->next) { int i; - if (do_skip_mute && (seq->flag & SEQ_MUTE)) { + if (do_skip_mute && SEQ_render_is_muted(channels, seq)) { continue; } @@ -442,7 +444,7 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect) if (rect->xmax < seq->enddisp + 1) { rect->xmax = seq->enddisp + 1; } - if (rect->ymax < seq->machine + 2) { + if (rect->ymax < seq->machine) { rect->ymax = seq->machine + 2; } } diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index ddf75f3d664..618fed079f4 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -17,6 +17,7 @@ #include "BKE_sound.h" #include "SEQ_animation.h" +#include "SEQ_channels.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -391,6 +392,12 @@ void SEQ_transform_offset_after_frame(Scene *scene, } } +bool SEQ_transform_is_locked(ListBase *channels, Sequence *seq) +{ + SeqTimelineChannel *channel = SEQ_channel_get_by_index(channels, seq->machine); + return seq->flag & SEQ_LOCK || SEQ_channel_is_locked(channel); +} + void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2]) { r_mirror[0] = 1.0f; diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 0c37fb11c04..da422c4228f 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -24,6 +24,7 @@ #include "BKE_scene.h" #include "SEQ_animation.h" +#include "SEQ_channels.h" #include "SEQ_edit.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -380,7 +381,8 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) { - const Editing *ed = scene->ed; + Editing *ed = scene->ed; + ListBase *channels = SEQ_channels_displayed_get(ed); const Sequence *seq, *best_seq = NULL; int best_machine = -1; @@ -389,7 +391,7 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) } for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->flag & SEQ_MUTE || !SEQ_time_strip_intersects_frame(seq, frame)) { + if (SEQ_render_is_muted(channels, seq) || !SEQ_time_strip_intersects_frame(seq, frame)) { continue; } /* Only use strips that generate an image, not ones that combine |