speeddurdialog now sets speed correctly
This commit is contained in:
@@ -23,18 +23,28 @@
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, QWidget *parent) :
|
||||
QDialog(parent)
|
||||
#define super QDialog
|
||||
|
||||
SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, const rational &timebase, QWidget *parent) :
|
||||
super(parent),
|
||||
clips_(clips),
|
||||
timebase_(timebase)
|
||||
{
|
||||
setWindowTitle(tr("Speed/Duration"));
|
||||
|
||||
QGridLayout *layout = new QGridLayout(this);
|
||||
|
||||
int row = 0;
|
||||
|
||||
layout->addWidget(new QLabel(tr("Speed:")), row, 0);
|
||||
|
||||
FloatSlider *speed_slider_ = new FloatSlider();
|
||||
speed_slider_ = new FloatSlider();
|
||||
speed_slider_->SetDisplayType(FloatSlider::kPercentage);
|
||||
connect(speed_slider_, &FloatSlider::ValueChanged, this, &SpeedDurationDialog::SpeedChanged);
|
||||
layout->addWidget(speed_slider_, row, 1);
|
||||
|
||||
row++;
|
||||
@@ -42,11 +52,20 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, QWid
|
||||
layout->addWidget(new QLabel(tr("Duration:")), row, 0);
|
||||
|
||||
dur_slider_ = new RationalSlider();
|
||||
dur_slider_->SetTimebase(timebase);
|
||||
dur_slider_->SetDisplayType(RationalSlider::kTime);
|
||||
connect(dur_slider_, &RationalSlider::ValueChanged, this, &SpeedDurationDialog::DurationChanged);
|
||||
layout->addWidget(dur_slider_, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
ripple_box_ = new QCheckBox();
|
||||
link_box_ = new QCheckBox(tr("Link Speed and Duration"));
|
||||
link_box_->setChecked(true);
|
||||
layout->addWidget(link_box_, row, 0, 1, 2);
|
||||
|
||||
row++;
|
||||
|
||||
ripple_box_ = new QCheckBox(tr("Ripple Trailing Clips"));
|
||||
layout->addWidget(ripple_box_, row, 0, 1, 2);
|
||||
|
||||
row++;
|
||||
@@ -56,6 +75,119 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, QWid
|
||||
connect(btns, &QDialogButtonBox::accepted, this, &SpeedDurationDialog::accept);
|
||||
connect(btns, &QDialogButtonBox::rejected, this, &SpeedDurationDialog::reject);
|
||||
layout->addWidget(btns, row, 0, 1, 2);
|
||||
|
||||
// Determine which speed value to use
|
||||
start_speed_ = clips.first()->speed();
|
||||
start_duration_ = clips.first()->length();
|
||||
for (int i=1; i<clips.size(); i++) {
|
||||
if (!qIsNaN(start_speed_) && !qFuzzyCompare(start_speed_, clips.at(i)->speed())) {
|
||||
// Speed differs per clip
|
||||
start_speed_ = qSNaN();
|
||||
}
|
||||
|
||||
if (start_duration_ != -1 && clips.at(i)->length() != start_duration_) {
|
||||
start_duration_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (qIsNaN(start_speed_)) {
|
||||
speed_slider_->SetTristate();
|
||||
} else {
|
||||
speed_slider_->SetValue(start_speed_);
|
||||
}
|
||||
|
||||
if (start_duration_ == -1) {
|
||||
dur_slider_->SetTristate();
|
||||
} else {
|
||||
dur_slider_->SetValue(start_duration_);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedDurationDialog::accept()
|
||||
{
|
||||
super::accept();
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
// Set speed values
|
||||
if (speed_slider_->IsTristate()) {
|
||||
if (link_box_->isChecked() && !dur_slider_->IsTristate()) {
|
||||
// Automatically determine speed from duration
|
||||
foreach (ClipBlock *c, clips_) {
|
||||
command->add_child(new SetSpeedCommand(c, GetSpeedAdjustment(c->speed(), c->length(), dur_slider_->GetValue())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Set speeds to value of slider
|
||||
foreach (ClipBlock *c, clips_) {
|
||||
command->add_child(new SetSpeedCommand(c, speed_slider_->GetValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// Set duration values
|
||||
if (ripple_box_->isChecked()) {
|
||||
// Determine where and how much we need to ripple
|
||||
foreach (ClipBlock *c, clips_) {
|
||||
rational new_len = c->length();
|
||||
if (dur_slider_->IsTristate()) {
|
||||
if (link_box_->isChecked() && !speed_slider_->IsTristate()) {
|
||||
new_len = GetLengthAdjustment(c->length(), c->speed(), speed_slider_->GetValue(), timebase_);
|
||||
}
|
||||
} else {
|
||||
new_len = dur_slider_->GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
}
|
||||
|
||||
rational SpeedDurationDialog::GetLengthAdjustment(const rational &original_length, double original_speed, double new_speed, const rational &timebase)
|
||||
{
|
||||
return Timecode::snap_time_to_timebase(rational::fromDouble(original_length.toDouble() / new_speed * original_speed), timebase);
|
||||
}
|
||||
|
||||
double SpeedDurationDialog::GetSpeedAdjustment(double original_speed, const rational &original_length, const rational &new_length)
|
||||
{
|
||||
return original_speed / new_length.toDouble() * original_length.toDouble();
|
||||
}
|
||||
|
||||
void SpeedDurationDialog::SpeedChanged(double s)
|
||||
{
|
||||
if (!link_box_->isChecked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start_duration_ == -1) {
|
||||
dur_slider_->SetTristate();
|
||||
} else {
|
||||
dur_slider_->SetValue(GetLengthAdjustment(start_duration_, start_speed_, s, timebase_));
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedDurationDialog::DurationChanged(const rational &r)
|
||||
{
|
||||
if (!link_box_->isChecked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (qIsNaN(start_speed_)) {
|
||||
speed_slider_->SetTristate();
|
||||
} else {
|
||||
speed_slider_->SetValue(GetSpeedAdjustment(start_speed_, start_duration_, r));
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedDurationDialog::SetSpeedCommand::redo()
|
||||
{
|
||||
old_speed_ = clip_->speed();
|
||||
clip_->set_speed(new_speed_);
|
||||
}
|
||||
|
||||
void SpeedDurationDialog::SetSpeedCommand::undo()
|
||||
{
|
||||
clip_->set_speed(old_speed_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QDialog>
|
||||
|
||||
#include "node/block/clip/clip.h"
|
||||
#include "undo/undocommand.h"
|
||||
#include "widget/slider/floatslider.h"
|
||||
#include "widget/slider/rationalslider.h"
|
||||
|
||||
@@ -34,17 +35,63 @@ class SpeedDurationDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpeedDurationDialog(const QVector<ClipBlock*> &clips, QWidget *parent = nullptr);
|
||||
explicit SpeedDurationDialog(const QVector<ClipBlock*> &clips, const rational &timebase, QWidget *parent = nullptr);
|
||||
|
||||
class SetSpeedCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
SetSpeedCommand(ClipBlock *clip, double new_speed) :
|
||||
clip_(clip),
|
||||
new_speed_(new_speed)
|
||||
{}
|
||||
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return clip_->project();
|
||||
}
|
||||
|
||||
private:
|
||||
ClipBlock *clip_;
|
||||
double new_speed_;
|
||||
double old_speed_;
|
||||
|
||||
};
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
static rational GetLengthAdjustment(const rational &original_length, double original_speed, double new_speed, const rational &timebase);
|
||||
|
||||
static double GetSpeedAdjustment(double original_speed, const rational &original_length, const rational &new_length);
|
||||
|
||||
QVector<ClipBlock*> clips_;
|
||||
|
||||
FloatSlider *speed_slider_;
|
||||
|
||||
RationalSlider *dur_slider_;
|
||||
|
||||
QCheckBox *link_box_;
|
||||
|
||||
QCheckBox *ripple_box_;
|
||||
|
||||
double start_speed_;
|
||||
|
||||
rational start_duration_;
|
||||
|
||||
rational timebase_;
|
||||
|
||||
private slots:
|
||||
void SpeedChanged(double s);
|
||||
|
||||
void DurationChanged(const rational &r);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -92,6 +92,11 @@ public:
|
||||
|
||||
virtual void NudgeRight() override;
|
||||
|
||||
void ShowSpeedDurationDialogForSelectedClips()
|
||||
{
|
||||
timeline_widget()->ShowSpeedDurationDialogForSelectedClips();
|
||||
}
|
||||
|
||||
void InsertFootageAtPlayhead(const QVector<ViewerOutput *> &footage);
|
||||
|
||||
void OverwriteFootageAtPlayhead(const QVector<ViewerOutput *> &footage);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "dialog/speedduration/speeddurationdialog.h"
|
||||
#include "panel/panelmanager.h"
|
||||
#include "panel/timeline/timeline.h"
|
||||
#include "window/mainwindow/mainwindow.h"
|
||||
@@ -47,7 +46,7 @@ MenuShared::MenuShared()
|
||||
edit_delete_item_ = Menu::CreateItem(this, "delete", this, &MenuShared::DeleteSelectedTriggered, "Del");
|
||||
edit_ripple_delete_item_ = Menu::CreateItem(this, "rippledelete", this, &MenuShared::RippleDeleteTriggered, "Shift+Del");
|
||||
edit_split_item_ = Menu::CreateItem(this, "split", this, &MenuShared::SplitAtPlayheadTriggered, "Ctrl+K");
|
||||
edit_speedduration_item_ = Menu::CreateItem(this, "speeddur", this, &MenuShared::SpeedDurationTriggered);
|
||||
edit_speedduration_item_ = Menu::CreateItem(this, "speeddur", this, &MenuShared::SpeedDurationTriggered, "Ctrl+R");
|
||||
|
||||
// "In/Out" menu shared items
|
||||
inout_set_in_item_ = Menu::CreateItem(this, "setinpoint", this, &MenuShared::SetInTriggered, "I");
|
||||
@@ -310,18 +309,7 @@ void MenuShared::SpeedDurationTriggered()
|
||||
TimelinePanel* timeline = PanelManager::instance()->MostRecentlyFocused<TimelinePanel>();
|
||||
|
||||
if (timeline) {
|
||||
QVector<Block*> sel = timeline->GetSelectedBlocks();
|
||||
QVector<ClipBlock*> clips;
|
||||
|
||||
foreach (Block *b, sel) {
|
||||
ClipBlock *c = dynamic_cast<ClipBlock*>(b);
|
||||
if (c) {
|
||||
clips.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
SpeedDurationDialog sdd(clips, Core::instance()->main_window());
|
||||
sdd.exec();
|
||||
timeline->ShowSpeedDurationDialogForSelectedClips();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "dialog/nodeproperties/nodepropertiesdialog.h"
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "dialog/speedduration/speeddurationdialog.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "tool/add.h"
|
||||
#include "tool/beam.h"
|
||||
@@ -738,6 +739,23 @@ void TimelineWidget::NudgeRight()
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::ShowSpeedDurationDialogForSelectedClips()
|
||||
{
|
||||
QVector<ClipBlock*> clips;
|
||||
|
||||
foreach (Block *b, selected_blocks_) {
|
||||
ClipBlock *c = dynamic_cast<ClipBlock*>(b);
|
||||
if (c) {
|
||||
clips.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (!clips.isEmpty()) {
|
||||
SpeedDurationDialog sdd(clips, timebase(), this);
|
||||
sdd.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, MultiUndoCommand *command)
|
||||
{
|
||||
for (int i=0;i<Track::kCount;i++) {
|
||||
|
||||
@@ -95,6 +95,8 @@ public:
|
||||
|
||||
void NudgeRight();
|
||||
|
||||
void ShowSpeedDurationDialogForSelectedClips();
|
||||
|
||||
/**
|
||||
* @brief Timelines should always be connected to sequences
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user