688 lines
18 KiB
C++
688 lines
18 KiB
C++
/***
|
|
|
|
Olive - Non-Linear Video Editor
|
|
Copyright (C) 2020 Olive Team
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#include "timebasedwidget.h"
|
|
|
|
#include <QInputDialog>
|
|
|
|
#include "common/autoscroll.h"
|
|
#include "common/timecodefunctions.h"
|
|
#include "config/config.h"
|
|
#include "core.h"
|
|
#include "node/project/sequence/sequence.h"
|
|
#include "widget/timelinewidget/timelineundo.h"
|
|
|
|
namespace olive {
|
|
|
|
TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_status_visible, QWidget *parent) :
|
|
TimelineScaledWidget(parent),
|
|
viewer_node_(nullptr),
|
|
auto_max_scrollbar_(false),
|
|
toggle_show_all_(false),
|
|
auto_set_timebase_(true)
|
|
{
|
|
ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this);
|
|
connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal);
|
|
|
|
scrollbar_ = new ResizableTimelineScrollBar(Qt::Horizontal, this);
|
|
connect(scrollbar_, &ResizableScrollBar::ResizeBegan, this, &TimeBasedWidget::ScrollBarResizeBegan);
|
|
connect(scrollbar_, &ResizableScrollBar::ResizeMoved, this, &TimeBasedWidget::ScrollBarResizeMoved);
|
|
|
|
PassWheelEventsToScrollBar(ruler_);
|
|
}
|
|
|
|
void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale)
|
|
{
|
|
SetScale(scale);
|
|
|
|
// Zoom towards the playhead
|
|
// (using a hacky singleShot so the scroll occurs after the scene and its scrollbars have updated)
|
|
QTimer::singleShot(0, this, &TimeBasedWidget::CenterScrollOnPlayhead);
|
|
}
|
|
|
|
rational TimeBasedWidget::GetTime() const
|
|
{
|
|
return Timecode::timestamp_to_time(ruler()->GetTime(), timebase());
|
|
}
|
|
|
|
const int64_t &TimeBasedWidget::GetTimestamp() const
|
|
{
|
|
return ruler_->GetTime();
|
|
}
|
|
|
|
ViewerOutput *TimeBasedWidget::GetConnectedNode() const
|
|
{
|
|
return viewer_node_;
|
|
}
|
|
|
|
void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
|
|
{
|
|
// Ignore no-op
|
|
if (viewer_node_ == node) {
|
|
return;
|
|
}
|
|
|
|
if (viewer_node_) {
|
|
// Call potential derivative functions for disconnecting the viewer node
|
|
DisconnectNodeEvent(viewer_node_);
|
|
|
|
// Disconnect length changed signal
|
|
disconnect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll);
|
|
|
|
// Disconnect rate change signals if they were connected
|
|
disconnect(viewer_node_, &ViewerOutput::FrameRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase);
|
|
disconnect(viewer_node_, &ViewerOutput::SampleRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase);
|
|
|
|
// Reset timebase to null
|
|
SetTimebase(rational());
|
|
|
|
// Disconnect ruler and scrollbar from timeline points
|
|
ruler()->ConnectTimelinePoints(nullptr);
|
|
scrollbar_->ConnectTimelinePoints(nullptr);
|
|
}
|
|
|
|
// Set viewer node
|
|
ViewerOutput* old = viewer_node_;
|
|
viewer_node_ = node;
|
|
emit ConnectedNodeChanged(old, node);
|
|
|
|
// Call derivatives
|
|
ConnectedNodeChangeEvent(viewer_node_);
|
|
|
|
if (viewer_node_) {
|
|
// Connect length changed signal
|
|
connect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll);
|
|
|
|
// Connect ruler and scrollbar to timeline points
|
|
ruler()->ConnectTimelinePoints(viewer_node_->GetTimelinePoints());
|
|
scrollbar_->ConnectTimelinePoints(viewer_node_->GetTimelinePoints());
|
|
|
|
// If we're setting the timebase, set it automatically based on the video and audio parameters
|
|
if (auto_set_timebase_) {
|
|
AutoUpdateTimebase();
|
|
connect(viewer_node_, &ViewerOutput::FrameRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase);
|
|
connect(viewer_node_, &ViewerOutput::SampleRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase);
|
|
}
|
|
|
|
// Call derivatives
|
|
ConnectNodeEvent(viewer_node_);
|
|
}
|
|
|
|
UpdateMaximumScroll();
|
|
}
|
|
|
|
void TimeBasedWidget::UpdateMaximumScroll()
|
|
{
|
|
rational length = (viewer_node_) ? viewer_node_->GetLength() : 0;
|
|
|
|
if (auto_max_scrollbar_) {
|
|
scrollbar_->setMaximum(qMax(0, qCeil(TimeToScene(length)) - width()));
|
|
}
|
|
|
|
foreach (TimeBasedView* base, timeline_views_) {
|
|
base->SetEndTime(length);
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::ScrollBarResizeBegan(int current_bar_width, bool top_handle)
|
|
{
|
|
QScrollBar* bar = static_cast<QScrollBar*>(sender());
|
|
|
|
scrollbar_start_width_ = current_bar_width;
|
|
scrollbar_start_value_ = bar->value();
|
|
scrollbar_start_scale_ = GetScale();
|
|
scrollbar_top_handle_ = top_handle;
|
|
}
|
|
|
|
void TimeBasedWidget::ScrollBarResizeMoved(int movement)
|
|
{
|
|
ResizableScrollBar* bar = static_cast<ResizableScrollBar*>(sender());
|
|
|
|
// Negate movement for the top handle
|
|
if (scrollbar_top_handle_) {
|
|
movement = -movement;
|
|
}
|
|
|
|
// The user wants the bar to be this size
|
|
int proposed_size = scrollbar_start_width_ + movement;
|
|
|
|
double ratio = double(scrollbar_start_width_) / double(proposed_size);
|
|
|
|
if (ratio > 0) {
|
|
SetScale(scrollbar_start_scale_ * ratio);
|
|
|
|
if (scrollbar_top_handle_) {
|
|
int viewable_area;
|
|
|
|
if (timeline_views_.isEmpty()) {
|
|
viewable_area = width();
|
|
} else {
|
|
viewable_area = timeline_views_.first()->width();
|
|
}
|
|
|
|
bar->setValue((scrollbar_start_value_ + viewable_area) * ratio - viewable_area);
|
|
} else {
|
|
bar->setValue(scrollbar_start_value_ * ratio);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::PageScrollToPlayhead()
|
|
{
|
|
PageScrollInternal(qRound(TimeToScene(GetTime())), true);
|
|
}
|
|
|
|
void TimeBasedWidget::CatchUpScrollToPlayhead()
|
|
{
|
|
CatchUpScrollToPoint(qRound(TimeToScene(GetTime())));
|
|
}
|
|
|
|
void TimeBasedWidget::CatchUpScrollToPoint(int point)
|
|
{
|
|
PageScrollInternal(point, false);
|
|
}
|
|
|
|
void TimeBasedWidget::AutoUpdateTimebase()
|
|
{
|
|
rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base();
|
|
|
|
if (!video_tb.isNull()) {
|
|
SetTimebase(video_tb);
|
|
} else {
|
|
rational audio_tb = viewer_node_->GetAudioParams().sample_rate_as_time_base();
|
|
|
|
if (!audio_tb.isNull()) {
|
|
SetTimebase(audio_tb);
|
|
} else {
|
|
SetTimebase(rational());
|
|
}
|
|
}
|
|
}
|
|
|
|
TimeRuler *TimeBasedWidget::ruler() const
|
|
{
|
|
return ruler_;
|
|
}
|
|
|
|
ResizableTimelineScrollBar *TimeBasedWidget::scrollbar() const
|
|
{
|
|
return scrollbar_;
|
|
}
|
|
|
|
void TimeBasedWidget::TimebaseChangedEvent(const rational &timebase)
|
|
{
|
|
TimelineScaledWidget::TimebaseChangedEvent(timebase);
|
|
|
|
ruler_->SetTimebase(timebase);
|
|
scrollbar_->SetTimebase(timebase);
|
|
|
|
emit TimebaseChanged(timebase);
|
|
}
|
|
|
|
void TimeBasedWidget::ScaleChangedEvent(const double &scale)
|
|
{
|
|
TimelineScaledWidget::ScaleChangedEvent(scale);
|
|
|
|
ruler_->SetScale(scale);
|
|
scrollbar_->SetScale(scale);
|
|
|
|
UpdateMaximumScroll();
|
|
|
|
toggle_show_all_ = false;
|
|
}
|
|
|
|
void TimeBasedWidget::SetAutoMaxScrollBar(bool e)
|
|
{
|
|
auto_max_scrollbar_ = e;
|
|
}
|
|
|
|
void TimeBasedWidget::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
|
|
// Update horizontal scrollbar's page step to the width of the panel
|
|
scrollbar()->setPageStep(scrollbar()->width());
|
|
|
|
UpdateMaximumScroll();
|
|
}
|
|
|
|
void TimeBasedWidget::ConnectTimelineView(TimeBasedView *base, bool connect_time_change_event)
|
|
{
|
|
if (connect_time_change_event) {
|
|
connect(base, &TimeBasedView::TimeChanged, this, &TimeBasedWidget::SetTimestamp);
|
|
connect(base, &TimeBasedView::TimeChanged, this, &TimeBasedWidget::TimeChanged);
|
|
}
|
|
|
|
timeline_views_.append(base);
|
|
}
|
|
|
|
void TimeBasedWidget::PassWheelEventsToScrollBar(QObject *object)
|
|
{
|
|
wheel_passthrough_objects_.append(object);
|
|
object->installEventFilter(this);
|
|
}
|
|
|
|
void TimeBasedWidget::SetTimestamp(int64_t timestamp)
|
|
{
|
|
if (GetTime() != timestamp) {
|
|
if (UserIsDraggingPlayhead()) {
|
|
// If the user is dragging the playhead, we will simply nudge over and not use autoscroll rules.
|
|
QMetaObject::invokeMethod(this, "CatchUpScrollToPlayhead", Qt::QueuedConnection);
|
|
} else {
|
|
// Otherwise, assume we jumped to this out of nowhere and must now autoscroll
|
|
switch (static_cast<AutoScroll::Method>(Config::Current()["Autoscroll"].toInt())) {
|
|
case AutoScroll::kNone:
|
|
// Do nothing
|
|
break;
|
|
case AutoScroll::kPage:
|
|
QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection);
|
|
break;
|
|
case AutoScroll::kSmooth:
|
|
QMetaObject::invokeMethod(this, "CenterScrollOnPlayhead", Qt::QueuedConnection);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ruler_->SetTime(timestamp);
|
|
|
|
TimeChangedEvent(timestamp);
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::SetTimebase(const rational &timebase)
|
|
{
|
|
TimelineScaledWidget::SetTimebase(timebase);
|
|
}
|
|
|
|
void TimeBasedWidget::SetScale(const double &scale)
|
|
{
|
|
// Simple QObject slot wrapper around TimelineScaledWidget::SetScale()
|
|
TimelineScaledWidget::SetScale(scale);
|
|
}
|
|
|
|
void TimeBasedWidget::ZoomIn()
|
|
{
|
|
SetScaleAndCenterOnPlayhead(GetScale() * 2);
|
|
}
|
|
|
|
void TimeBasedWidget::ZoomOut()
|
|
{
|
|
SetScaleAndCenterOnPlayhead(GetScale() * 0.5);
|
|
}
|
|
|
|
void TimeBasedWidget::GoToPrevCut()
|
|
{
|
|
// Cuts are only possible in sequences
|
|
Sequence* sequence = dynamic_cast<Sequence*>(viewer_node_);
|
|
|
|
if (!sequence) {
|
|
return;
|
|
}
|
|
|
|
if (GetTimestamp() == 0) {
|
|
return;
|
|
}
|
|
|
|
int64_t closest_cut = 0;
|
|
|
|
foreach (Track* track, sequence->GetTracks()) {
|
|
int64_t this_track_closest_cut = 0;
|
|
|
|
foreach (Block* block, track->Blocks()) {
|
|
int64_t block_out_ts = Timecode::time_to_timestamp(block->out(), timebase());
|
|
|
|
if (block_out_ts < GetTimestamp()) {
|
|
this_track_closest_cut = block_out_ts;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
closest_cut = qMax(closest_cut, this_track_closest_cut);
|
|
}
|
|
|
|
SetTimeAndSignal(closest_cut);
|
|
}
|
|
|
|
void TimeBasedWidget::GoToNextCut()
|
|
{
|
|
// Cuts are only possible in sequences
|
|
Sequence* sequence = dynamic_cast<Sequence*>(viewer_node_);
|
|
|
|
if (!sequence) {
|
|
return;
|
|
}
|
|
|
|
int64_t closest_cut = INT64_MAX;
|
|
|
|
foreach (Track* track, sequence->GetTracks()) {
|
|
int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase());
|
|
|
|
if (this_track_closest_cut <= GetTimestamp()) {
|
|
this_track_closest_cut = INT64_MAX;
|
|
}
|
|
|
|
foreach (Block* block, track->Blocks()) {
|
|
int64_t block_in_ts = Timecode::time_to_timestamp(block->in(), timebase());
|
|
|
|
if (block_in_ts > GetTimestamp()) {
|
|
this_track_closest_cut = block_in_ts;
|
|
break;
|
|
}
|
|
}
|
|
|
|
closest_cut = qMin(closest_cut, this_track_closest_cut);
|
|
}
|
|
|
|
if (closest_cut < INT64_MAX) {
|
|
SetTimeAndSignal(closest_cut);
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::GoToStart()
|
|
{
|
|
if (viewer_node_) {
|
|
SetTimeAndSignal(0);
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::PrevFrame()
|
|
{
|
|
if (viewer_node_) {
|
|
SetTimeAndSignal(qMax(static_cast<int64_t>(0), ruler()->GetTime() - 1));
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::NextFrame()
|
|
{
|
|
if (viewer_node_) {
|
|
SetTimeAndSignal(ruler()->GetTime() + 1);
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::GoToEnd()
|
|
{
|
|
if (viewer_node_) {
|
|
SetTimeAndSignal(Timecode::time_to_timestamp(viewer_node_->GetLength(), timebase()));
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::SetTimeAndSignal(const int64_t &t)
|
|
{
|
|
SetTimestamp(t);
|
|
emit TimeChanged(t);
|
|
}
|
|
|
|
void TimeBasedWidget::CenterScrollOnPlayhead()
|
|
{
|
|
scrollbar_->setValue(qRound(TimeToScene(Timecode::timestamp_to_time(ruler_->GetTime(), timebase()))) - scrollbar_->width()/2);
|
|
}
|
|
|
|
void TimeBasedWidget::SetAutoSetTimebase(bool e)
|
|
{
|
|
auto_set_timebase_ = e;
|
|
}
|
|
|
|
void TimeBasedWidget::SetPoint(Timeline::MovementMode m, const rational& time)
|
|
{
|
|
if (!viewer_node_) {
|
|
return;
|
|
}
|
|
|
|
MultiUndoCommand* command = new MultiUndoCommand();
|
|
TimelinePoints* points = viewer_node_->GetTimelinePoints();
|
|
|
|
// Enable workarea if it isn't already enabled
|
|
if (!points->workarea()->enabled()) {
|
|
command->add_child(new WorkareaSetEnabledCommand(viewer_node_->project(), points, true));
|
|
}
|
|
|
|
// Determine our new range
|
|
rational in_point, out_point;
|
|
|
|
if (m == Timeline::kTrimIn) {
|
|
in_point = time;
|
|
|
|
if (!points->workarea()->enabled() || points->workarea()->out() < in_point) {
|
|
out_point = TimelineWorkArea::kResetOut;
|
|
} else {
|
|
out_point = points->workarea()->out();
|
|
}
|
|
} else {
|
|
out_point = time;
|
|
|
|
if (!points->workarea()->enabled() || points->workarea()->in() > out_point) {
|
|
in_point = TimelineWorkArea::kResetIn;
|
|
} else {
|
|
in_point = points->workarea()->in();
|
|
}
|
|
}
|
|
|
|
// Set workarea
|
|
command->add_child(new WorkareaSetRangeCommand(viewer_node_->project(), points, TimeRange(in_point, out_point)));
|
|
|
|
Core::instance()->undo_stack()->push(command);
|
|
}
|
|
|
|
void TimeBasedWidget::ResetPoint(Timeline::MovementMode m)
|
|
{
|
|
if (!GetConnectedNode()) {
|
|
return;
|
|
}
|
|
|
|
TimelinePoints* points = GetConnectedNode()->GetTimelinePoints();
|
|
|
|
if (!GetConnectedNode() || !points->workarea()->enabled()) {
|
|
return;
|
|
}
|
|
|
|
TimeRange r = points->workarea()->range();
|
|
|
|
if (m == Timeline::kTrimIn) {
|
|
r.set_in(TimelineWorkArea::kResetIn);
|
|
} else {
|
|
r.set_out(TimelineWorkArea::kResetOut);
|
|
}
|
|
|
|
Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(viewer_node_->project(), points, r));
|
|
}
|
|
|
|
void TimeBasedWidget::PageScrollInternal(QScrollBar *bar, int maximum, int screen_position, bool whole_page_scroll)
|
|
{
|
|
int viewport_padding = maximum / 16;
|
|
|
|
if (whole_page_scroll) {
|
|
if (screen_position < bar->value()) {
|
|
// Anchor the playhead to the RIGHT of where we scroll to
|
|
bar->setValue(screen_position - maximum + viewport_padding);
|
|
} else if (screen_position > bar->value() + maximum) {
|
|
// Anchor the playhead to the LEFT of where we scroll to
|
|
bar->setValue(screen_position - viewport_padding);
|
|
}
|
|
} else {
|
|
// Just jump in increments
|
|
if (screen_position < bar->value() + viewport_padding) {
|
|
bar->setValue(bar->value() - viewport_padding);
|
|
} else if (screen_position > bar->value() + maximum - viewport_padding) {
|
|
bar->setValue(bar->value() + viewport_padding);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::PageScrollInternal(int screen_position, bool whole_page_scroll)
|
|
{
|
|
PageScrollInternal(scrollbar(), ruler()->width(), screen_position, whole_page_scroll);
|
|
}
|
|
|
|
bool TimeBasedWidget::UserIsDraggingPlayhead() const
|
|
{
|
|
if (ruler_->IsDraggingPlayhead()) {
|
|
return true;
|
|
}
|
|
|
|
foreach (TimeBasedView* view, timeline_views_) {
|
|
if (view->IsDraggingPlayhead()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TimeBasedWidget::SetInAtPlayhead()
|
|
{
|
|
SetPoint(Timeline::kTrimIn, GetTime());
|
|
}
|
|
|
|
void TimeBasedWidget::SetOutAtPlayhead()
|
|
{
|
|
SetPoint(Timeline::kTrimOut, GetTime());
|
|
}
|
|
|
|
void TimeBasedWidget::ResetIn()
|
|
{
|
|
ResetPoint(Timeline::kTrimIn);
|
|
}
|
|
|
|
void TimeBasedWidget::ResetOut()
|
|
{
|
|
ResetPoint(Timeline::kTrimOut);
|
|
}
|
|
|
|
void TimeBasedWidget::ClearInOutPoints()
|
|
{
|
|
if (!GetConnectedNode()) {
|
|
return;
|
|
}
|
|
|
|
|
|
Core::instance()->undo_stack()->push(new WorkareaSetEnabledCommand(GetConnectedNode()->project(), GetConnectedNode()->GetTimelinePoints(), false));
|
|
}
|
|
|
|
void TimeBasedWidget::SetMarker()
|
|
{
|
|
if (!GetConnectedNode()) {
|
|
return;
|
|
}
|
|
|
|
bool ok;
|
|
QString marker_name;
|
|
|
|
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
|
|
marker_name = QInputDialog::getText(this, tr("Set Marker"), tr("Marker name:"), QLineEdit::Normal, QString(), &ok);
|
|
} else {
|
|
ok = true;
|
|
}
|
|
|
|
if (ok) {
|
|
Core::instance()->undo_stack()->push(new MarkerAddCommand(GetConnectedNode()->project(),
|
|
GetConnectedNode()->GetTimelinePoints()->markers(), TimeRange(GetTime(), GetTime()), marker_name));
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::ToggleShowAll()
|
|
{
|
|
if (!GetConnectedNode()) {
|
|
return;
|
|
}
|
|
|
|
if (toggle_show_all_) {
|
|
SetScale(toggle_show_all_old_scale_);
|
|
scrollbar_->setValue(toggle_show_all_old_scroll_);
|
|
|
|
// Don't have to set toggle_show_all_ because SetScale() will automatically set it to false
|
|
} else {
|
|
int w;
|
|
|
|
if (timeline_views_.isEmpty()) {
|
|
w = width();
|
|
} else {
|
|
w = timeline_views_.first()->width();
|
|
}
|
|
|
|
|
|
|
|
toggle_show_all_old_scale_ = GetScale();
|
|
toggle_show_all_old_scroll_ = scrollbar_->value();
|
|
|
|
SetScaleFromDimensions(w, GetConnectedNode()->GetLength().toDouble());
|
|
scrollbar_->setValue(0);
|
|
|
|
// Must explicitly do this because SetScale() will automatically set this to false
|
|
toggle_show_all_ = true;
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::GoToIn()
|
|
{
|
|
if (GetConnectedNode()) {
|
|
if (GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
|
|
SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedNode()->GetTimelinePoints()->workarea()->in(), timebase()));
|
|
} else {
|
|
GoToStart();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TimeBasedWidget::GoToOut()
|
|
{
|
|
if (GetConnectedNode()) {
|
|
if (GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
|
|
SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedNode()->GetTimelinePoints()->workarea()->out(), timebase()));
|
|
} else {
|
|
GoToEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
TimeBasedWidget::MarkerAddCommand::MarkerAddCommand(Project *project, TimelineMarkerList *marker_list, const TimeRange &range, const QString &name) :
|
|
project_(project),
|
|
marker_list_(marker_list),
|
|
range_(range),
|
|
name_(name)
|
|
{
|
|
}
|
|
|
|
Project *TimeBasedWidget::MarkerAddCommand::GetRelevantProject() const
|
|
{
|
|
return project_;
|
|
}
|
|
|
|
void TimeBasedWidget::MarkerAddCommand::redo()
|
|
{
|
|
added_marker_ = marker_list_->AddMarker(range_, name_);
|
|
}
|
|
|
|
void TimeBasedWidget::MarkerAddCommand::undo()
|
|
{
|
|
marker_list_->RemoveMarker(added_marker_);
|
|
}
|
|
|
|
bool TimeBasedWidget::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
if (wheel_passthrough_objects_.contains(object) && event->type() == QEvent::Wheel) {
|
|
QCoreApplication::sendEvent(scrollbar(), event);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|