diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index ad67aee1a3f..a114f33b088 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -674,7 +674,7 @@ const bTheme U_theme_default = { .meta = RGBA(0x5b4d91ff), .text_strip = RGBA(0x824c8fff), .color_strip = RGBA(0x8f8f8fff), - .active_strip = RGBA(0xd9d9d9ff), + .active_strip = RGBA(0xffffffff), .selected_strip = RGBA(0xff8f0dff), .gp_vertex_size = 3, .gp_vertex_select = RGBA(0xff8500ff), diff --git a/scripts/presets/interface_theme/Blender_Light.xml b/scripts/presets/interface_theme/Blender_Light.xml index 4f6b8147258..e27746ff8a1 100644 --- a/scripts/presets/interface_theme/Blender_Light.xml +++ b/scripts/presets/interface_theme/Blender_Light.xml @@ -823,7 +823,7 @@ meta_strip="#5b4d91" mask_strip="#8f5656" text_strip="#824c8f" - active_strip="#d9d9d9" + active_strip="#ffffff" selected_strip="#ff6a00" frame_current="#5680c2" time_scrub_background="#292929e6" diff --git a/source/blender/editors/include/UI_interface_icons.hh b/source/blender/editors/include/UI_interface_icons.hh index 3741ab9e24e..2b59d602ab1 100644 --- a/source/blender/editors/include/UI_interface_icons.hh +++ b/source/blender/editors/include/UI_interface_icons.hh @@ -113,6 +113,14 @@ void UI_icon_draw_ex(float x, bool mono_border, const IconTextOverlay *text_overlay); +/** + * Draw an monochrome icon into a given coordinate rectangle. The rectangle is used as-is, + * and the icon image fills it. Icon is tinted with indicated color. If icon + * is not found or the icon type is not monochrome, the function does nothing. + */ +void UI_icon_draw_mono_rect( + float x, float y, float width, float height, int icon_id, const uchar color[4]); + void UI_icons_free(); void UI_icons_free_drawinfo(void *drawinfo); diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index 6450b5eed91..c0539777410 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -1650,7 +1650,6 @@ static void icon_draw_rect(float x, float y, int w, int h, - float /*aspect*/, int rw, int rh, const uint8_t *rect, @@ -2014,8 +2013,7 @@ static void icon_draw_size(float x, const ImBuf *ibuf = static_cast(icon->obj); GPU_blend(GPU_BLEND_ALPHA_PREMULT); - icon_draw_rect( - x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->byte_buffer.data, alpha, desaturate); + icon_draw_rect(x, y, w, h, ibuf->x, ibuf->y, ibuf->byte_buffer.data, alpha, desaturate); GPU_blend(GPU_BLEND_ALPHA); } else if (di->type == ICON_TYPE_VECTOR) { @@ -2055,7 +2053,7 @@ static void icon_draw_size(float x, } GPU_blend(GPU_BLEND_ALPHA_PREMULT); - icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->byte_buffer.data, alpha, desaturate); + icon_draw_rect(x, y, w, h, w, h, ibuf->byte_buffer.data, alpha, desaturate); GPU_blend(GPU_BLEND_ALPHA); } else if (di->type == ICON_TYPE_EVENT) { @@ -2125,7 +2123,7 @@ static void icon_draw_size(float x, return; } - icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate); + icon_draw_rect(x, y, w, h, iimg->w, iimg->h, iimg->rect, alpha, desaturate); } else if (di->type == ICON_TYPE_PREVIEW) { PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : @@ -2144,7 +2142,6 @@ static void icon_draw_size(float x, y, w, h, - aspect, pi->w[size], pi->h[size], reinterpret_cast(pi->rect[size]), @@ -2696,6 +2693,35 @@ void UI_icon_draw_ex(float x, text_overlay); } +void UI_icon_draw_mono_rect( + float x, float y, float width, float height, int icon_id, const uchar color[4]) +{ + Icon *icon = BKE_icon_get(icon_id); + if (icon == nullptr) { + return; + } + DrawInfo *di = icon_ensure_drawinfo(icon); + if (di->type != ICON_TYPE_MONO_TEXTURE) { + return; + } + + float fcolor[4]; + straight_uchar_to_premul_float(fcolor, color); + + icon_draw_texture(x, + y, + width, + height, + di->data.texture.x, + di->data.texture.y, + di->data.texture.w, + di->data.texture.h, + fcolor[3], + fcolor, + false, + nullptr); +} + void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, const int icon_indicator_number) { diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc index 8aaf633feb4..b7e2f6b276c 100644 --- a/source/blender/editors/interface/view2d.cc +++ b/source/blender/editors/interface/view2d.cc @@ -2156,7 +2156,7 @@ void UI_view2d_text_cache_draw(ARegion *region) } if (col_pack_prev != v2s->col.pack) { - BLF_color3ubv(font_id, v2s->col.ub); + BLF_color4ubv(font_id, v2s->col.ub); col_pack_prev = v2s->col.pack; } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.hh b/source/blender/editors/space_sequencer/sequencer_intern.hh index fd74384edad..bf3ba25959b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.hh +++ b/source/blender/editors/space_sequencer/sequencer_intern.hh @@ -41,7 +41,6 @@ struct Editing; struct ListBase; #define DEFAULT_IMG_STRIP_LENGTH 25 /* XXX arbitrary but ok for now. */ -#define OVERLAP_ALPHA 180 namespace blender::ed::seq { diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc index 9ee44ae9d7f..720091d3421 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc @@ -20,6 +20,7 @@ #include "BIF_glutil.hh" +#include "SEQ_channels.hh" #include "SEQ_relations.hh" #include "SEQ_render.hh" #include "SEQ_sequencer.hh" @@ -464,6 +465,9 @@ void draw_seq_strip_thumbnail(View2D *v2d, return; } + Editing *ed = SEQ_editing_get(scene); + ListBase *channels = ed ? SEQ_channels_displayed_get(ed) : nullptr; + const float thumb_height = y2 - y1; seq_get_thumb_image_dimensions( seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height); @@ -479,7 +483,6 @@ void draw_seq_strip_thumbnail(View2D *v2d, } float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur); - float thumb_x_end; GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq); /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent @@ -490,7 +493,7 @@ void draw_seq_strip_thumbnail(View2D *v2d, /* Start drawing. */ while (timeline_frame < upper_thumb_bound) { - thumb_x_end = timeline_frame + thumb_width; + float thumb_x_end = timeline_frame + thumb_width; clipped = false; /* Checks to make sure that thumbs are loaded only when in view and within the confines of the @@ -510,20 +513,17 @@ void draw_seq_strip_thumbnail(View2D *v2d, if (thumb_x_end > (upper_thumb_bound)) { thumb_x_end = upper_thumb_bound; clipped = true; - if (thumb_x_end - timeline_frame < 1) { - break; - } } float zoom_x = thumb_width / image_width; float zoom_y = thumb_height / image_height; - float cropx_min = (cut_off / pixelx) / (zoom_y / pixely); - float cropx_max = ((thumb_x_end - timeline_frame) / pixelx) / (zoom_y / pixely); - if (cropx_max == (thumb_x_end - timeline_frame)) { - cropx_max = cropx_max + 1; + int cropx_min = int((cut_off / pixelx) / (zoom_y / pixely)); + int cropx_max = int(((thumb_x_end - timeline_frame) / pixelx) / (zoom_y / pixely)); + if (cropx_max < 1) { + break; } - BLI_rcti_init(&crop, int(cropx_min), int(cropx_max), 0, int(image_height) - 1); + BLI_rcti_init(&crop, cropx_min, cropx_max - 1, 0, int(image_height) - 1); /* Get the image. */ ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); @@ -548,19 +548,21 @@ void draw_seq_strip_thumbnail(View2D *v2d, break; } - /* Transparency on overlap. */ - if (seq->flag & SEQ_OVERLAP) { + /* Transparency on mute. */ + bool muted = channels ? SEQ_render_is_muted(channels, seq) : false; + if (muted) { + const uchar alpha = 120; GPU_blend(GPU_BLEND_ALPHA); if (ibuf->byte_buffer.data) { uchar *buf = ibuf->byte_buffer.data; for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) { - buf[3] = OVERLAP_ALPHA; + buf[3] = alpha; } } else if (ibuf->float_buffer.data) { float *buf = ibuf->float_buffer.data; for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) { - buf[3] = (OVERLAP_ALPHA / 255.0f); + buf[3] = (alpha / 255.0f); } } } diff --git a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc index 84e580b2476..c43fe4c9ca7 100644 --- a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc @@ -1,4 +1,5 @@ /* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. + * SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -48,6 +49,7 @@ #include "SEQ_transform.hh" #include "SEQ_utils.hh" +#include "UI_interface_icons.hh" #include "UI_resources.hh" #include "UI_view2d.hh" @@ -67,6 +69,8 @@ #define SEQ_HANDLE_SIZE 8.0f #define MUTE_ALPHA 120 +constexpr float MISSING_ICON_SIZE = 16.0f; + struct StripDrawContext { Sequence *seq; /* Strip boundary in timeline space. Content start/end is clamped by left/right handle. */ @@ -82,6 +86,7 @@ struct StripDrawContext { bool is_active_strip; bool is_single_image; /* Strip has single frame of content. */ bool show_strip_color_tag; + bool missing_data_block; }; struct TimelineDrawContext { @@ -177,6 +182,25 @@ static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext threshold; } +static bool meta_strip_has_missing_data(const Sequence *seq) +{ + if (seq->type != SEQ_TYPE_META) { + return false; + } + + const ListBase *seqbase = &seq->seqbase; + if (!seqbase || BLI_listbase_is_empty(seqbase)) { + return false; + } + + LISTBASE_FOREACH (const Sequence *, sub, seqbase) { + if (!SEQ_sequence_has_source(sub)) { + return true; + } + } + return false; +} + static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequence *seq) { StripDrawContext strip_ctx; @@ -211,6 +235,7 @@ static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequenc strip_ctx.handle_width = sequence_handle_size_get_clamped(ctx->scene, seq, ctx->pixelx); strip_ctx.show_strip_color_tag = (ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); + strip_ctx.missing_data_block = !SEQ_sequence_has_source(seq) || meta_strip_has_missing_data(seq); if (strip_ctx.can_draw_text_overlay) { strip_ctx.strip_content_top = strip_ctx.top - min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely); @@ -570,14 +595,14 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw return; } - Scene *scene = timeline_ctx->scene; + const Scene *scene = timeline_ctx->scene; uchar col[4]; int chan_min = MAXSEQ; int chan_max = 0; int chan_range = 0; - float draw_range = strip_ctx->top - strip_ctx->bottom; + float draw_range = strip_ctx->strip_content_top - strip_ctx->bottom; float draw_height; Editing *ed = SEQ_editing_get(scene); @@ -635,6 +660,12 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw col[3] = 196; } + if (!SEQ_sequence_has_source(seq)) { + col[0] = 112; + col[1] = 0; + col[2] = 0; + } + /* Clamp within parent sequence strip bounds. */ if (x1_chan < strip_ctx->left_handle) { x1_chan = strip_ctx->left_handle; @@ -667,7 +698,7 @@ static void draw_seq_handle(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, const short direction) { - Sequence *seq = strip_ctx->seq; + const Sequence *seq = strip_ctx->seq; if (SEQ_transform_is_locked(timeline_ctx->channels, seq)) { return; } @@ -745,17 +776,16 @@ static void draw_seq_handle(TimelineDrawContext *timeline_ctx, } } +/* Strip border, and outline for selected/active strips. */ static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) { - Sequence *seq = strip_ctx->seq; + const Sequence *seq = strip_ctx->seq; + const bool selected = seq->flag & SELECT; - /* Get the color for the outline. */ + /* Outline color. */ uchar col[4]; - if (strip_ctx->is_active_strip && (seq->flag & SELECT)) { - UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col); - } - else if (seq->flag & SELECT) { - UI_GetThemeColor3ubv(TH_SEQ_SELECTED, col); + if (selected) { + UI_GetThemeColor3ubv(strip_ctx->is_active_strip ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col); } else { /* Color for unselected strips is a bit darker than the background. */ @@ -765,12 +795,9 @@ static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawC /* Outline while translating strips: * - Slightly lighter. - * - Red when overlapping with other strips. - */ + * - Red when overlapping with other strips. */ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene); - if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT) && - overlap_mode != SEQ_OVERLAP_OVERWRITE) - { + if ((G.moving & G_TRANSFORM_SEQ) && selected && overlap_mode != SEQ_OVERLAP_OVERWRITE) { if (seq->flag & SEQ_OVERLAP) { col[0] = 255; col[1] = col[2] = 33; @@ -780,44 +807,35 @@ static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawC } } - /* 2px wide outline for selected strips: draw as four quads. */ - if (seq->flag & SELECT) { - float delta_x = timeline_ctx->pixelx; - float delta_y = timeline_ctx->pixely * 2; + /* Selected outline: 2px wide outline, plus 1px wide background inset. */ + const float x0 = strip_ctx->left_handle; + const float x1 = strip_ctx->right_handle; + const float y0 = strip_ctx->bottom; + const float y1 = strip_ctx->top; + if (selected) { + const float dx = timeline_ctx->pixelx; + const float dy = timeline_ctx->pixely; - /* Left */ - timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x, - strip_ctx->bottom, - strip_ctx->left_handle + delta_x, - strip_ctx->top, - col); - /* Bottom */ - timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x, - strip_ctx->bottom, - strip_ctx->right_handle + delta_x, - strip_ctx->bottom + delta_y, - col); - /* Right */ - timeline_ctx->quads->add_quad(strip_ctx->right_handle - delta_x, - strip_ctx->bottom, - strip_ctx->right_handle + delta_x, - strip_ctx->top, - col); - /* Top */ - timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x, - strip_ctx->top - delta_y, - strip_ctx->right_handle + delta_x, - strip_ctx->top, - col); + /* Left, right, bottom, top. */ + timeline_ctx->quads->add_quad(x0 - dx, y0, x0 + dx, y1, col); + timeline_ctx->quads->add_quad(x1 - dx, y0, x1 + dx, y1, col); + timeline_ctx->quads->add_quad(x0, y0, x1, y0 + dy * 2, col); + timeline_ctx->quads->add_quad(x0, y1 - dy * 2, x1, y1, col); + + /* Inset. */ + UI_GetThemeColor3ubv(TH_BACK, col); + timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x0 + dx * 2, y1 - dy * 2, col); + timeline_ctx->quads->add_quad(x1 - dx * 2, y0 + dy * 2, x1 - dx, y1 - dy * 2, col); + timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x1 - dx, y0 + dy * 3, col); + timeline_ctx->quads->add_quad(x0 + dx, y1 - dy * 3, x1 - dx, y1 - dy * 2, col); } else { - /* 1px wide outline for unselected strips. */ - timeline_ctx->quads->add_wire_quad( - strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top, col); + /* Thin wireframe outline for unselected strips. */ + timeline_ctx->quads->add_wire_quad(x0, y0, x1, y1, col); } } -static const char *draw_seq_text_get_name(Sequence *seq) +static const char *draw_seq_text_get_name(const Sequence *seq) { const char *name = seq->name + 2; if (name[0] == '\0') { @@ -826,7 +844,7 @@ static const char *draw_seq_text_get_name(Sequence *seq) return name; } -static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_maxncpy) +static void draw_seq_text_get_source(const Sequence *seq, char *r_source, size_t source_maxncpy) { *r_source = '\0'; @@ -888,7 +906,7 @@ static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx char *r_overlay_string, size_t overlay_string_len) { - Sequence *seq = strip_ctx->seq; + const Sequence *seq = strip_ctx->seq; const char *text_sep = " | "; const char *text_array[5]; @@ -923,6 +941,95 @@ static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i); } +static void get_strip_text_color(const TimelineDrawContext *ctx, + const StripDrawContext *strip, + uchar r_col[4]) +{ + /* Text: 75% opacity, fully opaque when selected/active. */ + const Sequence *seq = strip->seq; + const bool active_or_selected = (seq->flag & SELECT) || strip->is_active_strip; + if (active_or_selected) { + UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, r_col); + r_col[3] = 255; + } + else { + r_col[0] = r_col[1] = r_col[2] = 224; + r_col[3] = 192; + } + + /* Muted strips: gray color, reduce opacity. */ + if (SEQ_render_is_muted(ctx->channels, seq)) { + r_col[0] = r_col[1] = r_col[2] = 192; + r_col[3] *= 0.66f; + } +} + +static void draw_icon_centered(TimelineDrawContext &ctx, + const rctf &rect, + int icon_id, + const uchar color[4]) +{ + const float icon_size_x = MISSING_ICON_SIZE * ctx.pixelx * UI_SCALE_FAC; + const float icon_size_y = MISSING_ICON_SIZE * ctx.pixely * UI_SCALE_FAC; + if (BLI_rctf_size_x(&rect) * 1.1f < icon_size_x || BLI_rctf_size_y(&rect) * 1.1f < icon_size_y) { + return; + } + + UI_icon_draw_mono_rect(BLI_rctf_cent_x(&rect) - icon_size_x * 0.5f, + BLI_rctf_cent_y(&rect) - icon_size_y * 0.5f, + icon_size_x, + icon_size_y, + icon_id, + color); +} + +static void draw_strip_icons(TimelineDrawContext *timeline_ctx, + const blender::Vector &strips) +{ + timeline_ctx->quads->draw(); + GPU_blend(GPU_BLEND_ALPHA); + + UI_icon_draw_cache_begin(); + + const float icon_size_x = MISSING_ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC; + + for (const StripDrawContext &strip : strips) { + if (!strip.missing_data_block) { + continue; + } + + /* Draw icon in the title bar area. */ + if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 && !strip.strip_is_too_small && + strip.can_draw_text_overlay) + { + uchar col[4]; + get_strip_text_color(timeline_ctx, &strip, col); + + float icon_indent = 2.0f * strip.handle_width - 4 * timeline_ctx->pixelx * UI_SCALE_FAC; + rctf rect; + rect.xmin = max_ff(strip.left_handle, timeline_ctx->v2d->cur.xmin) + icon_indent; + rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x); + rect.ymin = strip.strip_content_top; + rect.ymax = strip.top; + draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col); + } + + /* Draw icon in center of content. */ + if (strip.can_draw_strip_content && strip.seq->type != SEQ_TYPE_META) { + rctf rect; + rect.xmin = strip.left_handle + strip.handle_width; + rect.xmax = strip.right_handle - strip.handle_width; + rect.ymin = strip.bottom; + rect.ymax = strip.strip_content_top; + uchar col[4] = {112, 0, 0, 255}; + draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col); + } + } + + UI_icon_draw_cache_end(); + GPU_blend(GPU_BLEND_NONE); +} + /* Draw info text on a sequence strip. */ static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) @@ -945,30 +1052,23 @@ static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, return; } - /* White text for the active strip. */ uchar col[4]; - col[0] = col[1] = col[2] = strip_ctx->is_active_strip ? 255 : 10; - col[3] = 255; - - /* Make the text duller when the strip is muted. */ - if (SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) { - if (strip_ctx->is_active_strip) { - UI_GetColorPtrShade3ubv(col, col, -70); - } - else { - UI_GetColorPtrShade3ubv(col, col, 15); - } - } + get_strip_text_color(timeline_ctx, strip_ctx, col); float text_margin = 2.0f * strip_ctx->handle_width; rctf rect; - rect.xmin = strip_ctx->left_handle + 2.0f * strip_ctx->handle_width; - rect.xmax = strip_ctx->right_handle - 2.0f * strip_ctx->handle_width; + rect.xmin = strip_ctx->left_handle + text_margin; + rect.xmax = strip_ctx->right_handle - text_margin; rect.ymax = strip_ctx->top; /* Depending on the vertical space, draw text on top or in the center of strip. */ rect.ymin = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom : strip_ctx->strip_content_top; - CLAMP(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax); + rect.xmin = max_ff(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin); + if (strip_ctx->missing_data_block) { + rect.xmin += MISSING_ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC; + } + rect.xmin = min_ff(rect.xmin, timeline_ctx->v2d->cur.xmax); + CLAMP(rect.xmax, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax); UI_view2d_text_cache_add_rectf( @@ -978,7 +1078,7 @@ static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) { - Sequence *seq = strip_ctx->seq; + const Sequence *seq = strip_ctx->seq; if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) { return; } @@ -991,8 +1091,8 @@ static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, return; } - Scene *scene = timeline_ctx->scene; - ListBase *channels = timeline_ctx->channels; + const Scene *scene = timeline_ctx->scene; + const ListBase *channels = timeline_ctx->channels; uchar col[4], blend_col[4]; color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col); @@ -1032,23 +1132,19 @@ static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, } } -static uchar mute_overlap_alpha_factor_get(const ListBase *channels, const Sequence *seq) +static uchar mute_alpha_factor_get(const ListBase *channels, const Sequence *seq) { /* Draw muted strips semi-transparent. */ if (SEQ_render_is_muted(channels, seq)) { return MUTE_ALPHA; } - /* Draw background semi-transparent when overlapping strips. */ - if (seq->flag & SEQ_OVERLAP) { - return OVERLAP_ALPHA; - } return 255; } static void draw_strip_color_band(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) { - Sequence *seq = strip_ctx->seq; + const Sequence *seq = strip_ctx->seq; if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (seq->type != SEQ_TYPE_COLOR)) { return; } @@ -1056,7 +1152,7 @@ static void draw_strip_color_band(TimelineDrawContext *timeline_ctx, SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; uchar col[4]; rgb_float_to_uchar(col, colvars->col); - col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, seq); + col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq); timeline_ctx->quads->add_quad(strip_ctx->left_handle, strip_ctx->bottom, @@ -1076,12 +1172,17 @@ static void draw_strip_color_band(TimelineDrawContext *timeline_ctx, static void draw_strip_background(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) { - Scene *scene = timeline_ctx->scene; - Sequence *seq = strip_ctx->seq; + const Scene *scene = timeline_ctx->scene; + const Sequence *seq = strip_ctx->seq; uchar col[4]; color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col); - col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, seq); + col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq); + /* Muted strips: turn almost gray. */ + if (col[3] == MUTE_ALPHA) { + uchar muted_color[3] = {128, 128, 128}; + UI_GetColorPtrBlendShade3ubv(col, muted_color, col, 0.8f, 0); + } /* Draw the main strip body. */ float x1 = strip_ctx->is_single_image ? strip_ctx->left_handle : strip_ctx->content_start; @@ -1132,7 +1233,7 @@ static void draw_seq_transition_strip_half(TimelineDrawContext *timeline_ctx, } } - col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, strip_ctx->seq); + col[3] = mute_alpha_factor_get(timeline_ctx->channels, strip_ctx->seq); float tri[3][2]; @@ -1179,12 +1280,12 @@ static void draw_seq_locked(TimelineDrawContext *timeline_ctx, immUniform1i("size1", 8); immUniform1i("size2", 4); - for (const StripDrawContext &strip_ctx : strips) { - if (!SEQ_transform_is_locked(timeline_ctx->channels, strip_ctx.seq)) { + for (const StripDrawContext &strip : strips) { + if (!SEQ_transform_is_locked(timeline_ctx->channels, strip.seq)) { continue; } - immRectf(pos, strip_ctx.left_handle, strip_ctx.bottom, strip_ctx.right_handle, strip_ctx.top); + immRectf(pos, strip.left_handle, strip.bottom, strip.right_handle, strip.strip_content_top); } immUnbindProgram(); @@ -1194,15 +1295,27 @@ static void draw_seq_locked(TimelineDrawContext *timeline_ctx, static void draw_seq_invalid(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx) { - if (SEQ_sequence_has_source(strip_ctx->seq)) { + if (!strip_ctx->missing_data_block) { return; } - uchar color[4] = {255, 0, 0, 230}; - timeline_ctx->quads->add_quad(strip_ctx->left_handle, - strip_ctx->top, - strip_ctx->right_handle, - strip_ctx->strip_content_top, - color); + /* Do not tint title area for muted strips; we want to see gray for them. */ + if (!SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) { + uchar col_top[4] = {112, 0, 0, 230}; + timeline_ctx->quads->add_quad(strip_ctx->left_handle, + strip_ctx->top, + strip_ctx->right_handle, + strip_ctx->strip_content_top, + col_top); + } + /* Do not tint content area for meta strips; we want to display children. */ + if (strip_ctx->seq->type != SEQ_TYPE_META) { + uchar col_main[4] = {64, 0, 0, 230}; + timeline_ctx->quads->add_quad(strip_ctx->left_handle, + strip_ctx->strip_content_top, + strip_ctx->right_handle, + strip_ctx->bottom, + col_main); + } } /** @@ -1422,6 +1535,8 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx, return; } + UI_view2d_view_ortho(timeline_ctx->v2d); + /* Draw parts of strips below thumbnails. */ GPU_blend(GPU_BLEND_ALPHA); for (const StripDrawContext &strip_ctx : strips) { @@ -1451,6 +1566,7 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx, for (const StripDrawContext &strip_ctx : strips) { draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx); draw_seq_waveform_overlay(timeline_ctx, &strip_ctx); + draw_seq_invalid(timeline_ctx, &strip_ctx); } timeline_ctx->quads->draw(); GPU_blend(GPU_BLEND_NONE); @@ -1461,15 +1577,27 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx, /* Draw the rest. */ GPU_blend(GPU_BLEND_ALPHA); for (const StripDrawContext &strip_ctx : strips) { - draw_seq_invalid(timeline_ctx, &strip_ctx); draw_effect_inputs_highlight(timeline_ctx, &strip_ctx); draw_multicam_highlight(timeline_ctx, &strip_ctx); draw_seq_solo_highlight(timeline_ctx, &strip_ctx); draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_LEFTHANDLE); draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_RIGHTHANDLE); draw_seq_outline(timeline_ctx, &strip_ctx); + draw_seq_text_overlay(timeline_ctx, &strip_ctx); } + + /* Draw icons separately (different shader). */ + draw_strip_icons(timeline_ctx, strips); + timeline_ctx->quads->draw(); + + /* Draw text labels with a drop shadow. */ + const int font_id = BLF_default(); + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 3, blender::float4{0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); + UI_view2d_text_cache_draw(timeline_ctx->region); + BLF_disable(font_id, BLF_SHADOW); GPU_blend(GPU_BLEND_NONE); } @@ -1483,18 +1611,6 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx) visible_strips_ordered_get(timeline_ctx, unselected, selected); draw_seq_strips(timeline_ctx, unselected); draw_seq_strips(timeline_ctx, selected); - - /* Draw text overlay parts in the opposite order: first selected set, then - * unselected (UI_view2d_text_cache_add_rectf adds new text in front of - * other entries!). This is to make sure selected strip labels are on top - * of others while they are being dragged over. */ - for (const StripDrawContext &strip_ctx : selected) { - draw_seq_text_overlay(timeline_ctx, &strip_ctx); - } - for (const StripDrawContext &strip_ctx : unselected) { - draw_seq_text_overlay(timeline_ctx, &strip_ctx); - } - UI_view2d_text_cache_draw(timeline_ctx->region); } static void draw_timeline_sfra_efra(TimelineDrawContext *ctx) @@ -1570,7 +1686,7 @@ static void draw_timeline_sfra_efra(TimelineDrawContext *ctx) } struct CacheDrawData { - View2D *v2d; + const View2D *v2d; float stripe_ofs_y; float stripe_ht; int cache_flag; @@ -1651,8 +1767,8 @@ static void draw_cache_stripe(const Scene *scene, static void draw_cache_background(const bContext *C, CacheDrawData *draw_data) { using blender::uchar4; - Scene *scene = CTX_data_scene(C); - View2D *v2d = UI_view2d_fromcontext(C); + const Scene *scene = CTX_data_scene(C); + const View2D *v2d = UI_view2d_fromcontext(C); const uchar4 bg_final{255, 102, 51, 25}; const uchar4 bg_raw{255, 25, 5, 25}; @@ -1694,7 +1810,7 @@ static void draw_cache_background(const bContext *C, CacheDrawData *draw_data) static void draw_cache_view(const bContext *C) { Scene *scene = CTX_data_scene(C); - View2D *v2d = UI_view2d_fromcontext(C); + const View2D *v2d = UI_view2d_fromcontext(C); if ((scene->ed->cache_flag & SEQ_CACHE_VIEW_ENABLE) == 0) { return; diff --git a/source/blender/sequencer/SEQ_transform.hh b/source/blender/sequencer/SEQ_transform.hh index 2e8d8d50e3d..75d1ca5d11e 100644 --- a/source/blender/sequencer/SEQ_transform.hh +++ b/source/blender/sequencer/SEQ_transform.hh @@ -71,7 +71,7 @@ void SEQ_transform_offset_after_frame(Scene *scene, * Check if `seq` can be moved. * This function also checks `SeqTimelineChannel` flag. */ -bool SEQ_transform_is_locked(ListBase *channels, Sequence *seq); +bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq); /* Image transformation. */ diff --git a/source/blender/sequencer/SEQ_utils.hh b/source/blender/sequencer/SEQ_utils.hh index 405c9df8e30..038aaf145af 100644 --- a/source/blender/sequencer/SEQ_utils.hh +++ b/source/blender/sequencer/SEQ_utils.hh @@ -17,7 +17,7 @@ struct Sequence; struct StripElem; void SEQ_sequence_base_unique_name_recursive(Scene *scene, ListBase *seqbasep, Sequence *seq); -const char *SEQ_sequence_give_name(Sequence *seq); +const char *SEQ_sequence_give_name(const Sequence *seq); ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **channels, int *r_offset); const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame); /** diff --git a/source/blender/sequencer/intern/strip_transform.cc b/source/blender/sequencer/intern/strip_transform.cc index b7950efcb1b..588c15041a0 100644 --- a/source/blender/sequencer/intern/strip_transform.cc +++ b/source/blender/sequencer/intern/strip_transform.cc @@ -599,7 +599,7 @@ void SEQ_transform_offset_after_frame(Scene *scene, } } -bool SEQ_transform_is_locked(ListBase *channels, Sequence *seq) +bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq) { const SeqTimelineChannel *channel = SEQ_channel_get_by_index(channels, seq->machine); return seq->flag & SEQ_LOCK || diff --git a/source/blender/sequencer/intern/utils.cc b/source/blender/sequencer/intern/utils.cc index 3823b15ab28..1cd5e250d57 100644 --- a/source/blender/sequencer/intern/utils.cc +++ b/source/blender/sequencer/intern/utils.cc @@ -161,7 +161,7 @@ static const char *give_seqname_by_type(int type) } } -const char *SEQ_sequence_give_name(Sequence *seq) +const char *SEQ_sequence_give_name(const Sequence *seq) { const char *name = give_seqname_by_type(seq->type);