/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2012 Blender Foundation. All rights reserved. */ /** \file * \ingroup spseq */ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_scene_types.h" #include "BKE_context.h" #include "WM_api.h" #include "WM_types.h" #include "RNA_define.h" #include "UI_view2d.h" #include "SEQ_iterator.h" #include "SEQ_select.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" #include "SEQ_transform.h" /* For menu, popup, icons, etc. */ #include "ED_anim_api.h" #include "ED_screen.h" #include "ED_time_scrub_ui.h" #include "ED_util_imbuf.h" /* Own include. */ #include "sequencer_intern.h" /* -------------------------------------------------------------------- */ /** \name Sequencer Sample Backdrop Operator * \{ */ void SEQUENCER_OT_sample(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Sample Color"; ot->idname = "SEQUENCER_OT_sample"; ot->description = "Use mouse to sample color in current frame"; /* Api callbacks. */ ot->invoke = ED_imbuf_sample_invoke; ot->modal = ED_imbuf_sample_modal; ot->cancel = ED_imbuf_sample_cancel; ot->poll = ED_imbuf_sample_poll; /* Flags. */ ot->flag = OPTYPE_BLOCKING; /* Not implemented. */ PropertyRNA *prop; prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64); RNA_def_property_subtype(prop, PROP_PIXEL); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } /** \} */ /* -------------------------------------------------------------------- */ /** \name Sequencer Frame All Operator * \{ */ static int sequencer_view_all_exec(bContext *C, wmOperator *op) { ARegion *region = CTX_wm_region(C); rctf box; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); Scene *scene = CTX_data_scene(C); const Editing *ed = SEQ_editing_get(scene); SEQ_timeline_init_boundbox(scene, &box); MetaStack *ms = SEQ_meta_stack_active_get(ed); /* Use meta strip range instead of scene. */ if (ms != NULL) { box.xmin = ms->disp_range[0] - 1; box.xmax = ms->disp_range[1] + 1; } SEQ_timeline_expand_boundbox(SEQ_active_seqbase_get(ed), &box); View2D *v2d = ®ion->v2d; rcti scrub_rect; ED_time_scrub_region_rect_get(region, &scrub_rect); const float pixel_view_size_y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); const float scrub_bar_height = BLI_rcti_size_y(&scrub_rect) * pixel_view_size_y; /* Channel n has range of . */ box.ymax += 1.0f + scrub_bar_height; UI_view2d_smooth_view(C, region, &box, smooth_viewtx); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_all(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Frame All"; ot->idname = "SEQUENCER_OT_view_all"; ot->description = "View all the strips in the sequencer"; /* Api callbacks. */ ot->exec = sequencer_view_all_exec; ot->poll = ED_operator_sequencer_active; /* Flags. */ ot->flag = OPTYPE_REGISTER; } /** \} */ /* -------------------------------------------------------------------- */ /** \name Go to Current Frame Operator * \{ */ static int sequencer_view_frame_exec(bContext *C, wmOperator *op) { const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); ANIM_center_frame(C, smooth_viewtx); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_frame(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Go to Current Frame"; ot->idname = "SEQUENCER_OT_view_frame"; ot->description = "Move the view to the current frame"; /* Api callbacks. */ ot->exec = sequencer_view_frame_exec; ot->poll = ED_operator_sequencer_active; /* Flags. */ ot->flag = 0; } /** \} */ /* -------------------------------------------------------------------- */ /** \name Preview Frame All Operator * \{ */ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceSeq *sseq = CTX_wm_space_seq(C); bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); #if 0 ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); #endif View2D *v2d = UI_view2d_fromcontext(C); v2d->cur = v2d->tot; UI_view2d_curRect_changed(C, v2d); UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY); #if 0 /* Like zooming on an image view. */ float zoomX, zoomY; int width, height, imgwidth, imgheight; width = region->winx; height = region->winy; seq_reset_imageofs(sseq); imgwidth = (scene->r.size * scene->r.xsch) / 100; imgheight = (scene->r.size * scene->r.ysch) / 100; /* Apply aspect, doesn't need to be that accurate. */ imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp)); if (((imgwidth >= width) || (imgheight >= height)) && ((width > 0) && (height > 0))) { /* Find the zoom value that will fit the image in the image space. */ zoomX = ((float)width) / ((float)imgwidth); zoomY = ((float)height) / ((float)imgheight); sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY; sseq->zoom = 1.0f / power_of_2(1 / min_ff(zoomX, zoomY)); } else { sseq->zoom = 1.0f; } #endif sseq->flag |= SEQ_ZOOM_TO_FIT; ED_area_tag_redraw(CTX_wm_area(C)); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_all_preview(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Frame All"; ot->idname = "SEQUENCER_OT_view_all_preview"; ot->description = "Zoom preview to fit in the area"; /* Api callbacks. */ ot->exec = sequencer_view_all_preview_exec; ot->poll = ED_operator_sequencer_active; /* Flags. */ ot->flag = OPTYPE_REGISTER; } /** \} */ /* -------------------------------------------------------------------- */ /** \name Sequencer View Zoom Ratio Operator * \{ */ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op) { RenderData *rd = &CTX_data_scene(C)->r; View2D *v2d = UI_view2d_fromcontext(C); float ratio = RNA_float_get(op->ptr, "ratio"); float winx = (int)(rd->size * rd->xsch) / 100; float winy = (int)(rd->size * rd->ysch) / 100; float facx = BLI_rcti_size_x(&v2d->mask) / winx; float facy = BLI_rcti_size_y(&v2d->mask) / winy; BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f)); ED_region_tag_redraw(CTX_wm_region(C)); UI_view2d_curRect_changed(C, v2d); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Sequencer View Zoom Ratio"; ot->idname = "SEQUENCER_OT_view_zoom_ratio"; ot->description = "Change zoom ratio of sequencer preview"; /* Api callbacks. */ ot->exec = sequencer_view_zoom_ratio_exec; ot->poll = ED_operator_sequencer_active; /* Properties. */ RNA_def_float(ot->srna, "ratio", 1.0f, -FLT_MAX, FLT_MAX, "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX); } /** \} */ /* -------------------------------------------------------------------- */ /** \name Frame Selected Operator * \{ */ static void seq_view_collection_rect_preview(Scene *scene, SeqCollection *strips, rctf *rect) { float min[2], max[2]; SEQ_image_transform_bounding_box_from_collection(scene, strips, true, min, max); rect->xmin = min[0]; rect->xmax = max[0]; rect->ymin = min[1]; rect->ymax = max[1]; float minsize = min_ff(BLI_rctf_size_x(rect), BLI_rctf_size_y(rect)); /* If the size of the strip is smaller than a pixel, add padding to prevent division by zero. */ if (minsize < 1.0f) { BLI_rctf_pad(rect, 20.0f, 20.0f); } /* Add padding. */ BLI_rctf_scale(rect, 1.1f); } static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strips, rctf *rect) { Sequence *seq; int xmin = MAXFRAME * 2; int xmax = -MAXFRAME * 2; int ymin = MAXSEQ + 1; int ymax = 0; int orig_height; int ymid; int ymargin = 1; int xmargin = FPS; SEQ_ITERATOR_FOREACH (seq, strips) { xmin = min_ii(xmin, seq->startdisp); xmax = max_ii(xmax, seq->enddisp); ymin = min_ii(ymin, seq->machine); ymax = max_ii(ymax, seq->machine); } xmax += xmargin; xmin -= xmargin; ymax += ymargin; ymin -= ymargin; orig_height = BLI_rctf_size_y(rect); rect->xmin = xmin; rect->xmax = xmax; rect->ymin = ymin; rect->ymax = ymax; /* Only zoom out vertically. */ if (orig_height > BLI_rctf_size_y(rect)) { ymid = BLI_rctf_cent_y(rect); rect->ymin = ymid - (orig_height / 2); rect->ymax = ymid + (orig_height / 2); } } static int sequencer_view_selected_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ARegion *region = CTX_wm_region(C); SeqCollection *strips = selected_strips_from_context(C); View2D *v2d = UI_view2d_fromcontext(C); rctf cur_new = v2d->cur; if (SEQ_collection_len(strips) == 0) { return OPERATOR_CANCELLED; } if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) { return OPERATOR_CANCELLED; } if (region && region->regiontype == RGN_TYPE_PREVIEW) { seq_view_collection_rect_preview(scene, strips, &cur_new); } else { seq_view_collection_rect_timeline(scene, strips, &cur_new); } const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_selected(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Frame Selected"; ot->idname = "SEQUENCER_OT_view_selected"; ot->description = "Zoom the sequencer on the selected strips"; /* Api callbacks. */ ot->exec = sequencer_view_selected_exec; ot->poll = ED_operator_sequencer_active; /* Flags. */ ot->flag = OPTYPE_REGISTER; } /** \} */ /* -------------------------------------------------------------------- */ /** \name Border Offset View Operator * \{ */ static int view_ghost_border_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); rctf rect; /* Convert coordinates of rect to 'tot' rect coordinates. */ WM_operator_properties_border_to_rctf(op, &rect); UI_view2d_region_to_view_rctf(v2d, &rect, &rect); rect.xmin /= fabsf(BLI_rctf_size_x(&v2d->tot)); rect.ymin /= fabsf(BLI_rctf_size_y(&v2d->tot)); rect.xmax /= fabsf(BLI_rctf_size_x(&v2d->tot)); rect.ymax /= fabsf(BLI_rctf_size_y(&v2d->tot)); rect.xmin += 0.5f; rect.xmax += 0.5f; rect.ymin += 0.5f; rect.ymax += 0.5f; CLAMP(rect.xmin, 0.0f, 1.0f); CLAMP(rect.ymin, 0.0f, 1.0f); CLAMP(rect.xmax, 0.0f, 1.0f); CLAMP(rect.ymax, 0.0f, 1.0f); scene->ed->overlay_frame_rect = rect; WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; } void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Border Offset View"; ot->idname = "SEQUENCER_OT_view_ghost_border"; ot->description = "Set the boundaries of the border used for offset view"; /* Api callbacks. */ ot->invoke = WM_gesture_box_invoke; ot->exec = view_ghost_border_exec; ot->modal = WM_gesture_box_modal; ot->poll = sequencer_view_has_preview_poll; ot->cancel = WM_gesture_box_cancel; /* Flags. */ ot->flag = 0; /* Properties. */ WM_operator_properties_gesture_box(ot); } /** \} */