forked from mia/Aegisub
Make VideoSlider use commands for its key events
Originally committed to SVN as r5256.
This commit is contained in:
parent
1f79d89e5b
commit
6ad2098749
8 changed files with 244 additions and 274 deletions
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "../ass_dialogue.h"
|
||||||
|
#include "../ass_time.h"
|
||||||
#include "../compat.h"
|
#include "../compat.h"
|
||||||
#include "../frame_main.h"
|
#include "../frame_main.h"
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
|
@ -254,6 +256,66 @@ struct video_frame_next : public Command {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Seek to the next subtitle boundary.
|
||||||
|
struct video_frame_next_boundary : public Command {
|
||||||
|
CMD_NAME("video/frame/next/boundary")
|
||||||
|
STR_MENU("Next Boundary")
|
||||||
|
STR_DISP("Next Boundary")
|
||||||
|
STR_HELP("Seek to the next subtitle boundary.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
AssDialogue *active_line = c->selectionController->GetActiveLine();
|
||||||
|
if (!active_line) return;
|
||||||
|
|
||||||
|
int target = c->videoController->FrameAtTime(active_line->Start.GetMS(), agi::vfr::START);
|
||||||
|
if (target > c->videoController->GetFrameN()) {
|
||||||
|
c->videoController->JumpToFrame(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = c->videoController->FrameAtTime(active_line->End.GetMS(), agi::vfr::END);
|
||||||
|
if (target > c->videoController->GetFrameN()) {
|
||||||
|
c->videoController->JumpToFrame(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->selectionController->NextLine();
|
||||||
|
AssDialogue *new_line = c->selectionController->GetActiveLine();
|
||||||
|
if (new_line != active_line)
|
||||||
|
c->videoController->JumpToTime(new_line->Start.GetMS());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Seek to the next keyframe.
|
||||||
|
struct video_frame_next_keyframe : public Command {
|
||||||
|
CMD_NAME("video/frame/next/keyframe")
|
||||||
|
STR_MENU("Next Keyframe")
|
||||||
|
STR_DISP("Next Keyframe")
|
||||||
|
STR_HELP("Seek to the next keyframe.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
std::vector<int> const& kf = c->videoController->GetKeyFrames();
|
||||||
|
std::vector<int>::const_iterator pos = lower_bound(kf.begin(), kf.end(), c->videoController->GetFrameN());
|
||||||
|
if (pos != kf.end()) ++pos;
|
||||||
|
|
||||||
|
c->videoController->JumpToFrame(pos == kf.end() ? c->videoController->GetFrameN() - 1 : *pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Fast jump forward
|
||||||
|
struct video_frame_next_large : public Command {
|
||||||
|
CMD_NAME("video/frame/next/large")
|
||||||
|
STR_MENU("Fast jump forward")
|
||||||
|
STR_DISP("Fast jump forward")
|
||||||
|
STR_HELP("Fast jump forward.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoController->JumpToFrame(
|
||||||
|
c->videoController->GetFrameN() +
|
||||||
|
OPT_GET("Video/Slider/Fast Jump Step")->GetInt());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Seek to the previous frame.
|
/// Seek to the previous frame.
|
||||||
struct video_frame_prev : public Command {
|
struct video_frame_prev : public Command {
|
||||||
CMD_NAME("video/frame/prev")
|
CMD_NAME("video/frame/prev")
|
||||||
|
@ -266,6 +328,68 @@ struct video_frame_prev : public Command {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Seek to the previous subtitle boundary.
|
||||||
|
struct video_frame_prev_boundary : public Command {
|
||||||
|
CMD_NAME("video/frame/prev/boundary")
|
||||||
|
STR_MENU("Previous Boundary")
|
||||||
|
STR_DISP("Previous Boundary")
|
||||||
|
STR_HELP("Seek to the previous subtitle boundary.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
AssDialogue *active_line = c->selectionController->GetActiveLine();
|
||||||
|
if (!active_line) return;
|
||||||
|
|
||||||
|
int target = c->videoController->FrameAtTime(active_line->End.GetMS(), agi::vfr::END);
|
||||||
|
if (target < c->videoController->GetFrameN()) {
|
||||||
|
c->videoController->JumpToFrame(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = c->videoController->FrameAtTime(active_line->Start.GetMS(), agi::vfr::START);
|
||||||
|
if (target < c->videoController->GetFrameN()) {
|
||||||
|
c->videoController->JumpToFrame(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->selectionController->PrevLine();
|
||||||
|
AssDialogue *new_line = c->selectionController->GetActiveLine();
|
||||||
|
if (new_line != active_line)
|
||||||
|
c->videoController->JumpToTime(new_line->End.GetMS(), agi::vfr::END);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Seek to the previous keyframe.
|
||||||
|
struct video_frame_prev_keyframe : public Command {
|
||||||
|
CMD_NAME("video/frame/prev/keyframe")
|
||||||
|
STR_MENU("Previous Keyframe")
|
||||||
|
STR_DISP("Previous Keyframe")
|
||||||
|
STR_HELP("Seek to the previous keyframe.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
int frame = c->videoController->GetFrameN();
|
||||||
|
std::vector<int> const& kf = c->videoController->GetKeyFrames();
|
||||||
|
std::vector<int>::const_iterator pos = lower_bound(kf.begin(), kf.end(), frame);
|
||||||
|
|
||||||
|
if (frame != 0 && (pos == kf.end() || *pos == frame))
|
||||||
|
--pos;
|
||||||
|
|
||||||
|
c->videoController->JumpToFrame(*pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Fast jump backwards
|
||||||
|
struct video_frame_prev_large : public Command {
|
||||||
|
CMD_NAME("video/frame/prev/large")
|
||||||
|
STR_MENU("Fast jump backwards")
|
||||||
|
STR_DISP("Fast jump backwards")
|
||||||
|
STR_HELP("Fast jump backwards")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoController->JumpToFrame(
|
||||||
|
c->videoController->GetFrameN() -
|
||||||
|
OPT_GET("Video/Slider/Fast Jump Step")->GetInt());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Jump to frame or time.
|
/// Jump to frame or time.
|
||||||
struct video_jump : public Command {
|
struct video_jump : public Command {
|
||||||
|
@ -493,7 +617,13 @@ void init_video(CommandManager *cm) {
|
||||||
cm->reg(new video_details);
|
cm->reg(new video_details);
|
||||||
cm->reg(new video_focus_seek);
|
cm->reg(new video_focus_seek);
|
||||||
cm->reg(new video_frame_next);
|
cm->reg(new video_frame_next);
|
||||||
|
cm->reg(new video_frame_next_boundary);
|
||||||
|
cm->reg(new video_frame_next_keyframe);
|
||||||
|
cm->reg(new video_frame_next_large);
|
||||||
cm->reg(new video_frame_prev);
|
cm->reg(new video_frame_prev);
|
||||||
|
cm->reg(new video_frame_prev_boundary);
|
||||||
|
cm->reg(new video_frame_prev_keyframe);
|
||||||
|
cm->reg(new video_frame_prev_large);
|
||||||
cm->reg(new video_jump);
|
cm->reg(new video_jump);
|
||||||
cm->reg(new video_jump_end);
|
cm->reg(new video_jump_end);
|
||||||
cm->reg(new video_jump_start);
|
cm->reg(new video_jump_start);
|
||||||
|
|
|
@ -79,7 +79,6 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *parent, agi::Context *contex
|
||||||
videoBox = new VideoBox(panel, true, NULL, context);
|
videoBox = new VideoBox(panel, true, NULL, context);
|
||||||
videoBox->videoDisplay->freeSize = true;
|
videoBox->videoDisplay->freeSize = true;
|
||||||
videoBox->videoDisplay->SetClientSize(initialDisplaySize);
|
videoBox->videoDisplay->SetClientSize(initialDisplaySize);
|
||||||
videoBox->videoSlider->grid = context->subsGrid;
|
|
||||||
|
|
||||||
// Set sizer
|
// Set sizer
|
||||||
wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
|
wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
|
@ -298,7 +298,6 @@ void FrameMain::InitContents() {
|
||||||
StartupLog("Create subtitles grid");
|
StartupLog("Create subtitles grid");
|
||||||
context->subsGrid = SubsGrid = new SubtitlesGrid(Panel,context.get(),wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,"Subs grid");
|
context->subsGrid = SubsGrid = new SubtitlesGrid(Panel,context.get(),wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,"Subs grid");
|
||||||
context->selectionController = context->subsGrid;
|
context->selectionController = context->subsGrid;
|
||||||
context->videoBox->videoSlider->grid = SubsGrid;
|
|
||||||
Search.context = context.get();
|
Search.context = context.get();
|
||||||
|
|
||||||
StartupLog("Create tool area splitter window");
|
StartupLog("Create tool area splitter window");
|
||||||
|
|
|
@ -504,6 +504,27 @@
|
||||||
"enable" : true
|
"enable" : true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"video/frame/next/boundary" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Ctrl" ],
|
||||||
|
"key" : "Right",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"video/frame/next/keyframe" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Shift" ],
|
||||||
|
"key" : "Right",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"video/frame/next/large" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Alt" ],
|
||||||
|
"key" : "Right",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
"video/frame/prev" : [
|
"video/frame/prev" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
|
@ -511,6 +532,27 @@
|
||||||
"enable" : true
|
"enable" : true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"video/frame/prev/boundary" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Ctrl" ],
|
||||||
|
"key" : "Left",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"video/frame/prev/keyframe" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Shift" ],
|
||||||
|
"key" : "Left",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"video/frame/prev/large" : [
|
||||||
|
{
|
||||||
|
"modifiers" : [ "Alt" ],
|
||||||
|
"key" : "Left",
|
||||||
|
"enable" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
"visual typesetting set tool crosshair" : [
|
"visual typesetting set tool crosshair" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
|
|
|
@ -90,7 +90,7 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox, agi::
|
||||||
add_option(this, videoBottomSizer, "video/opt/autoscroll", "Video/Subtitle Sync");
|
add_option(this, videoBottomSizer, "video/opt/autoscroll", "Video/Subtitle Sync");
|
||||||
|
|
||||||
// Seek
|
// Seek
|
||||||
videoSlider = new VideoSlider(this,-1);
|
videoSlider = new VideoSlider(this, context);
|
||||||
videoSlider->SetToolTip(_("Seek video."));
|
videoSlider->SetToolTip(_("Seek video."));
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
|
@ -120,9 +120,6 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox, agi::
|
||||||
// Display
|
// Display
|
||||||
videoDisplay = new VideoDisplay(this,VideoPosition,VideoSubsPos,zoomBox,this,context);
|
videoDisplay = new VideoDisplay(this,VideoPosition,VideoSubsPos,zoomBox,this,context);
|
||||||
|
|
||||||
// Set display
|
|
||||||
videoSlider->Display = videoDisplay;
|
|
||||||
|
|
||||||
// Top sizer
|
// Top sizer
|
||||||
// Detached and attached video needs different flags, see bugs #742 and #853
|
// Detached and attached video needs different flags, see bugs #742 and #853
|
||||||
int highSizerFlags = isDetached ? wxEXPAND : 0;
|
int highSizerFlags = isDetached ? wxEXPAND : 0;
|
||||||
|
|
|
@ -266,7 +266,7 @@ void VideoContext::JumpToFrame(int n) {
|
||||||
// Prevent intervention during playback
|
// Prevent intervention during playback
|
||||||
if (isPlaying && n != playNextFrame) return;
|
if (isPlaying && n != playNextFrame) return;
|
||||||
|
|
||||||
frame_n = n;
|
frame_n = mid(0, n, GetLength() - 1);
|
||||||
|
|
||||||
Seek(n);
|
Seek(n);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,52 +40,30 @@
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "include/aegisub/context.h"
|
||||||
|
#include "include/aegisub/hotkey.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "subs_edit_box.h"
|
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
|
||||||
#include "video_slider.h"
|
#include "video_slider.h"
|
||||||
|
|
||||||
/// IDs
|
VideoSlider::VideoSlider (wxWindow* parent, agi::Context *c)
|
||||||
enum {
|
: wxWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE)
|
||||||
NextFrame = 1300,
|
, vc(c->videoController)
|
||||||
PrevFrame
|
, grid(c->subsGrid)
|
||||||
};
|
, val(0)
|
||||||
|
, max(1)
|
||||||
/// @brief Constructor
|
|
||||||
/// @param parent
|
|
||||||
/// @param id
|
|
||||||
///
|
|
||||||
VideoSlider::VideoSlider (wxWindow* parent, wxWindowID id)
|
|
||||||
: wxWindow (parent,id,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE)
|
|
||||||
{
|
{
|
||||||
val = 0;
|
|
||||||
max = 1;
|
|
||||||
Display = NULL;
|
|
||||||
SetClientSize(20,25);
|
SetClientSize(20,25);
|
||||||
SetMinSize(wxSize(20, 25));
|
SetMinSize(wxSize(20, 25));
|
||||||
locked = false;
|
slots.push_back(OPT_SUB("Video/Slider/Show Keyframes", &wxWindow::Refresh, this, false, (wxRect*)NULL));
|
||||||
OPT_SUB("Video/Slider/Show Keyframes", &wxWindow::Refresh, this, false, (wxRect*)NULL);
|
slots.push_back(vc->AddSeekListener(&VideoSlider::SetValue, this));
|
||||||
VideoContext *vc = VideoContext::Get();
|
slots.push_back(vc->AddVideoOpenListener(&VideoSlider::VideoOpened, this));
|
||||||
assert(vc);
|
slots.push_back(vc->AddKeyframesListener(&VideoSlider::KeyframesChanged, this));
|
||||||
vc->AddSeekListener(&VideoSlider::SetValue, this);
|
|
||||||
vc->AddVideoOpenListener(&VideoSlider::VideoOpened, this);
|
|
||||||
vc->AddKeyframesListener(&VideoSlider::KeyframesChanged, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoSlider::~VideoSlider() {
|
|
||||||
VideoContext *vc = VideoContext::Get();
|
|
||||||
assert(vc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Set value
|
|
||||||
/// @param value
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void VideoSlider::SetValue(int value) {
|
void VideoSlider::SetValue(int value) {
|
||||||
if (val == value) return;
|
if (val == value) return;
|
||||||
val = mid(0, value, max);
|
val = mid(0, value, max);
|
||||||
|
@ -93,7 +71,6 @@ void VideoSlider::SetValue(int value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoSlider::VideoOpened() {
|
void VideoSlider::VideoOpened() {
|
||||||
VideoContext *vc = VideoContext::Get();
|
|
||||||
max = vc->GetLength() - 1;
|
max = vc->GetLength() - 1;
|
||||||
keyframes = vc->GetKeyFrames();
|
keyframes = vc->GetKeyFrames();
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
|
@ -104,37 +81,21 @@ void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) {
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get value at X
|
|
||||||
/// @param x
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int VideoSlider::GetValueAtX(int x) {
|
int VideoSlider::GetValueAtX(int x) {
|
||||||
// Get dimensions
|
|
||||||
int w,h;
|
int w,h;
|
||||||
GetClientSize(&w,&h);
|
GetClientSize(&w,&h);
|
||||||
|
|
||||||
// Special case
|
// Special case
|
||||||
if (w <= 10) return 0;
|
if (w <= 10) return 0;
|
||||||
|
|
||||||
// Calculate
|
|
||||||
return (int64_t)(x-5)*(int64_t)max/(int64_t)(w-10);
|
return (int64_t)(x-5)*(int64_t)max/(int64_t)(w-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Get X at value
|
|
||||||
/// @param value
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int VideoSlider::GetXAtValue(int value) {
|
int VideoSlider::GetXAtValue(int value) {
|
||||||
// Get dimensions
|
|
||||||
int w,h;
|
|
||||||
GetClientSize(&w,&h);
|
|
||||||
|
|
||||||
// Special case
|
|
||||||
if (max <= 0) return 0;
|
if (max <= 0) return 0;
|
||||||
|
|
||||||
// Calculate
|
int w,h;
|
||||||
|
GetClientSize(&w,&h);
|
||||||
return (int64_t)value*(int64_t)(w-10)/(int64_t)max+5;
|
return (int64_t)value*(int64_t)(w-10)/(int64_t)max+5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,223 +108,79 @@ BEGIN_EVENT_TABLE(VideoSlider, wxWindow)
|
||||||
EVT_ERASE_BACKGROUND(VideoSlider::OnEraseBackground)
|
EVT_ERASE_BACKGROUND(VideoSlider::OnEraseBackground)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
/// @brief Mouse events
|
|
||||||
/// @param event
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void VideoSlider::OnMouse(wxMouseEvent &event) {
|
void VideoSlider::OnMouse(wxMouseEvent &event) {
|
||||||
// Coordinates
|
|
||||||
int x = event.GetX();
|
int x = event.GetX();
|
||||||
//int y = event.GetY();
|
|
||||||
bool shift = event.m_shiftDown;
|
|
||||||
|
|
||||||
// Left click
|
|
||||||
if (event.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
|
if (event.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
|
||||||
// Check if it's OK to drag
|
// If the slider didn't already have focus, don't seek if the user
|
||||||
bool canDrag = wxWindow::FindFocus() == this;
|
// clicked very close to the current location as they were probably
|
||||||
if (!canDrag) {
|
// just trying to focus the slider
|
||||||
int tolerance = 4;
|
if (wxWindow::FindFocus() != this && abs(x - GetXAtValue(val)) < 4) {
|
||||||
int curX = GetXAtValue(val);
|
SetFocus();
|
||||||
if (x-curX < -tolerance || x-curX > tolerance) canDrag = true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drag
|
// Shift click to snap to keyframe
|
||||||
if (canDrag) {
|
if (event.m_shiftDown) {
|
||||||
// Shift click to snap to keyframe
|
int clickedFrame = GetValueAtX(x);
|
||||||
if (shift && Display) {
|
std::vector<int>::const_iterator pos = lower_bound(keyframes.begin(), keyframes.end(), clickedFrame);
|
||||||
std::vector<int> KeyFrames = VideoContext::Get()->GetKeyFrames();
|
if (pos == keyframes.end())
|
||||||
int keys = KeyFrames.size();
|
--pos;
|
||||||
int clickedFrame = GetValueAtX(x);
|
else if (pos + 1 != keyframes.end() && clickedFrame - *pos > (*pos + 1) - clickedFrame)
|
||||||
int closest = 0;
|
++pos;
|
||||||
int cur;
|
|
||||||
|
|
||||||
// Find closest
|
if (*pos == val) return;
|
||||||
for (int i=0;i<keys;i++) {
|
SetValue(*pos);
|
||||||
cur = KeyFrames[i];
|
|
||||||
if (abs(cur-clickedFrame) < abs(closest-clickedFrame)) {
|
|
||||||
closest = cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump to frame
|
|
||||||
if (closest == val) return;
|
|
||||||
SetValue(closest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal click
|
|
||||||
else {
|
|
||||||
int go = GetValueAtX(x);
|
|
||||||
if (go == val) return;
|
|
||||||
SetValue(go);
|
|
||||||
}
|
|
||||||
Refresh(false);
|
|
||||||
|
|
||||||
// Playing?
|
|
||||||
if (VideoContext::Get()->IsPlaying()) {
|
|
||||||
VideoContext::Get()->Stop();
|
|
||||||
VideoContext::Get()->JumpToFrame(val);
|
|
||||||
VideoContext::Get()->Play();
|
|
||||||
}
|
|
||||||
else VideoContext::Get()->JumpToFrame(val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get focus
|
// Normal click
|
||||||
|
else {
|
||||||
|
int go = GetValueAtX(x);
|
||||||
|
if (go == val) return;
|
||||||
|
SetValue(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vc->IsPlaying()) {
|
||||||
|
vc->Stop();
|
||||||
|
vc->JumpToFrame(val);
|
||||||
|
vc->Play();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vc->JumpToFrame(val);
|
||||||
SetFocus();
|
SetFocus();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right/middle click
|
|
||||||
if (event.ButtonDown(wxMOUSE_BTN_RIGHT) || event.ButtonDown(wxMOUSE_BTN_MIDDLE)) {
|
if (event.ButtonDown(wxMOUSE_BTN_RIGHT) || event.ButtonDown(wxMOUSE_BTN_MIDDLE)) {
|
||||||
SetFocus();
|
SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something else
|
else if (!vc->IsPlaying())
|
||||||
else if (!VideoContext::Get()->IsPlaying()) event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Key down event
|
|
||||||
/// @param event
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void VideoSlider::OnKeyDown(wxKeyEvent &event) {
|
void VideoSlider::OnKeyDown(wxKeyEvent &event) {
|
||||||
if (VideoContext::Get()->IsPlaying()) return;
|
if (vc->IsPlaying()) return;
|
||||||
|
|
||||||
// Get flags
|
if (hotkey::check("Video", event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
|
||||||
int key = event.GetKeyCode();
|
return;
|
||||||
#ifdef __APPLE__
|
|
||||||
bool ctrl = event.m_metaDown;
|
|
||||||
#else
|
|
||||||
bool ctrl = event.m_controlDown;
|
|
||||||
#endif
|
|
||||||
bool alt = event.m_altDown;
|
|
||||||
bool shift = event.m_shiftDown;
|
|
||||||
int direction = 0;
|
|
||||||
|
|
||||||
// Pick direction
|
|
||||||
if (key == WXK_LEFT) direction = -1;
|
|
||||||
else if (key == WXK_RIGHT) direction = 1;
|
|
||||||
|
|
||||||
// If a direction was actually pressed
|
|
||||||
if (direction) {
|
|
||||||
// Standard move
|
|
||||||
if (!ctrl && !shift && !alt) {
|
|
||||||
if (direction == 1) VideoContext::Get()->NextFrame();
|
|
||||||
else VideoContext::Get()->PrevFrame();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast move
|
|
||||||
if (!ctrl && !shift && alt) {
|
|
||||||
if (VideoContext::Get()->IsPlaying()) return;
|
|
||||||
int target = mid<int>(0,val + direction * OPT_GET("Video/Slider/Fast Jump Step")->GetInt(),max);
|
|
||||||
if (target != val) VideoContext::Get()->JumpToFrame(target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boundaries
|
|
||||||
if (ctrl && !shift && !alt) {
|
|
||||||
// Prepare
|
|
||||||
wxArrayInt sel = grid->GetSelection();
|
|
||||||
int cur;
|
|
||||||
if (sel.Count() > 0) cur = sel[0];
|
|
||||||
else {
|
|
||||||
grid->SetActiveLine(grid->GetDialogue(0));
|
|
||||||
grid->SelectRow(0);
|
|
||||||
cur = 0;
|
|
||||||
}
|
|
||||||
AssDialogue *curDiag = grid->GetDialogue(cur);
|
|
||||||
if (!curDiag) return;
|
|
||||||
|
|
||||||
// Jump to next sub boundary
|
|
||||||
if (direction != 0) {
|
|
||||||
int target1 = VideoContext::Get()->FrameAtTime(curDiag->Start.GetMS(),agi::vfr::START);
|
|
||||||
int target2 = VideoContext::Get()->FrameAtTime(curDiag->End.GetMS(),agi::vfr::END);
|
|
||||||
bool drawn = false;
|
|
||||||
|
|
||||||
// Forward
|
|
||||||
if (direction == 1) {
|
|
||||||
if (VideoContext::Get()->GetFrameN() < target1) VideoContext::Get()->JumpToFrame(target1);
|
|
||||||
else if (VideoContext::Get()->GetFrameN() < target2) VideoContext::Get()->JumpToFrame(target2);
|
|
||||||
else {
|
|
||||||
if (cur+1 >= grid->GetRows()) return;
|
|
||||||
grid->SetActiveLine(grid->GetDialogue(cur+1));
|
|
||||||
grid->SelectRow(cur+1);
|
|
||||||
grid->MakeCellVisible(cur+1,0);
|
|
||||||
grid->SetVideoToSubs(true);
|
|
||||||
grid->Refresh(false);
|
|
||||||
drawn = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backward
|
|
||||||
else {
|
|
||||||
if (VideoContext::Get()->GetFrameN() > target2) VideoContext::Get()->JumpToFrame(target2);
|
|
||||||
else if (VideoContext::Get()->GetFrameN() > target1) VideoContext::Get()->JumpToFrame(target1);
|
|
||||||
else {
|
|
||||||
if (cur-1 < 0) return;
|
|
||||||
grid->SetActiveLine(grid->GetDialogue(cur-1));
|
|
||||||
grid->SelectRow(cur-1);
|
|
||||||
grid->MakeCellVisible(cur-1,0);
|
|
||||||
grid->SetVideoToSubs(false);
|
|
||||||
grid->Refresh(false);
|
|
||||||
drawn = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snap to keyframe
|
|
||||||
if (shift && !ctrl && !alt) {
|
|
||||||
if (direction != 0) {
|
|
||||||
std::vector<int>::iterator pos = std::lower_bound(keyframes.begin(), keyframes.end(), val);
|
|
||||||
|
|
||||||
if (direction < 0 && val != 0 && (pos == keyframes.end() || *pos == val))
|
|
||||||
--pos;
|
|
||||||
if (direction > 0 && pos != keyframes.end())
|
|
||||||
++pos;
|
|
||||||
|
|
||||||
VideoContext::Get()->JumpToFrame(pos == keyframes.end() ? max : *pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward up/down to grid
|
// Forward up/down to grid
|
||||||
if (key == WXK_UP || key == WXK_DOWN) {
|
if (event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_DOWN) {
|
||||||
grid->GetEventHandler()->ProcessEvent(event);
|
grid->GetEventHandler()->ProcessEvent(event);
|
||||||
grid->SetFocus();
|
grid->SetFocus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward other keys to video display
|
|
||||||
if (Display) {
|
|
||||||
Display->GetEventHandler()->ProcessEvent(event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Paint event
|
|
||||||
/// @param event
|
|
||||||
///
|
|
||||||
void VideoSlider::OnPaint(wxPaintEvent &event) {
|
void VideoSlider::OnPaint(wxPaintEvent &event) {
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
DrawImage(dc);
|
DrawImage(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Draw image
|
|
||||||
/// @param destdc
|
|
||||||
///
|
|
||||||
void VideoSlider::DrawImage(wxDC &destdc) {
|
void VideoSlider::DrawImage(wxDC &destdc) {
|
||||||
// Get dimensions
|
|
||||||
int w,h;
|
int w,h;
|
||||||
GetClientSize(&w,&h);
|
GetClientSize(&w,&h);
|
||||||
|
|
||||||
|
@ -408,7 +225,7 @@ void VideoSlider::DrawImage(wxDC &destdc) {
|
||||||
|
|
||||||
// Draw keyframes
|
// Draw keyframes
|
||||||
int curX;
|
int curX;
|
||||||
if (Display && OPT_GET("Video/Slider/Show Keyframes")->GetBool()) {
|
if (OPT_GET("Video/Slider/Show Keyframes")->GetBool()) {
|
||||||
dc.SetPen(wxPen(shad));
|
dc.SetPen(wxPen(shad));
|
||||||
for (size_t i=0;i<keyframes.size();i++) {
|
for (size_t i=0;i<keyframes.size();i++) {
|
||||||
curX = GetXAtValue(keyframes[i]);
|
curX = GetXAtValue(keyframes[i]);
|
||||||
|
@ -455,19 +272,6 @@ void VideoSlider::DrawImage(wxDC &destdc) {
|
||||||
destdc.Blit(0,0,w,h,&dc,0,0);
|
destdc.Blit(0,0,w,h,&dc,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Update image
|
|
||||||
///
|
|
||||||
void VideoSlider::UpdateImage () {
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Focus change
|
|
||||||
/// @param event
|
|
||||||
///
|
|
||||||
void VideoSlider::OnFocus(wxFocusEvent &event) {
|
void VideoSlider::OnFocus(wxFocusEvent &event) {
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,14 @@
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <wx/window.h>
|
#include <wx/window.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class VideoDisplay;
|
#include <libaegisub/signal.h>
|
||||||
|
|
||||||
|
class VideoContext;
|
||||||
class SubtitlesGrid;
|
class SubtitlesGrid;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -47,24 +51,26 @@ class SubtitlesGrid;
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class VideoSlider: public wxWindow {
|
class VideoSlider: public wxWindow {
|
||||||
std::vector<int> keyframes;
|
VideoContext *vc; ///< Video controller
|
||||||
|
SubtitlesGrid *grid; ///< temp hack; remove this once event forwarding is killed
|
||||||
|
std::vector<int> keyframes; ///< Currently loaded keyframes
|
||||||
|
std::vector<agi::signal::Connection> slots;
|
||||||
|
|
||||||
/// DOCME
|
int val; ///< Current frame number
|
||||||
int val;
|
int max; ///< Last frame number
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int max;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool locked;
|
|
||||||
|
|
||||||
|
/// Get the frame number for the given x coordinate
|
||||||
int GetValueAtX(int x);
|
int GetValueAtX(int x);
|
||||||
|
/// Get the x-coordinate for a frame number
|
||||||
int GetXAtValue(int value);
|
int GetXAtValue(int value);
|
||||||
|
/// Render the slider
|
||||||
void DrawImage(wxDC &dc);
|
void DrawImage(wxDC &dc);
|
||||||
void UpdateImage();
|
/// Set the position of the slider
|
||||||
void SetValue(int value);
|
void SetValue(int value);
|
||||||
|
|
||||||
|
/// Video open event handler
|
||||||
void VideoOpened();
|
void VideoOpened();
|
||||||
|
/// Keyframe open even handler
|
||||||
void KeyframesChanged(std::vector<int> const& newKeyframes);
|
void KeyframesChanged(std::vector<int> const& newKeyframes);
|
||||||
|
|
||||||
void OnMouse(wxMouseEvent &event);
|
void OnMouse(wxMouseEvent &event);
|
||||||
|
@ -74,14 +80,7 @@ class VideoSlider: public wxWindow {
|
||||||
void OnEraseBackground(wxEraseEvent &event) {}
|
void OnEraseBackground(wxEraseEvent &event) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// DOCME
|
VideoSlider(wxWindow* parent, agi::Context *c);
|
||||||
VideoDisplay *Display;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
SubtitlesGrid *grid;
|
|
||||||
|
|
||||||
VideoSlider(wxWindow* parent, wxWindowID id);
|
|
||||||
~VideoSlider();
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue