Blender V5.0
sequencer_view.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_bounds_types.hh"
10#include "BLI_listbase.h"
11#include "BLI_math_base.h"
12#include "BLI_math_vector.hh"
13#include "BLI_utildefines.h"
14
15#include "DNA_scene_types.h"
16
17#include "BKE_context.hh"
18#include "BKE_scene.hh"
19
20#include "WM_api.hh"
21#include "WM_types.hh"
22
23#include "RNA_define.hh"
24
25#include "UI_view2d.hh"
26
27#include "SEQ_sequencer.hh"
28#include "SEQ_time.hh"
29#include "SEQ_transform.hh"
30
31/* For menu, popup, icons, etc. */
32#include "ED_anim_api.hh"
33#include "ED_markers.hh"
34#include "ED_screen.hh"
35#include "ED_sequencer.hh"
36#include "ED_time_scrub_ui.hh"
37#include "ED_util_imbuf.hh"
38
39/* Own include. */
40#include "sequencer_intern.hh"
41
42namespace blender::ed::vse {
43
44/* -------------------------------------------------------------------- */
47
49{
50 /* Identifiers. */
51 ot->name = "Sample Color";
52 ot->idname = "SEQUENCER_OT_sample";
53 ot->description = "Use mouse to sample color in current frame";
54
55 /* API callbacks. */
56 ot->invoke = ED_imbuf_sample_invoke;
58 ot->cancel = ED_imbuf_sample_cancel;
60
61 /* Flags. */
62 ot->flag = OPTYPE_BLOCKING;
63
64 /* Not implemented. */
65 PropertyRNA *prop;
66 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
69}
70
72
73/* -------------------------------------------------------------------- */
76void SEQ_get_timeline_region_padding(const bContext *C, float *r_pad_top, float *r_pad_bottom)
77{
78 *r_pad_top = UI_TIME_SCRUB_MARGIN_Y;
79 const SpaceSeq *sseq = CTX_wm_space_seq(C);
80 if (sseq->flag & SEQ_SHOW_OVERLAY && sseq->cache_overlay.flag & SEQ_CACHE_SHOW &&
82 {
83 *r_pad_top += UI_TIME_CACHE_MARGIN_Y;
84 }
85
89}
90
92{
93 /* Calculate and add margin to the view.
94 * This is needed so that the focused strips are not occluded by the scrub area or other
95 * overlays.
96 */
97 float pad_top, pad_bottom;
98 SEQ_get_timeline_region_padding(C, &pad_top, &pad_bottom);
99
100 ARegion *region = CTX_wm_region(C);
101 BLI_rctf_pad_y(view_box, region->winy, pad_bottom, pad_top);
102}
103
105{
106 ARegion *region = CTX_wm_region(C);
107 rctf box;
108
109 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
111 const Editing *ed = seq::editing_get(scene);
112
113 seq::timeline_init_boundbox(scene, &box);
115 /* Use meta strip range instead of scene. */
116 if (ms != nullptr) {
117 box.xmin = ms->disp_range[0] - 1;
118 box.xmax = ms->disp_range[1] + 1;
119 }
121
123
124 UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
125 return OPERATOR_FINISHED;
126}
127
129{
130 /* Identifiers. */
131 ot->name = "Frame All";
132 ot->idname = "SEQUENCER_OT_view_all";
133 ot->description = "View all the strips in the sequencer";
134
135 /* API callbacks. */
138
139 /* Flags. */
140 ot->flag = OPTYPE_REGISTER;
141}
142
144
145/* -------------------------------------------------------------------- */
148
150{
151 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
152 ANIM_center_frame(C, smooth_viewtx);
153
154 return OPERATOR_FINISHED;
155}
156
158{
159 /* Identifiers. */
160 ot->name = "Go to Current Frame";
161 ot->idname = "SEQUENCER_OT_view_frame";
162 ot->description = "Move the view to the current frame";
163
164 /* API callbacks. */
167
168 /* Flags. */
169 ot->flag = 0;
170}
171
173
174/* For frame all/selected operators, when we are in preview region
175 * with histogram/waveform display mode, frame the extents of the scope. */
177{
178 if (!region || region->regiontype != RGN_TYPE_PREVIEW) {
179 return false;
180 }
181 SpaceSeq *sseq = CTX_wm_space_seq(C);
182 if (!sseq) {
183 return false;
184 }
185 const View2D *v2d = UI_view2d_fromcontext(C);
186 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
187
188 if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) {
189 /* For histogram scope, use extents of the histogram. */
190 const vse::ScopeHistogram &hist = sseq->runtime->scopes.histogram;
191 if (hist.data.is_empty()) {
192 return false;
193 }
194
195 rctf cur_new = v2d->tot;
196 const float val_max = ScopeHistogram::bin_to_float(math::reduce_max(hist.max_bin));
197 cur_new.xmax = cur_new.xmin + (cur_new.xmax - cur_new.xmin) * val_max;
198
199 /* Add some padding around whole histogram. */
200 BLI_rctf_scale(&cur_new, 1.1f);
201
202 UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
203 return true;
204 }
205
207 /* For waveform/parade scopes, use 3.0 display space Y value as bounds
208 * for HDR content. */
209 const bool hdr = sseq->runtime->scopes.last_ibuf_float;
210 rctf cur_new = v2d->tot;
211 if (hdr) {
212 const float val_max = 3.0f;
213 cur_new.ymax = cur_new.ymin + (cur_new.ymax - cur_new.ymin) * val_max;
214 }
215 UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
216 return true;
217 }
218
219 return false;
220}
221
222/* -------------------------------------------------------------------- */
225
227{
228 SpaceSeq *sseq = CTX_wm_space_seq(C);
229 bScreen *screen = CTX_wm_screen(C);
230 ScrArea *area = CTX_wm_area(C);
231
233 return OPERATOR_FINISHED;
234 }
235
236#if 0
237 ARegion *region = CTX_wm_region(C);
239#endif
241
242 v2d->cur = v2d->tot;
244 UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY);
245
246#if 0
247 /* Like zooming on an image view. */
248 float zoomX, zoomY;
249 int width, height, imgwidth, imgheight;
250
251 width = region->winx;
252 height = region->winy;
253
254 seq_reset_imageofs(sseq);
255
256 BKE_render_resolution(&scene->r, false, &imgwidth, &imgheight);
257
258 /* Apply aspect, doesn't need to be that accurate. */
259 imgwidth = int(imgwidth * (scene->r.xasp / scene->r.yasp));
260
261 if (((imgwidth >= width) || (imgheight >= height)) && ((width > 0) && (height > 0))) {
262 /* Find the zoom value that will fit the image in the image space. */
263 zoomX = float(width) / float(imgwidth);
264 zoomY = float(height) / float(imgheight);
265 sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY;
266
267 sseq->zoom = 1.0f / power_of_2(1 / min_ff(zoomX, zoomY));
268 }
269 else {
270 sseq->zoom = 1.0f;
271 }
272#endif
273
274 sseq->flag |= SEQ_ZOOM_TO_FIT;
275
277 return OPERATOR_FINISHED;
278}
279
281{
282 /* Identifiers. */
283 ot->name = "Frame All";
284 ot->idname = "SEQUENCER_OT_view_all_preview";
285 ot->description = "Zoom preview to fit in the area";
286
287 /* API callbacks. */
290
291 /* Flags. */
292 ot->flag = OPTYPE_REGISTER;
293}
294
296
297/* -------------------------------------------------------------------- */
300
302{
303 const Scene *scene = CTX_data_sequencer_scene(C);
304 const RenderData *rd = &scene->r;
306
307 float ratio = RNA_float_get(op->ptr, "ratio");
308
309 int winx, winy;
310 BKE_render_resolution(rd, false, &winx, &winy);
311
312 float facx = (BLI_rcti_size_x(&v2d->mask) + 1) / float(winx);
313 float facy = (BLI_rcti_size_y(&v2d->mask) + 1) / float(winy);
314
315 BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f));
316
318
320
321 return OPERATOR_FINISHED;
322}
323
325{
326 /* Identifiers. */
327 ot->name = "Sequencer View Zoom Ratio";
328 ot->idname = "SEQUENCER_OT_view_zoom_ratio";
329 ot->description = "Change zoom ratio of sequencer preview";
330
331 /* API callbacks. */
334
335 /* Properties. */
336 RNA_def_float(ot->srna,
337 "ratio",
338 1.0f,
339 -FLT_MAX,
340 FLT_MAX,
341 "Ratio",
342 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
343 -FLT_MAX,
344 FLT_MAX);
345}
346
348
349/* -------------------------------------------------------------------- */
352
355 rctf *rect)
356{
358 scene, strips, true);
359
360 rect->xmin = box.min[0];
361 rect->xmax = box.max[0];
362 rect->ymin = box.min[1];
363 rect->ymax = box.max[1];
364
365 float minsize = min_ff(BLI_rctf_size_x(rect), BLI_rctf_size_y(rect));
366
367 /* If the size of the strip is smaller than a pixel, add padding to prevent division by zero. */
368 if (minsize < 1.0f) {
369 BLI_rctf_pad(rect, 20.0f, 20.0f);
370 }
371
372 /* Add padding. */
373 BLI_rctf_scale(rect, 1.1f);
374}
375
378 rctf *rect)
379{
380 const Scene *scene = CTX_data_sequencer_scene(C);
381 int xmin = MAXFRAME * 2;
382 int xmax = -MAXFRAME * 2;
383 int ymin = seq::MAX_CHANNELS + 1;
384 int ymax = 0;
385 int xmargin = scene->frames_per_second();
386
387 for (Strip *strip : strips) {
388 xmin = min_ii(xmin, seq::time_left_handle_frame_get(scene, strip));
389 xmax = max_ii(xmax, seq::time_right_handle_frame_get(scene, strip));
390
391 ymin = min_ii(ymin, strip->channel);
392 /* "+1" because each channel has a thickness of 1. */
393 ymax = max_ii(ymax, strip->channel + 1);
394 }
395
396 xmax += xmargin;
397 xmin -= xmargin;
398
399 float orig_height = BLI_rctf_size_y(rect);
400 rctf new_viewport;
401
402 new_viewport.xmin = xmin;
403 new_viewport.xmax = xmax;
404
405 new_viewport.ymin = ymin;
406 new_viewport.ymax = ymax;
407
408 SEQ_add_timeline_region_padding(C, &new_viewport);
409
410 /* Y axis should only zoom out if needed, never zoom in. */
411 if (orig_height > BLI_rctf_size_y(&new_viewport)) {
412 /* Get the current max/min channel we can display. */
413 const Editing *ed = seq::editing_get(scene);
414 rctf box;
417 float timeline_ymin = box.ymin;
418 float timeline_ymax = box.ymax;
419
420 if (orig_height > timeline_ymax - timeline_ymin) {
421 /* Only apply the x axis movement, we can't align the viewport any better
422 * on the y-axis if we are zoomed out further than the current timeline bounds. */
423 rect->xmin = new_viewport.xmin;
424 rect->xmax = new_viewport.xmax;
425 return;
426 }
427
428 float ymid = BLI_rctf_cent_y(&new_viewport);
429
430 new_viewport.ymin = ymid - (orig_height / 2.0f);
431 new_viewport.ymax = ymid + (orig_height / 2.0f);
432
433 if (new_viewport.ymin < timeline_ymin) {
434 new_viewport.ymin = timeline_ymin;
435 new_viewport.ymax = new_viewport.ymin + orig_height;
436 }
437 else if (new_viewport.ymax > timeline_ymax) {
438 new_viewport.ymax = timeline_ymax;
439 new_viewport.ymin = new_viewport.ymax - orig_height;
440 }
441 }
442 *rect = new_viewport;
443}
444
446{
448 ARegion *region = CTX_wm_region(C);
450 rctf cur_new = v2d->cur;
451
452 if (view_frame_preview_scope(C, op, region)) {
453 return OPERATOR_FINISHED;
454 }
455
457 if (strips.is_empty()) {
458 return OPERATOR_CANCELLED;
459 }
460
462 return OPERATOR_CANCELLED;
463 }
464
465 if (region && region->regiontype == RGN_TYPE_PREVIEW) {
466 seq_view_collection_rect_preview(scene, strips, &cur_new);
467 }
468 else {
469 seq_view_collection_rect_timeline(C, strips, &cur_new);
470 }
471
472 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
473 UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
474
475 return OPERATOR_FINISHED;
476}
477
479{
480 /* Identifiers. */
481 ot->name = "Frame Selected";
482 ot->idname = "SEQUENCER_OT_view_selected";
483 ot->description = "Zoom the sequencer on the selected strips";
484
485 /* API callbacks. */
488
489 /* Flags. */
490 ot->flag = OPTYPE_REGISTER;
491}
492
494
495/* -------------------------------------------------------------------- */
498
500{
503
504 rctf rect;
505
506 /* Convert coordinates of rect to 'tot' rect coordinates. */
508 UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
509
510 rect.xmin /= fabsf(BLI_rctf_size_x(&v2d->tot));
511 rect.ymin /= fabsf(BLI_rctf_size_y(&v2d->tot));
512
513 rect.xmax /= fabsf(BLI_rctf_size_x(&v2d->tot));
514 rect.ymax /= fabsf(BLI_rctf_size_y(&v2d->tot));
515
516 rect.xmin += 0.5f;
517 rect.xmax += 0.5f;
518 rect.ymin += 0.5f;
519 rect.ymax += 0.5f;
520
521 CLAMP(rect.xmin, 0.0f, 1.0f);
522 CLAMP(rect.ymin, 0.0f, 1.0f);
523 CLAMP(rect.xmax, 0.0f, 1.0f);
524 CLAMP(rect.ymax, 0.0f, 1.0f);
525
526 scene->ed->overlay_frame_rect = rect;
527
529
530 return OPERATOR_FINISHED;
531}
532
534{
535 /* Identifiers. */
536 ot->name = "Border Offset View";
537 ot->idname = "SEQUENCER_OT_view_ghost_border";
538 ot->description = "Set the boundaries of the border used for offset view";
539
540 /* API callbacks. */
541 ot->invoke = WM_gesture_box_invoke;
543 ot->modal = WM_gesture_box_modal;
545 ot->cancel = WM_gesture_box_cancel;
546
547 /* Flags. */
548 ot->flag = 0;
549
550 /* Properties. */
552}
553
555
556} // namespace blender::ed::vse
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float power_of_2(float f)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
void BLI_rctf_pad_y(struct rctf *rect, float boundary_size, float pad_min, float pad_max)
Definition rct.cc:689
void BLI_rctf_scale(rctf *rect, float scale)
Definition rct.cc:677
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition rct.cc:637
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
void BLI_rctf_resize(struct rctf *rect, float x, float y)
Definition rct.cc:657
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define CLAMP(a, b, c)
#define ELEM(...)
#define MAXFRAME
@ RGN_TYPE_PREVIEW
@ SEQ_CACHE_SHOW
@ SEQ_CACHE_SHOW_FINAL_OUT
@ SEQ_DRAW_IMG_RGBPARADE
@ SEQ_DRAW_IMG_HISTOGRAM
@ SEQ_DRAW_IMG_WAVEFORM
@ SEQ_ZOOM_TO_FIT
@ SEQ_SHOW_OVERLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
bool ED_operator_sequencer_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
wmOperatorStatus ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_imbuf_sample_poll(bContext *C)
wmOperatorStatus ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
@ PROP_PIXEL
Definition RNA_types.hh:248
#define C
Definition RandGen.cpp:29
void UI_view2d_smooth_view(const bContext *C, ARegion *region, const rctf *cur, int smooth_viewtx)
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
Definition view2d.cc:865
#define V2D_LOCK_COPY
Definition UI_view2d.hh:85
#define UI_MARKER_MARGIN_Y
Definition UI_view2d.hh:478
#define V2D_SCROLL_HANDLE_HEIGHT
Definition UI_view2d.hh:67
#define UI_TIME_CACHE_MARGIN_Y
Definition UI_view2d.hh:480
void UI_view2d_curRect_changed(const bContext *C, View2D *v2d)
Definition view2d.cc:833
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:479
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1855
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1675
#define ND_SEQUENCER
Definition WM_types.hh:437
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_REGISTER
Definition WM_types.hh:180
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:768
ListBase * ED_sequencer_context_get_markers(const bContext *C)
nullptr float
void SEQUENCER_OT_view_all_preview(wmOperatorType *ot)
static wmOperatorStatus view_ghost_border_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_view_frame_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_selected(wmOperatorType *ot)
void SEQUENCER_OT_view_frame(wmOperatorType *ot)
void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
static wmOperatorStatus sequencer_view_all_exec(bContext *C, wmOperator *op)
blender::VectorSet< Strip * > selected_strips_from_context(bContext *C)
void SEQUENCER_OT_sample(wmOperatorType *ot)
void SEQ_get_timeline_region_padding(const bContext *C, float *r_pad_top, float *r_pad_bottom)
bool sequencer_editing_initialized_and_active(bContext *C)
static wmOperatorStatus sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_all(wmOperatorType *ot)
static wmOperatorStatus sequencer_view_all_preview_exec(bContext *C, wmOperator *op)
static void seq_view_collection_rect_timeline(const bContext *C, blender::Span< Strip * > strips, rctf *rect)
bool sequencer_view_preview_only_poll(const bContext *C)
void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
static bool view_frame_preview_scope(bContext *C, wmOperator *op, ARegion *region)
bool sequencer_view_has_preview_poll(bContext *C)
void SEQ_add_timeline_region_padding(const bContext *C, rctf *view_box)
static void seq_view_collection_rect_preview(Scene *scene, blender::Span< Strip * > strips, rctf *rect)
static wmOperatorStatus sequencer_view_selected_exec(bContext *C, wmOperator *op)
T reduce_max(const VecBase< T, Size > &a)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
Bounds< float2 > image_transform_bounding_box_from_collection(Scene *scene, blender::Span< Strip * > strips, bool apply_rotation)
void timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *r_rect)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
int time_left_handle_frame_get(const Scene *, const Strip *strip)
MetaStack * meta_stack_active_get(const Editing *ed)
Definition sequencer.cc:454
constexpr int MAX_CHANNELS
void timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
void timeline_init_boundbox(const Scene *scene, rctf *r_rect)
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:433
#define fabsf
#define ceilf
float RNA_float_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
#define FLT_MAX
Definition stdcycles.h:14
rctf overlay_frame_rect
struct Editing * ed
struct RenderData r
struct SequencerCacheOverlay cache_overlay
SpaceSeq_Runtime * runtime
float xmax
float xmin
float ymax
float ymin
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
int WM_operator_smooth_viewtx_get(const wmOperator *op)