Blender V4.5
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_utildefines.h"
12
13#include "DNA_scene_types.h"
14
15#include "BKE_context.hh"
16#include "BKE_scene.hh"
17
18#include "WM_api.hh"
19#include "WM_types.hh"
20
21#include "RNA_define.hh"
22
23#include "UI_view2d.hh"
24
25#include "SEQ_sequencer.hh"
26#include "SEQ_time.hh"
27#include "SEQ_transform.hh"
28
29/* For menu, popup, icons, etc. */
30#include "ED_anim_api.hh"
31#include "ED_markers.hh"
32#include "ED_screen.hh"
33#include "ED_sequencer.hh"
34#include "ED_time_scrub_ui.hh"
35#include "ED_util_imbuf.hh"
36
37/* Own include. */
38#include "sequencer_intern.hh"
39
40namespace blender::ed::vse {
41
42/* -------------------------------------------------------------------- */
45
47{
48 /* Identifiers. */
49 ot->name = "Sample Color";
50 ot->idname = "SEQUENCER_OT_sample";
51 ot->description = "Use mouse to sample color in current frame";
52
53 /* API callbacks. */
54 ot->invoke = ED_imbuf_sample_invoke;
56 ot->cancel = ED_imbuf_sample_cancel;
58
59 /* Flags. */
60 ot->flag = OPTYPE_BLOCKING;
61
62 /* Not implemented. */
63 PropertyRNA *prop;
64 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
67}
68
70
71/* -------------------------------------------------------------------- */
74void SEQ_get_timeline_region_padding(const bContext *C, float *r_pad_top, float *r_pad_bottom)
75{
76 *r_pad_top = UI_TIME_SCRUB_MARGIN_Y;
77 const SpaceSeq *sseq = CTX_wm_space_seq(C);
78 if (sseq->flag & SEQ_SHOW_OVERLAY && sseq->cache_overlay.flag & SEQ_CACHE_SHOW &&
80 {
81 *r_pad_top += UI_TIME_CACHE_MARGIN_Y;
82 }
83
86}
87
89{
90 /* Calculate and add margin to the view.
91 * This is needed so that the focused strips are not occluded by the scrub area or other
92 * overlays.
93 */
94 float pad_top, pad_bottom;
95 SEQ_get_timeline_region_padding(C, &pad_top, &pad_bottom);
96
97 ARegion *region = CTX_wm_region(C);
98 BLI_rctf_pad_y(view_box, region->winy, pad_bottom, pad_top);
99}
100
102{
103 ARegion *region = CTX_wm_region(C);
104 rctf box;
105
106 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
107 Scene *scene = CTX_data_scene(C);
108 const Editing *ed = seq::editing_get(scene);
109
110 seq::timeline_init_boundbox(scene, &box);
112 /* Use meta strip range instead of scene. */
113 if (ms != nullptr) {
114 box.xmin = ms->disp_range[0] - 1;
115 box.xmax = ms->disp_range[1] + 1;
116 }
118
120
121 UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
122 return OPERATOR_FINISHED;
123}
124
126{
127 /* Identifiers. */
128 ot->name = "Frame All";
129 ot->idname = "SEQUENCER_OT_view_all";
130 ot->description = "View all the strips in the sequencer";
131
132 /* API callbacks. */
135
136 /* Flags. */
137 ot->flag = OPTYPE_REGISTER;
138}
139
141
142/* -------------------------------------------------------------------- */
145
147{
148 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
149 ANIM_center_frame(C, smooth_viewtx);
150
151 return OPERATOR_FINISHED;
152}
153
155{
156 /* Identifiers. */
157 ot->name = "Go to Current Frame";
158 ot->idname = "SEQUENCER_OT_view_frame";
159 ot->description = "Move the view to the current frame";
160
161 /* API callbacks. */
164
165 /* Flags. */
166 ot->flag = 0;
167}
168
170
171/* -------------------------------------------------------------------- */
174
176{
177 SpaceSeq *sseq = CTX_wm_space_seq(C);
178 bScreen *screen = CTX_wm_screen(C);
179 ScrArea *area = CTX_wm_area(C);
180#if 0
181 ARegion *region = CTX_wm_region(C);
182 Scene *scene = CTX_data_scene(C);
183#endif
185
186 v2d->cur = v2d->tot;
188 UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY);
189
190#if 0
191 /* Like zooming on an image view. */
192 float zoomX, zoomY;
193 int width, height, imgwidth, imgheight;
194
195 width = region->winx;
196 height = region->winy;
197
198 seq_reset_imageofs(sseq);
199
200 BKE_render_resolution(&scene->r, false, &imgwidth, &imgheight);
201
202 /* Apply aspect, doesn't need to be that accurate. */
203 imgwidth = int(imgwidth * (scene->r.xasp / scene->r.yasp));
204
205 if (((imgwidth >= width) || (imgheight >= height)) && ((width > 0) && (height > 0))) {
206 /* Find the zoom value that will fit the image in the image space. */
207 zoomX = float(width) / float(imgwidth);
208 zoomY = float(height) / float(imgheight);
209 sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY;
210
211 sseq->zoom = 1.0f / power_of_2(1 / min_ff(zoomX, zoomY));
212 }
213 else {
214 sseq->zoom = 1.0f;
215 }
216#endif
217
218 sseq->flag |= SEQ_ZOOM_TO_FIT;
219
221 return OPERATOR_FINISHED;
222}
223
225{
226 /* Identifiers. */
227 ot->name = "Frame All";
228 ot->idname = "SEQUENCER_OT_view_all_preview";
229 ot->description = "Zoom preview to fit in the area";
230
231 /* API callbacks. */
234
235 /* Flags. */
236 ot->flag = OPTYPE_REGISTER;
237}
238
240
241/* -------------------------------------------------------------------- */
244
246{
247 const RenderData *rd = &CTX_data_scene(C)->r;
249
250 float ratio = RNA_float_get(op->ptr, "ratio");
251
252 int winx, winy;
253 BKE_render_resolution(rd, false, &winx, &winy);
254
255 float facx = BLI_rcti_size_x(&v2d->mask) / float(winx);
256 float facy = BLI_rcti_size_y(&v2d->mask) / float(winy);
257
258 BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f));
259
261
263
264 return OPERATOR_FINISHED;
265}
266
268{
269 /* Identifiers. */
270 ot->name = "Sequencer View Zoom Ratio";
271 ot->idname = "SEQUENCER_OT_view_zoom_ratio";
272 ot->description = "Change zoom ratio of sequencer preview";
273
274 /* API callbacks. */
277
278 /* Properties. */
279 RNA_def_float(ot->srna,
280 "ratio",
281 1.0f,
282 -FLT_MAX,
283 FLT_MAX,
284 "Ratio",
285 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
286 -FLT_MAX,
287 FLT_MAX);
288}
289
291
292/* -------------------------------------------------------------------- */
295
298 rctf *rect)
299{
301 scene, strips, true);
302
303 rect->xmin = box.min[0];
304 rect->xmax = box.max[0];
305 rect->ymin = box.min[1];
306 rect->ymax = box.max[1];
307
308 float minsize = min_ff(BLI_rctf_size_x(rect), BLI_rctf_size_y(rect));
309
310 /* If the size of the strip is smaller than a pixel, add padding to prevent division by zero. */
311 if (minsize < 1.0f) {
312 BLI_rctf_pad(rect, 20.0f, 20.0f);
313 }
314
315 /* Add padding. */
316 BLI_rctf_scale(rect, 1.1f);
317}
318
321 rctf *rect)
322{
323 const Scene *scene = CTX_data_scene(C);
324 int xmin = MAXFRAME * 2;
325 int xmax = -MAXFRAME * 2;
326 int ymin = seq::MAX_CHANNELS + 1;
327 int ymax = 0;
328 int xmargin = FPS;
329
330 for (Strip *strip : strips) {
331 xmin = min_ii(xmin, seq::time_left_handle_frame_get(scene, strip));
332 xmax = max_ii(xmax, seq::time_right_handle_frame_get(scene, strip));
333
334 ymin = min_ii(ymin, strip->channel);
335 /* "+1" because each channel has a thickness of 1. */
336 ymax = max_ii(ymax, strip->channel + 1);
337 }
338
339 xmax += xmargin;
340 xmin -= xmargin;
341
342 float orig_height = BLI_rctf_size_y(rect);
343 rctf new_viewport;
344
345 new_viewport.xmin = xmin;
346 new_viewport.xmax = xmax;
347
348 new_viewport.ymin = ymin;
349 new_viewport.ymax = ymax;
350
351 SEQ_add_timeline_region_padding(C, &new_viewport);
352
353 /* Y axis should only zoom out if needed, never zoom in. */
354 if (orig_height > BLI_rctf_size_y(&new_viewport)) {
355 /* Get the current max/min channel we can display. */
356 const Editing *ed = seq::editing_get(scene);
357 rctf box;
360 float timeline_ymin = box.ymin;
361 float timeline_ymax = box.ymax;
362
363 if (orig_height > timeline_ymax - timeline_ymin) {
364 /* Only apply the x axis movement, we can't align the viewport any better
365 * on the y-axis if we are zoomed out further than the current timeline bounds. */
366 rect->xmin = new_viewport.xmin;
367 rect->xmax = new_viewport.xmax;
368 return;
369 }
370
371 float ymid = BLI_rctf_cent_y(&new_viewport);
372
373 new_viewport.ymin = ymid - (orig_height / 2.0f);
374 new_viewport.ymax = ymid + (orig_height / 2.0f);
375
376 if (new_viewport.ymin < timeline_ymin) {
377 new_viewport.ymin = timeline_ymin;
378 new_viewport.ymax = new_viewport.ymin + orig_height;
379 }
380 else if (new_viewport.ymax > timeline_ymax) {
381 new_viewport.ymax = timeline_ymax;
382 new_viewport.ymin = new_viewport.ymax - orig_height;
383 }
384 }
385 *rect = new_viewport;
386}
387
389{
390 Scene *scene = CTX_data_scene(C);
391 ARegion *region = CTX_wm_region(C);
394 rctf cur_new = v2d->cur;
395
396 if (strips.is_empty()) {
397 return OPERATOR_CANCELLED;
398 }
399
401 return OPERATOR_CANCELLED;
402 }
403
404 if (region && region->regiontype == RGN_TYPE_PREVIEW) {
405 seq_view_collection_rect_preview(scene, strips, &cur_new);
406 }
407 else {
408 seq_view_collection_rect_timeline(C, strips, &cur_new);
409 }
410
411 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
412 UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
413
414 return OPERATOR_FINISHED;
415}
416
418{
419 /* Identifiers. */
420 ot->name = "Frame Selected";
421 ot->idname = "SEQUENCER_OT_view_selected";
422 ot->description = "Zoom the sequencer on the selected strips";
423
424 /* API callbacks. */
427
428 /* Flags. */
429 ot->flag = OPTYPE_REGISTER;
430}
431
433
434/* -------------------------------------------------------------------- */
437
439{
440 Scene *scene = CTX_data_scene(C);
442
443 rctf rect;
444
445 /* Convert coordinates of rect to 'tot' rect coordinates. */
447 UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
448
449 rect.xmin /= fabsf(BLI_rctf_size_x(&v2d->tot));
450 rect.ymin /= fabsf(BLI_rctf_size_y(&v2d->tot));
451
452 rect.xmax /= fabsf(BLI_rctf_size_x(&v2d->tot));
453 rect.ymax /= fabsf(BLI_rctf_size_y(&v2d->tot));
454
455 rect.xmin += 0.5f;
456 rect.xmax += 0.5f;
457 rect.ymin += 0.5f;
458 rect.ymax += 0.5f;
459
460 CLAMP(rect.xmin, 0.0f, 1.0f);
461 CLAMP(rect.ymin, 0.0f, 1.0f);
462 CLAMP(rect.xmax, 0.0f, 1.0f);
463 CLAMP(rect.ymax, 0.0f, 1.0f);
464
465 scene->ed->overlay_frame_rect = rect;
466
468
469 return OPERATOR_FINISHED;
470}
471
473{
474 /* Identifiers. */
475 ot->name = "Border Offset View";
476 ot->idname = "SEQUENCER_OT_view_ghost_border";
477 ot->description = "Set the boundaries of the border used for offset view";
478
479 /* API callbacks. */
480 ot->invoke = WM_gesture_box_invoke;
482 ot->modal = WM_gesture_box_modal;
484 ot->cancel = WM_gesture_box_cancel;
485
486 /* Flags. */
487 ot->flag = 0;
488
489 /* Properties. */
491}
492
494
495} // namespace blender::ed::vse
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
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 FPS
#define MAXFRAME
@ RGN_TYPE_PREVIEW
@ SEQ_CACHE_SHOW
@ SEQ_CACHE_SHOW_FINAL_OUT
@ SEQ_ZOOM_TO_FIT
@ SEQ_SHOW_OVERLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:714
bool ED_operator_sequencer_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
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:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
@ PROP_PIXEL
Definition RNA_types.hh:236
#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:470
#define V2D_SCROLL_HANDLE_HEIGHT
Definition UI_view2d.hh:67
#define UI_TIME_CACHE_MARGIN_Y
Definition UI_view2d.hh:472
void UI_view2d_curRect_changed(const bContext *C, View2D *v2d)
Definition view2d.cc:833
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:471
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1854
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1674
#define ND_SEQUENCER
Definition WM_types.hh:434
#define NC_SCENE
Definition WM_types.hh:375
@ 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:696
ListBase * ED_context_get_markers(const bContext *C)
#define ceilf(x)
#define fabsf(x)
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 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)
bool sequencer_view_has_preview_poll(bContext *C)
void SEQ_add_timeline_region_padding(const bContext *C, rctf *view_box)
static wmOperatorStatus sequencer_view_all_preview_exec(bContext *C, wmOperator *)
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)
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:272
int time_left_handle_frame_get(const Scene *, const Strip *strip)
MetaStack * meta_stack_active_get(const Editing *ed)
Definition sequencer.cc:452
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:420
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
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:4226
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)