Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/intern/scene.cc65
-rw-r--r--source/blender/blenloader/intern/versioning_280.c7
-rw-r--r--source/blender/blenloader/intern/versioning_300.c62
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc7
-rw-r--r--source/blender/blenloader/intern/versioning_common.h1
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c8
-rw-r--r--source/blender/editors/screen/screen_context.c5
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c359
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_edit.c59
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c57
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c18
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h31
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c21
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c37
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c13
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c25
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c8
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h17
-rw-r--r--source/blender/makesdna/DNA_space_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c106
-rw-r--r--source/blender/makesrna/intern/rna_space.c3
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c1
-rw-r--r--source/blender/sequencer/CMakeLists.txt2
-rw-r--r--source/blender/sequencer/SEQ_channels.h34
-rw-r--r--source/blender/sequencer/SEQ_iterator.h3
-rw-r--r--source/blender/sequencer/SEQ_render.h5
-rw-r--r--source/blender/sequencer/SEQ_transform.h7
-rw-r--r--source/blender/sequencer/intern/channels.c83
-rw-r--r--source/blender/sequencer/intern/effects.c8
-rw-r--r--source/blender/sequencer/intern/iterator.c10
-rw-r--r--source/blender/sequencer/intern/prefetch.c13
-rw-r--r--source/blender/sequencer/intern/render.c31
-rw-r--r--source/blender/sequencer/intern/render.h4
-rw-r--r--source/blender/sequencer/intern/sequencer.c19
-rw-r--r--source/blender/sequencer/intern/strip_edit.c14
-rw-r--r--source/blender/sequencer/intern/strip_time.c6
-rw-r--r--source/blender/sequencer/intern/strip_transform.c7
-rw-r--r--source/blender/sequencer/intern/utils.c6
42 files changed, 1079 insertions, 99 deletions
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 = &region->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 = &region->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(&region->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 = &region->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(&region->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(&region->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