From e3949cdaa1ccbc074a6cbc4e522ba8e6a48c8008 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Mon, 23 Nov 2020 20:19:29 +0100 Subject: [PATCH 01/16] Add video panning --- src/video_display.cpp | 24 ++++++++++++++++++++++-- src/video_display.h | 9 +++++++++ src/visual_tool_cross.cpp | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 8d85311a6d..73df313ba4 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -113,6 +113,8 @@ VideoDisplay::VideoDisplay(wxToolBar *toolbar, bool freeSize, wxComboBox *zoomBo Bind(wxEVT_LEFT_DCLICK, &VideoDisplay::OnMouseEvent, this); Bind(wxEVT_LEFT_DOWN, &VideoDisplay::OnMouseEvent, this); Bind(wxEVT_LEFT_UP, &VideoDisplay::OnMouseEvent, this); + Bind(wxEVT_MIDDLE_DOWN, &VideoDisplay::OnMouseEvent, this); + Bind(wxEVT_MIDDLE_UP, &VideoDisplay::OnMouseEvent, this); Bind(wxEVT_MOTION, &VideoDisplay::OnMouseEvent, this); Bind(wxEVT_MOUSEWHEEL, &VideoDisplay::OnMouseWheel, this); @@ -191,7 +193,7 @@ void VideoDisplay::Render() try { PositionVideo(); videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height); - E(glViewport(0, std::min(viewport_bottom, 0), videoSize.GetWidth(), videoSize.GetHeight())); + E(glViewport(0, viewport_bottom, videoSize.GetWidth(), videoSize.GetHeight())); E(glMatrixMode(GL_PROJECTION)); E(glLoadIdentity()); @@ -296,6 +298,9 @@ void VideoDisplay::PositionVideo() { } } + viewport_left += pan_x; + viewport_bottom -= pan_y; + if (tool) tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor, viewport_width / scale_factor, viewport_height / scale_factor); @@ -351,8 +356,23 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { last_mouse_pos = mouse_pos = event.GetPosition(); - if (tool) + if (event.GetButton() == wxMOUSE_BTN_MIDDLE) { + if ((panning = event.ButtonDown())) + pan_last_pos = event.GetPosition(); + } + if (panning && event.Dragging()) { + pan_x += event.GetX() - pan_last_pos.X(); + pan_y += event.GetY() - pan_last_pos.Y(); + pan_last_pos = event.GetPosition(); + + PositionVideo(); + } + + if (tool) { + if (pan_y) + event.SetPosition(wxPoint(event.GetX(), event.GetY() - pan_y)); tool->OnMouseEvent(event); + } } void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { diff --git a/src/video_display.h b/src/video_display.h index f0d65edb67..46ed78a690 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -87,6 +87,15 @@ class VideoDisplay final : public wxGLCanvas { /// The current zoom level, where 1.0 = 100% double zoomValue; + /// The last position of the mouse, when dragging + Vector2D pan_last_pos; + /// True if middle mouse button is down, and we should update pan_{x,y} + bool panning = false; + /// The current video pan offset width + int pan_x = 0; + /// The current video pan offset height + int pan_y = 0; + /// The video renderer std::unique_ptr videoOut; diff --git a/src/visual_tool_cross.cpp b/src/visual_tool_cross.cpp index ffbf5329b3..624cd76139 100644 --- a/src/visual_tool_cross.cpp +++ b/src/visual_tool_cross.cpp @@ -69,8 +69,8 @@ void VisualToolCross::Draw() { gl.SetInvert(); gl.SetLineColour(*wxWHITE, 1.0, 1); float lines[] = { - 0.f, mouse_pos.Y(), - video_res.X() + video_pos.X() * 2, mouse_pos.Y(), + video_pos.X(), mouse_pos.Y(), + video_res.X() + video_pos.X(), mouse_pos.Y(), mouse_pos.X(), 0.f, mouse_pos.X(), video_res.Y() + video_pos.Y() * 2 }; From f3d796a3e30912cb1740c1f6da35d5e0c54adc93 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Mon, 23 Nov 2020 20:21:02 +0100 Subject: [PATCH 02/16] Add menu item for resetting the video pan --- src/command/video.cpp | 12 ++++++++++++ src/libresrc/default_menu.json | 1 + src/video_display.cpp | 5 +++++ src/video_display.h | 3 +++ 4 files changed, 21 insertions(+) diff --git a/src/command/video.cpp b/src/command/video.cpp index d3ffaf7fe0..40ffb977b2 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -603,6 +603,17 @@ struct video_opt_autoscroll final : public Command { } }; +struct video_pan_reset final : public validator_video_loaded { + CMD_NAME("video/pan_reset") + STR_MENU("Reset video pan") + STR_DISP("Reset video pan") + STR_HELP("Reset the video pan to the original value") + + void operator()(agi::Context *c) override { + c->videoDisplay->ResetPan(); + } +}; + struct video_play final : public validator_video_loaded { CMD_NAME("video/play") CMD_ICON(button_play) @@ -767,6 +778,7 @@ namespace cmd { reg(agi::make_unique()); reg(agi::make_unique()); reg(agi::make_unique()); + reg(agi::make_unique()); reg(agi::make_unique()); reg(agi::make_unique()); reg(agi::make_unique()); diff --git a/src/libresrc/default_menu.json b/src/libresrc/default_menu.json index b1797836f8..81214dc081 100644 --- a/src/libresrc/default_menu.json +++ b/src/libresrc/default_menu.json @@ -156,6 +156,7 @@ { "submenu" : "main/video/set zoom", "text" : "Set &Zoom" }, { "submenu" : "main/video/override ar", "text" : "Override &AR" }, { "command" : "video/show_overscan" }, + { "command" : "video/pan_reset" }, {}, { "command" : "video/jump" }, { "command" : "video/jump/start" }, diff --git a/src/video_display.cpp b/src/video_display.cpp index 73df313ba4..5107e2b29a 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -398,6 +398,11 @@ void VideoDisplay::OnKeyDown(wxKeyEvent &event) { hotkey::check("Video", con, event); } +void VideoDisplay::ResetPan() { + pan_x = pan_y = 0; + PositionVideo(); +} + void VideoDisplay::SetZoom(double value) { if (value == 0) return; zoomValue = std::max(value, .125); diff --git a/src/video_display.h b/src/video_display.h index 46ed78a690..680873518c 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -169,6 +169,9 @@ class VideoDisplay final : public wxGLCanvas { /// @brief Get the current zoom level double GetZoom() const { return zoomValue; } + /// @brief Reset the video pan + void ResetPan(); + /// Get the last seen position of the mouse in script coordinates Vector2D GetMousePosition() const; From 5f95f76671d352077901960aca1ebd2ee1ca6553 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Mon, 23 Nov 2020 20:31:43 +0100 Subject: [PATCH 03/16] Change tab to spaces --- src/libresrc/default_menu.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libresrc/default_menu.json b/src/libresrc/default_menu.json index 81214dc081..8d2f6c55b9 100644 --- a/src/libresrc/default_menu.json +++ b/src/libresrc/default_menu.json @@ -156,7 +156,7 @@ { "submenu" : "main/video/set zoom", "text" : "Set &Zoom" }, { "submenu" : "main/video/override ar", "text" : "Override &AR" }, { "command" : "video/show_overscan" }, - { "command" : "video/pan_reset" }, + { "command" : "video/pan_reset" }, {}, { "command" : "video/jump" }, { "command" : "video/jump/start" }, From 0ec0f2069591efcb3c2da834be21e151270764f6 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 25 Nov 2020 10:54:37 +0100 Subject: [PATCH 04/16] Fix mouse position bug when videoAr > displayAr Crosshair drawing is broken when videoAr != displayAr --- src/video_display.cpp | 19 +++++++++++-------- src/video_display.h | 2 ++ src/visual_tool.cpp | 4 ++++ src/visual_tool.h | 2 ++ src/visual_tool_cross.cpp | 6 +++--- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 5107e2b29a..7f9a8d5124 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -193,7 +193,7 @@ void VideoDisplay::Render() try { PositionVideo(); videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height); - E(glViewport(0, viewport_bottom, videoSize.GetWidth(), videoSize.GetHeight())); + E(glViewport(0, viewport_bottom_end, videoSize.GetWidth(), videoSize.GetHeight())); E(glMatrixMode(GL_PROJECTION)); E(glLoadIdentity()); @@ -270,8 +270,11 @@ void VideoDisplay::PositionVideo() { auto provider = con->project->VideoProvider(); if (!provider || !IsShownOnScreen()) return; + int client_w, client_h; + GetClientSize(&client_w, &client_h); + viewport_left = 0; - viewport_bottom = GetClientSize().GetHeight() * scale_factor - videoSize.GetHeight(); + viewport_bottom_end = viewport_bottom = client_h * scale_factor - videoSize.GetHeight(); viewport_top = 0; viewport_width = videoSize.GetWidth(); viewport_height = videoSize.GetHeight(); @@ -299,12 +302,15 @@ void VideoDisplay::PositionVideo() { } viewport_left += pan_x; + viewport_top += pan_y; viewport_bottom -= pan_y; + viewport_bottom_end = std::min(viewport_bottom_end, 0); - if (tool) + if (tool) { + tool->SetClientSize(viewport_width, viewport_height); tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor, viewport_width / scale_factor, viewport_height / scale_factor); - + } Render(); } @@ -368,11 +374,8 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { PositionVideo(); } - if (tool) { - if (pan_y) - event.SetPosition(wxPoint(event.GetX(), event.GetY() - pan_y)); + if (tool) tool->OnMouseEvent(event); - } } void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { diff --git a/src/video_display.h b/src/video_display.h index 680873518c..5024421758 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -79,6 +79,8 @@ class VideoDisplay final : public wxGLCanvas { int viewport_width = 0; /// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport int viewport_bottom = 0; + /// The REAL bottom of the viewport; used only for glViewport + int viewport_bottom_end = 0; /// Screen pixels between the bottom of the canvas and the top of the video; used for coordinate space conversion int viewport_top = 0; /// The height of the video in screen pixels diff --git a/src/visual_tool.cpp b/src/visual_tool.cpp index 61d3207226..6465fe2484 100644 --- a/src/visual_tool.cpp +++ b/src/visual_tool.cpp @@ -132,6 +132,10 @@ AssDialogue* VisualToolBase::GetActiveDialogueLine() { return nullptr; } +void VisualToolBase::SetClientSize(int w, int h) { + client_size = Vector2D(w, h); +} + void VisualToolBase::SetDisplayArea(int x, int y, int w, int h) { if (x == video_pos.X() && y == video_pos.Y() && w == video_res.X() && h == video_res.Y()) return; diff --git a/src/visual_tool.h b/src/visual_tool.h index 72eec42249..15d0b007dc 100644 --- a/src/visual_tool.h +++ b/src/visual_tool.h @@ -104,6 +104,7 @@ class VisualToolBase { Vector2D script_res; ///< Script resolution Vector2D video_pos; ///< Top-left corner of the video in the display area Vector2D video_res; ///< Video resolution + Vector2D client_size; ///< The size of the display area const agi::OptionValue *highlight_color_primary_opt; const agi::OptionValue *highlight_color_secondary_opt; @@ -144,6 +145,7 @@ class VisualToolBase { // Stuff called by VideoDisplay virtual void OnMouseEvent(wxMouseEvent &event)=0; virtual void Draw()=0; + virtual void SetClientSize(int w, int h); virtual void SetDisplayArea(int x, int y, int w, int h); virtual void SetToolbar(wxToolBar *) { } virtual ~VisualToolBase() = default; diff --git a/src/visual_tool_cross.cpp b/src/visual_tool_cross.cpp index 624cd76139..87783c616f 100644 --- a/src/visual_tool_cross.cpp +++ b/src/visual_tool_cross.cpp @@ -69,10 +69,10 @@ void VisualToolCross::Draw() { gl.SetInvert(); gl.SetLineColour(*wxWHITE, 1.0, 1); float lines[] = { - video_pos.X(), mouse_pos.Y(), - video_res.X() + video_pos.X(), mouse_pos.Y(), + 0.f, mouse_pos.Y(), + client_size.X(), mouse_pos.Y(), mouse_pos.X(), 0.f, - mouse_pos.X(), video_res.Y() + video_pos.Y() * 2 + mouse_pos.X(), client_size.Y(), }; gl.DrawLines(2, lines, 4); gl.ClearInvert(); From 808ead65bff45d874880a1dde6a69cc79a2f2a7d Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 25 Nov 2020 19:36:05 +0100 Subject: [PATCH 05/16] Fix crosshair drawing I'm not sure about that scale_factor, i don't know how to test that --- src/video_display.cpp | 2 +- src/visual_tool_cross.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 7f9a8d5124..b64964a8a9 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -307,7 +307,7 @@ void VideoDisplay::PositionVideo() { viewport_bottom_end = std::min(viewport_bottom_end, 0); if (tool) { - tool->SetClientSize(viewport_width, viewport_height); + tool->SetClientSize(client_w * scale_factor, client_h * scale_factor); tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor, viewport_width / scale_factor, viewport_height / scale_factor); } diff --git a/src/visual_tool_cross.cpp b/src/visual_tool_cross.cpp index 87783c616f..ae82be7750 100644 --- a/src/visual_tool_cross.cpp +++ b/src/visual_tool_cross.cpp @@ -87,12 +87,12 @@ void VisualToolCross::Draw() { // Place the text in the corner of the cross closest to the center of the video int dx = mouse_pos.X(); int dy = mouse_pos.Y(); - if (dx > video_res.X() / 2) + if (dx > client_size.X() / 2) dx -= tw + 4; else dx += 4; - if (dy < video_res.Y() / 2) + if (dy < client_size.Y() / 2) dy += 3; else dy -= th + 3; From d73dfe9c187e5f3e62a1356463fa5d6868e25fb9 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 25 Nov 2020 19:40:28 +0100 Subject: [PATCH 06/16] Change pan values with the zoom level changes --- src/video_display.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_display.cpp b/src/video_display.cpp index b64964a8a9..6a335f990b 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -408,6 +408,8 @@ void VideoDisplay::ResetPan() { void VideoDisplay::SetZoom(double value) { if (value == 0) return; + pan_x *= value / zoomValue; + pan_y *= value / zoomValue; zoomValue = std::max(value, .125); size_t selIndex = zoomValue / .125 - 1; if (selIndex < zoomBox->GetCount()) From 70ddf3c7f5c6b382c98d73b22c2c414f7b43b8aa Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 25 Nov 2020 19:49:28 +0100 Subject: [PATCH 07/16] Respect min. zoom value when changing pan coords --- src/video_display.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 6a335f990b..8c682799cd 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -408,9 +408,10 @@ void VideoDisplay::ResetPan() { void VideoDisplay::SetZoom(double value) { if (value == 0) return; + value = std::max(value, .125); pan_x *= value / zoomValue; pan_y *= value / zoomValue; - zoomValue = std::max(value, .125); + zoomValue = value; size_t selIndex = zoomValue / .125 - 1; if (selIndex < zoomBox->GetCount()) zoomBox->SetSelection(selIndex); From 4f6836da9c30eb91dfb0405de295d201021f6740 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 21 Apr 2021 00:19:51 +0200 Subject: [PATCH 08/16] Make video zoom different from preview window zoom --- src/command/video.cpp | 10 ++--- src/frame_main.cpp | 4 +- src/project.cpp | 2 +- src/video_display.cpp | 93 +++++++++++++++++++++++++++---------------- src/video_display.h | 13 +++--- 5 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/command/video.cpp b/src/command/video.cpp index 40ffb977b2..a262c0dcc6 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -669,7 +669,7 @@ class video_zoom_100: public validator_video_attached { void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(1.); + c->videoDisplay->SetWindowZoom(1.); } }; @@ -700,7 +700,7 @@ class video_zoom_200: public validator_video_attached { void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(2.); + c->videoDisplay->SetWindowZoom(2.); } }; @@ -718,7 +718,7 @@ class video_zoom_50: public validator_video_attached { void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(.5); + c->videoDisplay->SetWindowZoom(.5); } }; @@ -730,7 +730,7 @@ struct video_zoom_in final : public validator_video_attached { STR_HELP("Zoom video in") void operator()(agi::Context *c) override { - c->videoDisplay->SetZoom(c->videoDisplay->GetZoom() + .125); + c->videoDisplay->SetWindowZoom(c->videoDisplay->GetZoom() + .125); } }; @@ -742,7 +742,7 @@ struct video_zoom_out final : public validator_video_attached { STR_HELP("Zoom video out") void operator()(agi::Context *c) override { - c->videoDisplay->SetZoom(c->videoDisplay->GetZoom() - .125); + c->videoDisplay->SetWindowZoom(c->videoDisplay->GetZoom() - .125); } }; } diff --git a/src/frame_main.cpp b/src/frame_main.cpp index df115b27c4..b37dafefc0 100644 --- a/src/frame_main.cpp +++ b/src/frame_main.cpp @@ -276,9 +276,9 @@ void FrameMain::OnVideoOpen(AsyncVideoProvider *provider) { double zoom = context->videoDisplay->GetZoom(); wxSize windowSize = GetSize(); if (vidx*3*zoom > windowSize.GetX()*4 || vidy*4*zoom > windowSize.GetY()*6) - context->videoDisplay->SetZoom(zoom * .25); + context->videoDisplay->SetWindowZoom(zoom * .25); else if (vidx*3*zoom > windowSize.GetX()*2 || vidy*4*zoom > windowSize.GetY()*3) - context->videoDisplay->SetZoom(zoom * .5); + context->videoDisplay->SetWindowZoom(zoom * .5); SetDisplayMode(1,-1); diff --git a/src/project.cpp b/src/project.cpp index e01dd3749f..26776b370b 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -220,7 +220,7 @@ void Project::LoadUnloadFiles(ProjectProperties properties) { vc->SetAspectRatio(properties.ar_value); else vc->SetAspectRatio(ar_mode); - context->videoDisplay->SetZoom(properties.video_zoom); + context->videoDisplay->SetWindowZoom(properties.video_zoom); } } diff --git a/src/video_display.cpp b/src/video_display.cpp index 8c682799cd..c1b1cfd28b 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -82,19 +82,20 @@ VideoDisplay::VideoDisplay(wxToolBar *toolbar, bool freeSize, wxComboBox *zoomBo : wxGLCanvas(parent, -1, attribList) , autohideTools(OPT_GET("Tool/Visual/Autohide")) , con(c) -, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125) +, windowZoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125) +, videoZoomValue(1) , toolBar(toolbar) , zoomBox(zoomBox) , freeSize(freeSize) , retina_helper(agi::make_unique(this)) , scale_factor(retina_helper->GetScaleFactor()) , scale_factor_connection(retina_helper->AddScaleFactorListener([=](int new_scale_factor) { - double new_zoom = zoomValue * new_scale_factor / scale_factor; + double new_zoom = windowZoomValue * new_scale_factor / scale_factor; scale_factor = new_scale_factor; - SetZoom(new_zoom); + SetWindowZoom(new_zoom); })) { - zoomBox->SetValue(fmt_wx("%g%%", zoomValue * 100.)); + zoomBox->SetValue(fmt_wx("%g%%", windowZoomValue * 100.)); zoomBox->Bind(wxEVT_COMBOBOX, &VideoDisplay::SetZoomFromBox, this); zoomBox->Bind(wxEVT_TEXT_ENTER, &VideoDisplay::SetZoomFromBoxText, this); @@ -193,11 +194,14 @@ void VideoDisplay::Render() try { PositionVideo(); videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height); - E(glViewport(0, viewport_bottom_end, videoSize.GetWidth(), videoSize.GetHeight())); + + int client_w, client_h; + GetClientSize(&client_w, &client_h); + E(glViewport(0, 0, client_w, client_h)); E(glMatrixMode(GL_PROJECTION)); E(glLoadIdentity()); - E(glOrtho(0.0f, videoSize.GetWidth() / scale_factor, videoSize.GetHeight() / scale_factor, 0.0f, -1000.0f, 1000.0f)); + E(glOrtho(0.0f, client_w / scale_factor, client_h / scale_factor, 0.0f, -1000.0f, 1000.0f)); if (OPT_GET("Video/Overscan Mask")->GetBool()) { double ar = con->videoController->GetAspectRatioValue(); @@ -274,7 +278,7 @@ void VideoDisplay::PositionVideo() { GetClientSize(&client_w, &client_h); viewport_left = 0; - viewport_bottom_end = viewport_bottom = client_h * scale_factor - videoSize.GetHeight(); + viewport_bottom = client_h * scale_factor - videoSize.GetHeight(); viewport_top = 0; viewport_width = videoSize.GetWidth(); viewport_height = videoSize.GetHeight(); @@ -284,27 +288,26 @@ void VideoDisplay::PositionVideo() { int vidH = provider->GetHeight(); AspectRatio arType = con->videoController->GetAspectRatioType(); - double displayAr = double(viewport_width) / viewport_height; + double displayAr = double(client_w) / client_h; double videoAr = arType == AspectRatio::Default ? double(vidW) / vidH : con->videoController->GetAspectRatioValue(); // Window is wider than video, blackbox left/right if (displayAr - videoAr > 0.01) { - int delta = viewport_width - videoAr * viewport_height; + int delta = client_w - videoAr * client_h; viewport_left = delta / 2; - viewport_width -= delta; } // Video is wider than window, blackbox top/bottom else if (videoAr - displayAr > 0.01) { - int delta = viewport_height - viewport_width / videoAr; + int delta = client_h - client_w / videoAr; viewport_top = viewport_bottom = delta / 2; viewport_height -= delta; + viewport_width = viewport_height * videoAr; } } viewport_left += pan_x; viewport_top += pan_y; viewport_bottom -= pan_y; - viewport_bottom_end = std::min(viewport_bottom_end, 0); if (tool) { tool->SetClientSize(client_w * scale_factor, client_h * scale_factor); @@ -319,9 +322,7 @@ void VideoDisplay::UpdateSize() { if (!provider || !IsShownOnScreen()) return; videoSize.Set(provider->GetWidth(), provider->GetHeight()); - videoSize *= zoomValue; - if (con->videoController->GetAspectRatioType() != AspectRatio::Default) - videoSize.SetWidth(videoSize.GetHeight() * con->videoController->GetAspectRatioValue()); + videoSize *= videoZoomValue * windowZoomValue; wxEventBlocker blocker(this); if (freeSize) { @@ -329,13 +330,15 @@ void VideoDisplay::UpdateSize() { while (!top->IsTopLevel()) top = top->GetParent(); wxSize cs = GetClientSize(); + float csAr = (float)cs.GetWidth() / (float)cs.GetHeight(); wxSize oldSize = top->GetSize(); - top->SetSize(top->GetSize() + videoSize / scale_factor - cs); + top->SetSize(top->GetSize() + wxSize(provider->GetHeight() * csAr, provider->GetHeight()) * windowZoomValue / scale_factor - cs); SetClientSize(cs + top->GetSize() - oldSize); } else { - SetMinClientSize(videoSize / scale_factor); - SetMaxClientSize(videoSize / scale_factor); + wxSize newSize = wxSize(provider->GetWidth(), provider->GetHeight()) * windowZoomValue / scale_factor; + SetMinClientSize(newSize); + SetMaxClientSize(newSize); GetGrandParent()->Layout(); } @@ -345,11 +348,16 @@ void VideoDisplay::UpdateSize() { void VideoDisplay::OnSizeEvent(wxSizeEvent &event) { if (freeSize) { - videoSize = GetClientSize() * scale_factor; - PositionVideo(); - zoomValue = double(viewport_height) / con->project->VideoProvider()->GetHeight(); - zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.)); - con->ass->Properties.video_zoom = zoomValue; + /* If the video is not moved */ + if (videoZoomValue == 1.0f && pan_x == 0 && pan_y == 0) + videoSize = GetClientSize() * scale_factor; + /* If the video is moving, we only need to update the size in this case */ + else if (videoSize.GetWidth() == 0 && videoSize.GetHeight() == 0) + videoSize = GetClientSize() * videoZoomValue * scale_factor; + windowZoomValue = double(GetClientSize().GetHeight()) / con->project->VideoProvider()->GetHeight(); + zoomBox->ChangeValue(fmt_wx("%g%%", windowZoomValue * 100.)); + con->ass->Properties.video_zoom = windowZoomValue; + UpdateSize(); } else { PositionVideo(); @@ -387,7 +395,10 @@ void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { if (int wheel = event.GetWheelRotation()) { if (ForwardMouseWheelEvent(this, event)) - SetZoom(zoomValue + .125 * (wheel / event.GetWheelDelta())); + if (event.ControlDown()) + SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); + else + SetVideoZoom(videoZoomValue + .125 * (wheel / event.GetWheelDelta())); } } @@ -403,28 +414,42 @@ void VideoDisplay::OnKeyDown(wxKeyEvent &event) { void VideoDisplay::ResetPan() { pan_x = pan_y = 0; + videoZoomValue = 1; + UpdateSize(); PositionVideo(); } -void VideoDisplay::SetZoom(double value) { +void VideoDisplay::SetWindowZoom(double value) { if (value == 0) return; value = std::max(value, .125); - pan_x *= value / zoomValue; - pan_y *= value / zoomValue; - zoomValue = value; - size_t selIndex = zoomValue / .125 - 1; + pan_x *= value / windowZoomValue; + pan_y *= value / windowZoomValue; + windowZoomValue = value; + size_t selIndex = windowZoomValue / .125 - 1; if (selIndex < zoomBox->GetCount()) zoomBox->SetSelection(selIndex); - zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.)); - con->ass->Properties.video_zoom = zoomValue; + zoomBox->ChangeValue(fmt_wx("%g%%", windowZoomValue * 100.)); + con->ass->Properties.video_zoom = windowZoomValue; + UpdateSize(); +} + +void VideoDisplay::SetVideoZoom(double value) { + if (value == 0) return; + value = std::max(value, .125); + Vector2D mp = tool->FromScriptCoords(GetMousePosition()); + wxSize cs = GetClientSize(); + pan_x *= value / videoZoomValue; + pan_y *= value / videoZoomValue; + + videoZoomValue = value; UpdateSize(); } void VideoDisplay::SetZoomFromBox(wxCommandEvent &) { int sel = zoomBox->GetSelection(); if (sel != wxNOT_FOUND) { - zoomValue = (sel + 1) * .125; - con->ass->Properties.video_zoom = zoomValue; + windowZoomValue = (sel + 1) * .125; + con->ass->Properties.video_zoom = windowZoomValue; UpdateSize(); } } @@ -436,7 +461,7 @@ void VideoDisplay::SetZoomFromBoxText(wxCommandEvent &) { double value; if (strValue.ToDouble(&value)) - SetZoom(value / 100.); + SetWindowZoom(value / 100.); } void VideoDisplay::SetTool(std::unique_ptr new_tool) { diff --git a/src/video_display.h b/src/video_display.h index 5024421758..f9856d6053 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -79,15 +79,15 @@ class VideoDisplay final : public wxGLCanvas { int viewport_width = 0; /// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport int viewport_bottom = 0; - /// The REAL bottom of the viewport; used only for glViewport - int viewport_bottom_end = 0; /// Screen pixels between the bottom of the canvas and the top of the video; used for coordinate space conversion int viewport_top = 0; /// The height of the video in screen pixels int viewport_height = 0; - /// The current zoom level, where 1.0 = 100% - double zoomValue; + /// The current window zoom level, where 1.0 = 100% + double windowZoomValue; + /// The current video zoom level, where 1.0 = 100% relative to the display window size + double videoZoomValue; /// The last position of the mouse, when dragging Vector2D pan_last_pos; @@ -167,9 +167,10 @@ class VideoDisplay final : public wxGLCanvas { /// @brief Set the zoom level /// @param value The new zoom level - void SetZoom(double value); + void SetWindowZoom(double value); + void SetVideoZoom(double value); /// @brief Get the current zoom level - double GetZoom() const { return zoomValue; } + double GetZoom() const { return windowZoomValue; } /// @brief Reset the video pan void ResetPan(); From db6297c8c36efc44e6bc75f5f29d89a177f02ad0 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 21 Apr 2021 00:21:06 +0200 Subject: [PATCH 09/16] Make zooming center around the cursor position --- src/video_display.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index c1b1cfd28b..d879e8abf1 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -299,7 +299,8 @@ void VideoDisplay::PositionVideo() { // Video is wider than window, blackbox top/bottom else if (videoAr - displayAr > 0.01) { int delta = client_h - client_w / videoAr; - viewport_top = viewport_bottom = delta / 2; + viewport_top += delta / 2; + viewport_bottom += delta / 2; viewport_height -= delta; viewport_width = viewport_height * videoAr; } @@ -436,10 +437,27 @@ void VideoDisplay::SetWindowZoom(double value) { void VideoDisplay::SetVideoZoom(double value) { if (value == 0) return; value = std::max(value, .125); - Vector2D mp = tool->FromScriptCoords(GetMousePosition()); + + // With the current blackbox algorithm in PositionVideo(), viewport_{width,height} could go negative. Stop that here wxSize cs = GetClientSize(); - pan_x *= value / videoZoomValue; - pan_y *= value / videoZoomValue; + wxSize videoNewSize = videoSize * (value / videoZoomValue); + float windowAR = (float)cs.GetWidth() / cs.GetHeight(); + float videoAR = (float)videoNewSize.GetWidth() / videoNewSize.GetHeight(); + if (windowAR < videoAR) { + float delta = cs.GetHeight() - cs.GetWidth() / videoAR; + if (videoNewSize.GetHeight() - delta < 0) + return; + } + + // Mouse coordinates, relative to the video, at the current zoom level + Vector2D mp = GetMousePosition() * videoZoomValue * windowZoomValue; + + // The video size will change by this many pixels + int pixelChangeW = videoSize.GetWidth() * (value / videoZoomValue - 1); + int pixelChangeH = videoSize.GetHeight() * (value / videoZoomValue - 1); + + pan_x -= pixelChangeW * (mp.X() / videoSize.GetWidth()); + pan_y -= pixelChangeH * (mp.Y() / videoSize.GetHeight()); videoZoomValue = value; UpdateSize(); From 09ea0f54d35d26a89d38aed731132d03e8f739e5 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 21 Apr 2021 00:22:18 +0200 Subject: [PATCH 10/16] Make zooming feel more linear with a "good enough" implementation --- src/video_display.cpp | 20 +++++++++++--------- src/video_display.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index d879e8abf1..243047486d 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -399,7 +399,7 @@ void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { if (event.ControlDown()) SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); else - SetVideoZoom(videoZoomValue + .125 * (wheel / event.GetWheelDelta())); + SetVideoZoom(wheel / event.GetWheelDelta()); } } @@ -434,17 +434,19 @@ void VideoDisplay::SetWindowZoom(double value) { UpdateSize(); } -void VideoDisplay::SetVideoZoom(double value) { - if (value == 0) return; - value = std::max(value, .125); +void VideoDisplay::SetVideoZoom(int step) { + if (step == 0) return; + double newVideoZoom = videoZoomValue + (.125 * step) * videoZoomValue; + if (newVideoZoom < 0.125 || newVideoZoom > 10.0) + return; // With the current blackbox algorithm in PositionVideo(), viewport_{width,height} could go negative. Stop that here wxSize cs = GetClientSize(); - wxSize videoNewSize = videoSize * (value / videoZoomValue); + wxSize videoNewSize = videoSize * (newVideoZoom / videoZoomValue); float windowAR = (float)cs.GetWidth() / cs.GetHeight(); float videoAR = (float)videoNewSize.GetWidth() / videoNewSize.GetHeight(); if (windowAR < videoAR) { - float delta = cs.GetHeight() - cs.GetWidth() / videoAR; + int delta = cs.GetHeight() - cs.GetWidth() / videoAR; if (videoNewSize.GetHeight() - delta < 0) return; } @@ -453,13 +455,13 @@ void VideoDisplay::SetVideoZoom(double value) { Vector2D mp = GetMousePosition() * videoZoomValue * windowZoomValue; // The video size will change by this many pixels - int pixelChangeW = videoSize.GetWidth() * (value / videoZoomValue - 1); - int pixelChangeH = videoSize.GetHeight() * (value / videoZoomValue - 1); + int pixelChangeW = std::lround(videoSize.GetWidth() * (newVideoZoom / videoZoomValue - 1.0)); + int pixelChangeH = std::lround(videoSize.GetHeight() * (newVideoZoom / videoZoomValue - 1.0)); pan_x -= pixelChangeW * (mp.X() / videoSize.GetWidth()); pan_y -= pixelChangeH * (mp.Y() / videoSize.GetHeight()); - videoZoomValue = value; + videoZoomValue = newVideoZoom; UpdateSize(); } diff --git a/src/video_display.h b/src/video_display.h index f9856d6053..bd27a05692 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -168,7 +168,7 @@ class VideoDisplay final : public wxGLCanvas { /// @brief Set the zoom level /// @param value The new zoom level void SetWindowZoom(double value); - void SetVideoZoom(double value); + void SetVideoZoom(int step); /// @brief Get the current zoom level double GetZoom() const { return windowZoomValue; } From 14d078fb9fd4d9398f1302ec7f9b39232953d7a7 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 21 Apr 2021 00:24:07 +0200 Subject: [PATCH 11/16] Fix a zooming bug on linux The preview window would change in width, when the video was being zoomed. Possibly, because on windows, zooming only calls UpdateSize once, but on linux, it gets called multiple, like 8 times. Rounding fixed it. --- src/video_display.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 243047486d..57db991956 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -330,11 +330,12 @@ void VideoDisplay::UpdateSize() { wxWindow *top = GetParent(); while (!top->IsTopLevel()) top = top->GetParent(); - wxSize cs = GetClientSize(); - float csAr = (float)cs.GetWidth() / (float)cs.GetHeight(); + wxSize oldClientSize = GetClientSize(); + double csAr = (double)oldClientSize.GetWidth() / (double)oldClientSize.GetHeight(); + wxSize newClientSize = wxSize(std::lround(provider->GetHeight() * csAr), provider->GetHeight()) * windowZoomValue / scale_factor; wxSize oldSize = top->GetSize(); - top->SetSize(top->GetSize() + wxSize(provider->GetHeight() * csAr, provider->GetHeight()) * windowZoomValue / scale_factor - cs); - SetClientSize(cs + top->GetSize() - oldSize); + top->SetSize(oldSize + (newClientSize - oldClientSize)); + SetClientSize(oldClientSize + (top->GetSize() - oldSize)); } else { wxSize newSize = wxSize(provider->GetWidth(), provider->GetHeight()) * windowZoomValue / scale_factor; From 0b8586e90dbd92ef13a2582b13898f6ae11fd006 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Fri, 16 Jul 2021 13:07:19 +0200 Subject: [PATCH 12/16] Add reset hotkey as Ctrl-R I'm not entirely sure, that this is how it's supposed to be added. This requires editing the already existing hotkey.json file (shows path in log, if it exists). Should this also be added to hotkey.cpp? --- src/libresrc/default_hotkey.json | 5 ++++- src/libresrc/osx/default_hotkey.json | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libresrc/default_hotkey.json b/src/libresrc/default_hotkey.json index b9460979e8..67e7844080 100644 --- a/src/libresrc/default_hotkey.json +++ b/src/libresrc/default_hotkey.json @@ -337,6 +337,9 @@ "video/frame/prev/large" : [ "Alt-Left" ], + "video/pan_reset" : [ + "Ctrl-R" + ], "video/tool/clip" : [ "H" ], @@ -359,4 +362,4 @@ "J" ] } -} \ No newline at end of file +} diff --git a/src/libresrc/osx/default_hotkey.json b/src/libresrc/osx/default_hotkey.json index 829adb88e6..ccebadaaa6 100644 --- a/src/libresrc/osx/default_hotkey.json +++ b/src/libresrc/osx/default_hotkey.json @@ -347,6 +347,9 @@ "video/frame/prev/large" : [ "Alt-Left" ], + "video/pan_reset" : [ + "Ctrl-R" + ], "video/tool/clip" : [ "H" ], From 36f7e102e21a1463f1a1a44ea135ad3404024b20 Mon Sep 17 00:00:00 2001 From: moex3 <46636583+moex3@users.noreply.github.com> Date: Wed, 2 Mar 2022 14:21:23 +0100 Subject: [PATCH 13/16] Revert "Add reset hotkey as Ctrl-R" / Not needed This reverts commit 3d525d9938790211b02a31a16d716498957891fc. The default hotkey is not required. People can just add a custom one from the hotkey settings if they want this. --- src/libresrc/default_hotkey.json | 5 +---- src/libresrc/osx/default_hotkey.json | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libresrc/default_hotkey.json b/src/libresrc/default_hotkey.json index 67e7844080..b9460979e8 100644 --- a/src/libresrc/default_hotkey.json +++ b/src/libresrc/default_hotkey.json @@ -337,9 +337,6 @@ "video/frame/prev/large" : [ "Alt-Left" ], - "video/pan_reset" : [ - "Ctrl-R" - ], "video/tool/clip" : [ "H" ], @@ -362,4 +359,4 @@ "J" ] } -} +} \ No newline at end of file diff --git a/src/libresrc/osx/default_hotkey.json b/src/libresrc/osx/default_hotkey.json index ccebadaaa6..829adb88e6 100644 --- a/src/libresrc/osx/default_hotkey.json +++ b/src/libresrc/osx/default_hotkey.json @@ -347,9 +347,6 @@ "video/frame/prev/large" : [ "Alt-Left" ], - "video/pan_reset" : [ - "Ctrl-R" - ], "video/tool/clip" : [ "H" ], From b332181937f5cdb9d276a8e4a83249585decee30 Mon Sep 17 00:00:00 2001 From: Sodra Date: Wed, 2 Mar 2022 18:24:17 -0800 Subject: [PATCH 14/16] Added option to enable video panning --- src/libresrc/default_config.json | 3 ++- src/preferences.cpp | 3 +++ src/video_display.cpp | 28 ++++++++++++++++++++-------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index 318f8d3eef..e177379b23 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -611,6 +611,7 @@ "Fast Jump Step" : 10, "Show Keyframes" : true }, - "Subtitle Sync" : true + "Subtitle Sync" : true, + "Video Pan": false } } diff --git a/src/preferences.cpp b/src/preferences.cpp index f6320dd75d..f0e1f6ff3d 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -433,6 +433,9 @@ void Advanced_Video(wxTreebook *book, Preferences *parent) { wxArrayString sp_choice = to_wx(SubtitlesProviderFactory::GetClasses()); p->OptionChoice(expert, _("Subtitles provider"), sp_choice, "Subtitle/Provider"); + + p->OptionChoice(expert, _("Video Panning"), "Video/Video Pan"); + #ifdef WITH_AVISYNTH auto avisynth = p->PageSizer("Avisynth"); diff --git a/src/video_display.cpp b/src/video_display.cpp index 57db991956..8598eae5c9 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -372,18 +372,30 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { last_mouse_pos = mouse_pos = event.GetPosition(); - if (event.GetButton() == wxMOUSE_BTN_MIDDLE) { - if ((panning = event.ButtonDown())) + ///if video pan + bool videoPan = OPT_GET("Video/Video Pan")->GetBool(); + + if (videoPan){ + if (event.GetButton() == wxMOUSE_BTN_MIDDLE) { + if ((panning = event.ButtonDown())) + pan_last_pos = event.GetPosition(); + } + if (panning && event.Dragging()) { + pan_x += event.GetX() - pan_last_pos.X(); + pan_y += event.GetY() - pan_last_pos.Y(); pan_last_pos = event.GetPosition(); - } - if (panning && event.Dragging()) { - pan_x += event.GetX() - pan_last_pos.X(); - pan_y += event.GetY() - pan_last_pos.Y(); - pan_last_pos = event.GetPosition(); - PositionVideo(); + PositionVideo(); + } + } + else if ((pan_x != 0 || pan_y != 0) && !videoPan) + { + pan_x = pan_y = 0; + PositionVideo(); } + /// + if (tool) tool->OnMouseEvent(event); } From bb5081189ea9963a511c67a5de5ba8d7bea5808f Mon Sep 17 00:00:00 2001 From: Sodra Date: Wed, 2 Mar 2022 18:36:38 -0800 Subject: [PATCH 15/16] Fix video panning option. Oops teehee ptep~ --- src/preferences.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preferences.cpp b/src/preferences.cpp index f0e1f6ff3d..1eb906c3ad 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -434,7 +434,7 @@ void Advanced_Video(wxTreebook *book, Preferences *parent) { wxArrayString sp_choice = to_wx(SubtitlesProviderFactory::GetClasses()); p->OptionChoice(expert, _("Subtitles provider"), sp_choice, "Subtitle/Provider"); - p->OptionChoice(expert, _("Video Panning"), "Video/Video Pan"); + p->OptionAdd(expert, _("Video Panning"), "Video/Video Pan"); #ifdef WITH_AVISYNTH From 03ffce8a89cdfcf4c528851c6a65db31918acf2f Mon Sep 17 00:00:00 2001 From: Sodra Date: Wed, 2 Mar 2022 19:02:21 -0800 Subject: [PATCH 16/16] Fixing zoom when panning is off --- src/video_display.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video_display.cpp b/src/video_display.cpp index 8598eae5c9..ebee959be5 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -407,9 +407,10 @@ void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { } void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { + bool videoPan = OPT_GET("Video/Video Pan")->GetBool(); if (int wheel = event.GetWheelRotation()) { if (ForwardMouseWheelEvent(this, event)) - if (event.ControlDown()) + if (event.ControlDown() || !videoPan) SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); else SetVideoZoom(wheel / event.GetWheelDelta());