Merge branch 'master' into track-redux
This commit is contained in:
+17
-2
@@ -24,14 +24,25 @@
|
||||
#include <QtGlobal>
|
||||
#include <cmath>
|
||||
|
||||
//#define ALLOW_RETURNING_INFINITY
|
||||
|
||||
namespace olive {
|
||||
|
||||
class Decibel
|
||||
{
|
||||
public:
|
||||
// In basically all circumstances, this should calculate to 0.0 linear
|
||||
static constexpr double MINIMUM = -200.0;
|
||||
|
||||
static double fromLinear(double linear)
|
||||
{
|
||||
return double(20.0) * std::log10(linear);
|
||||
double v = double(20.0) * std::log10(linear);
|
||||
#ifndef ALLOW_RETURNING_INFINITY
|
||||
if (std::isinf(v)) {
|
||||
return MINIMUM;
|
||||
}
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static double toLinear(double decibel)
|
||||
@@ -49,7 +60,11 @@ public:
|
||||
static double fromLogarithmic(double logarithmic)
|
||||
{
|
||||
if (logarithmic < 0.001)
|
||||
return -200.0;
|
||||
#ifdef ALLOW_RETURNING_INFINITY
|
||||
return std::numeric_limits<double>::infinity();
|
||||
#else
|
||||
return MINIMUM;
|
||||
#endif
|
||||
else if (logarithmic > 0.99)
|
||||
return 0;
|
||||
else
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/define.h"
|
||||
#include "opentimelineio/timeline.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
|
||||
@@ -69,7 +69,9 @@ ClipBlock::ClipBlock() :
|
||||
|
||||
QString ClipBlock::Name() const
|
||||
{
|
||||
if (track()) {
|
||||
if (connected_viewer_ && !connected_viewer_->GetLabel().isEmpty()) {
|
||||
return connected_viewer_->GetLabel();
|
||||
} else if (track()) {
|
||||
if (track()->type() == Track::kVideo) {
|
||||
return tr("Video Clip");
|
||||
} else if (track()->type() == Track::kAudio) {
|
||||
|
||||
@@ -29,9 +29,16 @@ LineGizmo::LineGizmo(QObject *parent) :
|
||||
|
||||
void LineGizmo::Draw(QPainter *p) const
|
||||
{
|
||||
p->setBrush(Qt::NoBrush);
|
||||
p->setPen(QPen(Qt::white, 0));
|
||||
// Draw transposed black
|
||||
QLineF transposed = p->transform().map(line_);
|
||||
transposed.translate(1, 1);
|
||||
transposed = p->transform().inverted().map(transposed);
|
||||
p->setPen(QPen(Qt::black, 0));
|
||||
p->drawLine(transposed);
|
||||
|
||||
// Draw normal white polygon
|
||||
p->setPen(QPen(Qt::white, 0));
|
||||
p->setBrush(Qt::NoBrush);
|
||||
p->drawLine(line_);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,16 @@ PathGizmo::PathGizmo(QObject *parent) :
|
||||
|
||||
void PathGizmo::Draw(QPainter *p) const
|
||||
{
|
||||
// Draw transposed black
|
||||
QPainterPath transposed = p->transform().map(path_);
|
||||
transposed.translate(1, 1);
|
||||
transposed = p->transform().inverted().map(transposed);
|
||||
p->setPen(QPen(Qt::black, 0));
|
||||
p->drawPath(transposed);
|
||||
|
||||
// Draw normal white polygon
|
||||
p->setPen(QPen(Qt::white, 0));
|
||||
p->setBrush(Qt::NoBrush);
|
||||
|
||||
p->drawPath(path_);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ void PointGizmo::Draw(QPainter *p) const
|
||||
QRectF rect = GetDrawingRect(p->transform(), GetStandardRadius());
|
||||
|
||||
if (shape_ != kAnchorPoint) {
|
||||
p->setPen(Qt::NoPen);
|
||||
p->setPen(QPen(Qt::black, 0));
|
||||
p->setBrush(Qt::white);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,16 @@ PolygonGizmo::PolygonGizmo(QObject *parent)
|
||||
|
||||
void PolygonGizmo::Draw(QPainter *p) const
|
||||
{
|
||||
// Draw transposed black
|
||||
QPolygonF transposed = p->transform().map(polygon_);
|
||||
transposed.translate(1, 1);
|
||||
transposed = p->transform().inverted().map(transposed);
|
||||
p->setPen(QPen(Qt::black, 0));
|
||||
p->drawPolyline(transposed);
|
||||
|
||||
// Draw normal white polygon
|
||||
p->setPen(QPen(Qt::white, 0));
|
||||
p->setBrush(Qt::NoBrush);
|
||||
|
||||
p->drawPolyline(polygon_);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@ TextGizmo::TextGizmo(QObject *parent)
|
||||
|
||||
}
|
||||
|
||||
void TextGizmo::SetRect(const QRectF &r)
|
||||
{
|
||||
rect_ = r;
|
||||
emit RectChanged(rect_);
|
||||
}
|
||||
|
||||
void TextGizmo::UpdateInputHtml(const QString &s, const rational &time)
|
||||
{
|
||||
if (input_.IsValid()) {
|
||||
@@ -41,4 +47,10 @@ void TextGizmo::UpdateInputHtml(const QString &s, const rational &time)
|
||||
}
|
||||
}
|
||||
|
||||
void TextGizmo::SetVerticalAlignment(Qt::Alignment va)
|
||||
{
|
||||
valign_ = va;
|
||||
emit VerticalAlignmentChanged(valign_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-11
@@ -33,7 +33,7 @@ public:
|
||||
explicit TextGizmo(QObject *parent = nullptr);
|
||||
|
||||
const QRectF &GetRect() const { return rect_; }
|
||||
void SetRect(const QRectF &r) { rect_ = r; }
|
||||
void SetRect(const QRectF &r);
|
||||
|
||||
const QString &GetHtml() const { return text_; }
|
||||
void SetHtml(const QString &t) { text_ = t; }
|
||||
@@ -42,21 +42,14 @@ public:
|
||||
|
||||
void UpdateInputHtml(const QString &s, const rational &time);
|
||||
|
||||
Qt::Alignment GetVerticalAlignment() const
|
||||
{
|
||||
return valign_;
|
||||
}
|
||||
|
||||
void SetVerticalAlignment(Qt::Alignment va)
|
||||
{
|
||||
valign_ = va;
|
||||
emit VerticalAlignmentChanged(valign_);
|
||||
}
|
||||
Qt::Alignment GetVerticalAlignment() const { return valign_; }
|
||||
void SetVerticalAlignment(Qt::Alignment va);
|
||||
|
||||
signals:
|
||||
void Activated();
|
||||
void Deactivated();
|
||||
void VerticalAlignmentChanged(Qt::Alignment va);
|
||||
void RectChanged(const QRectF &r);
|
||||
|
||||
private:
|
||||
QRectF rect_;
|
||||
|
||||
@@ -160,6 +160,10 @@ bool NodeGroup::GetInner(NodeInput *input)
|
||||
{
|
||||
if (NodeGroup *g = dynamic_cast<NodeGroup*>(input->node())) {
|
||||
const NodeInput &passthrough = g->GetInputFromID(input->input());
|
||||
if (!passthrough.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
input->set_node(passthrough.node());
|
||||
input->set_input(passthrough.input());
|
||||
return true;
|
||||
|
||||
@@ -35,6 +35,7 @@ const QVector<NodeValue::Type> ValueNode::kSupportedTypes = {
|
||||
NodeValue::kText,
|
||||
NodeValue::kMatrix,
|
||||
NodeValue::kFont,
|
||||
NodeValue::kBoolean,
|
||||
};
|
||||
|
||||
#define super Node
|
||||
|
||||
@@ -329,6 +329,13 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear duplicate label (to facilitate #2147)
|
||||
if (ClipBlock *c = dynamic_cast<ClipBlock*>(n)) {
|
||||
if (c->connected_viewer() && c->GetLabel() == c->connected_viewer()->GetLabel()) {
|
||||
c->SetLabel(QString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return load_data;
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
#include "node/distort/transform/transformdistortnode.h"
|
||||
#include "node/generator/matrix/matrix.h"
|
||||
#include "node/math/math/math.h"
|
||||
#include "node/nodeundo.h"
|
||||
#include "node/project/folder/folder.h"
|
||||
#include "node/project/footage/footage.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "timeline/timelineundogeneral.h"
|
||||
#include "window/mainwindow/mainwindowundo.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
#include "widget/timelinewidget/undo/timelineundogeneral.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#ifdef USE_OTIO
|
||||
|
||||
#include "common/otioutils.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project.h"
|
||||
#include "task/project/load/loadbasetask.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <opentimelineio/track.h>
|
||||
|
||||
#include "common/otioutils.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project.h"
|
||||
#include "task/task.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -203,6 +203,8 @@ void TrackSlideCommand::redo()
|
||||
|
||||
in_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
|
||||
we_removed_in_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() + movement_);
|
||||
@@ -225,6 +227,8 @@ void TrackSlideCommand::redo()
|
||||
|
||||
out_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
|
||||
we_removed_out_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() - movement_);
|
||||
@@ -246,9 +250,13 @@ void TrackSlideCommand::undo()
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(in_adjacent_);
|
||||
in_adjacent_->setParent(&memory_manager_);
|
||||
} else if (in_adjacent_remove_command_) {
|
||||
// We removed this, so we can restore it now
|
||||
in_adjacent_remove_command_->undo_now();
|
||||
} else if (we_removed_in_adjacent_) {
|
||||
if (in_adjacent_remove_command_) {
|
||||
// We removed this, so we can restore it now
|
||||
in_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
|
||||
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() - movement_);
|
||||
@@ -259,8 +267,12 @@ void TrackSlideCommand::undo()
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(out_adjacent_);
|
||||
out_adjacent_->setParent(&memory_manager_);
|
||||
} else if (out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_->undo_now();
|
||||
} else if (we_removed_out_adjacent_) {
|
||||
if (out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
|
||||
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
|
||||
} else {
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() + movement_);
|
||||
}
|
||||
|
||||
@@ -116,8 +116,10 @@ public:
|
||||
track_(track),
|
||||
blocks_(moving_blocks),
|
||||
movement_(movement),
|
||||
we_removed_in_adjacent_(false),
|
||||
in_adjacent_(in_adjacent),
|
||||
in_adjacent_remove_command_(nullptr),
|
||||
we_removed_out_adjacent_(false),
|
||||
out_adjacent_(out_adjacent),
|
||||
out_adjacent_remove_command_(nullptr)
|
||||
{
|
||||
@@ -148,9 +150,11 @@ private:
|
||||
rational movement_;
|
||||
|
||||
bool we_created_in_adjacent_;
|
||||
bool we_removed_in_adjacent_;
|
||||
Block* in_adjacent_;
|
||||
UndoCommand* in_adjacent_remove_command_;
|
||||
bool we_created_out_adjacent_;
|
||||
bool we_removed_out_adjacent_;
|
||||
Block* out_adjacent_;
|
||||
UndoCommand* out_adjacent_remove_command_;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <QScrollBar>
|
||||
#include <QtMath>
|
||||
|
||||
#include "common/decibel.h"
|
||||
#include "common/qtutils.h"
|
||||
#include "node/nodeundo.h"
|
||||
#include "widget/keyframeview/keyframeviewundo.h"
|
||||
|
||||
@@ -157,7 +157,11 @@ bool HandMovableView::WheelEventIsAZoomEvent(QWheelEvent *event)
|
||||
|
||||
qreal HandMovableView::GetScrollZoomMultiplier(QWheelEvent *event)
|
||||
{
|
||||
return 1.0 + (static_cast<qreal>(event->angleDelta().x() + event->angleDelta().y()) * 0.001);
|
||||
qreal v = (static_cast<qreal>(event->angleDelta().x() + event->angleDelta().y()) * 0.001);
|
||||
if (event->inverted()) {
|
||||
v = -v;
|
||||
}
|
||||
return 1.0 + v;
|
||||
}
|
||||
|
||||
void HandMovableView::wheelEvent(QWheelEvent *event)
|
||||
|
||||
@@ -311,8 +311,7 @@ void NodeParamView::RequestEditTextInViewer()
|
||||
{
|
||||
NodeParamViewItem *item = static_cast<NodeParamViewItem *>(sender());
|
||||
|
||||
focused_node_ = item;
|
||||
emit FocusedNodeChanged(item->GetNode());
|
||||
SetSelectedNodes({item});
|
||||
emit RequestViewerToStartEditingText();
|
||||
}
|
||||
|
||||
@@ -726,6 +725,7 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context)
|
||||
connect(item, &NodeParamViewItem::ArrayExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::ExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::Moved, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::InputArraySizeChanged, this, &NodeParamView::InputArraySizeChanged);
|
||||
|
||||
item->SetKeyframeConnections(keyframe_view_->AddKeyframesOfNode(n));
|
||||
}
|
||||
@@ -999,4 +999,42 @@ void NodeParamView::GroupInputPassthroughRemoved(NodeGroup *group, const NodeInp
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::InputArraySizeChanged(const QString &input, int, int new_size)
|
||||
{
|
||||
NodeParamViewItem *sender = static_cast<NodeParamViewItem *>(this->sender());
|
||||
|
||||
KeyframeView::NodeConnections &connections = sender->GetKeyframeConnections();
|
||||
KeyframeView::InputConnections &inputs = connections[input];
|
||||
|
||||
int adj_new_size = new_size + 1;
|
||||
|
||||
if (adj_new_size != inputs.size()) {
|
||||
if (adj_new_size < inputs.size()) {
|
||||
// Remove elements from keyframe view
|
||||
for (int i = adj_new_size; i < inputs.size(); i++) {
|
||||
const KeyframeView::ElementConnections &ec = inputs.at(i);
|
||||
for (auto kc : ec) {
|
||||
keyframe_view_->RemoveKeyframesOfTrack(kc);
|
||||
}
|
||||
}
|
||||
|
||||
// Resize vector to match new size
|
||||
inputs.resize(adj_new_size);
|
||||
} else {
|
||||
// Add elements
|
||||
int old_size = inputs.size();
|
||||
|
||||
// Resize vector to match
|
||||
inputs.resize(adj_new_size);
|
||||
|
||||
// Fill in extra elements
|
||||
for (int i = old_size; i < inputs.size(); i++) {
|
||||
inputs[i] = keyframe_view_->AddKeyframesOfElement(NodeInput(sender->GetNode(), input, i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QueueKeyframePositionUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -190,6 +190,8 @@ private slots:
|
||||
|
||||
void RequestEditTextInViewer();
|
||||
|
||||
void InputArraySizeChanged(const QString &input, int old_size, int new_size);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior c
|
||||
body_(nullptr),
|
||||
node_(node),
|
||||
create_checkboxes_(create_checkboxes),
|
||||
ctx_(nullptr)
|
||||
ctx_(nullptr),
|
||||
time_target_(nullptr)
|
||||
{
|
||||
node_->Retranslate();
|
||||
|
||||
@@ -58,6 +59,7 @@ NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior c
|
||||
RecreateBody();
|
||||
|
||||
connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate);
|
||||
connect(node_, &Node::InputArraySizeChanged, this, &NodeParamViewItem::InputArraySizeChanged);
|
||||
|
||||
// FIXME: Implemented to pick up when an input is set to hidden or not - DEFINITELY not a fast
|
||||
// way of doing this, but "fine" for now.
|
||||
@@ -96,6 +98,7 @@ void NodeParamViewItem::RecreateBody()
|
||||
connect(body_, &NodeParamViewItemBody::RequestEditTextInViewer, this, &NodeParamViewItem::RequestEditTextInViewer);
|
||||
body_->Retranslate();
|
||||
body_->SetTimebase(timebase_);
|
||||
body_->SetTimeTarget(time_target_);
|
||||
SetBody(body_);
|
||||
}
|
||||
|
||||
@@ -117,6 +120,7 @@ void NodeParamViewItem::SetInputChecked(const NodeInput &input, bool e)
|
||||
NodeParamViewItemBody::NodeParamViewItemBody(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
node_(node),
|
||||
time_target_(nullptr),
|
||||
create_checkboxes_(create_checkboxes)
|
||||
{
|
||||
QGridLayout* root_layout = new QGridLayout(this);
|
||||
@@ -265,22 +269,32 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, Node *node, const
|
||||
if (node->IsInputConnectable(input)) {
|
||||
UpdateUIForEdgeConnection(input_ref);
|
||||
}
|
||||
|
||||
SetTimeTargetOnInputUI(ui_objects);
|
||||
SetTimebaseOnInputUI(ui_objects);
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::SetTimeTarget(ViewerOutput *target)
|
||||
{
|
||||
time_target_ = target;
|
||||
|
||||
foreach (const InputUI& ui_obj, input_ui_map_) {
|
||||
// Only keyframable inputs have a key control widget
|
||||
if (ui_obj.key_control) {
|
||||
ui_obj.key_control->SetTimeTarget(target);
|
||||
}
|
||||
if (ui_obj.connected_label) {
|
||||
ui_obj.connected_label->SetViewerNode(target);
|
||||
}
|
||||
ui_obj.widget_bridge->SetTimeTarget(target);
|
||||
SetTimeTargetOnInputUI(ui_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::SetTimeTargetOnInputUI(const InputUI &ui_obj)
|
||||
{
|
||||
// Only keyframable inputs have a key control widget
|
||||
if (ui_obj.key_control) {
|
||||
ui_obj.key_control->SetTimeTarget(time_target_);
|
||||
}
|
||||
if (ui_obj.connected_label) {
|
||||
ui_obj.connected_label->SetViewerNode(time_target_);
|
||||
}
|
||||
ui_obj.widget_bridge->SetTimeTarget(time_target_);
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::Retranslate()
|
||||
{
|
||||
for (auto i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
|
||||
@@ -444,7 +458,7 @@ void NodeParamViewItemBody::ArrayAppendClicked()
|
||||
for (auto it=array_ui_.cbegin(); it!=array_ui_.cend(); it++) {
|
||||
if (it.value().append_btn == sender()) {
|
||||
NodeInput real_input = NodeGroup::ResolveInput(NodeInput(it.key().node, it.key().input));
|
||||
Core::instance()->undo_stack()->push(new NodeArrayInsertCommand(real_input.node(), real_input.input(), real_input.GetArraySize()+1));
|
||||
Core::instance()->undo_stack()->push(new NodeArrayInsertCommand(real_input.node(), real_input.input(), real_input.GetArraySize()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -492,10 +506,15 @@ void NodeParamViewItemBody::SetTimebase(const rational& timebase)
|
||||
timebase_ = timebase;
|
||||
|
||||
foreach (const InputUI& ui_obj, input_ui_map_) {
|
||||
ui_obj.widget_bridge->SetTimebase(timebase);
|
||||
SetTimebaseOnInputUI(ui_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::SetTimebaseOnInputUI(const InputUI& ui_obj)
|
||||
{
|
||||
ui_obj.widget_bridge->SetTimebase(timebase_);
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::SetInputChecked(const NodeInput &input, bool e)
|
||||
{
|
||||
if (input_ui_map_.contains(input)) {
|
||||
|
||||
@@ -104,6 +104,9 @@ private:
|
||||
NodeParamViewArrayButton* append_btn;
|
||||
};
|
||||
|
||||
void SetTimeTargetOnInputUI(const InputUI &ui);
|
||||
void SetTimebaseOnInputUI(const InputUI &ui);
|
||||
|
||||
Node *node_;
|
||||
|
||||
QHash<NodeInputPair, ArrayUI> array_ui_;
|
||||
@@ -112,6 +115,8 @@ private:
|
||||
|
||||
rational timebase_;
|
||||
|
||||
ViewerOutput *time_target_;
|
||||
|
||||
NodeParamViewCheckBoxBehavior create_checkboxes_;
|
||||
|
||||
QHash<NodeInputPair, NodeInputPair> input_group_lookup_;
|
||||
@@ -165,6 +170,8 @@ public:
|
||||
|
||||
void SetTimeTarget(ViewerOutput* target)
|
||||
{
|
||||
time_target_ = target;
|
||||
|
||||
body_->SetTimeTarget(target);
|
||||
}
|
||||
|
||||
@@ -194,7 +201,7 @@ public:
|
||||
|
||||
void SetInputChecked(const NodeInput &input, bool e);
|
||||
|
||||
const KeyframeView::NodeConnections &GetKeyframeConnections() const
|
||||
KeyframeView::NodeConnections &GetKeyframeConnections()
|
||||
{
|
||||
return keyframe_connections_;
|
||||
}
|
||||
@@ -213,6 +220,8 @@ signals:
|
||||
|
||||
void RequestEditTextInViewer();
|
||||
|
||||
void InputArraySizeChanged(const QString &input, int old_size, int new_size);
|
||||
|
||||
protected slots:
|
||||
virtual void Retranslate() override;
|
||||
|
||||
@@ -225,6 +234,8 @@ private:
|
||||
|
||||
Node *ctx_;
|
||||
|
||||
ViewerOutput *time_target_;
|
||||
|
||||
rational timebase_;
|
||||
|
||||
KeyframeView::NodeConnections keyframe_connections_;
|
||||
|
||||
@@ -133,6 +133,8 @@ void TimeBasedView::ZoomIntoCursorPosition(QWheelEvent *event, double scale_mult
|
||||
|
||||
void TimeBasedView::SetYScale(const double &y_scale)
|
||||
{
|
||||
Q_ASSERT(y_scale > 0);
|
||||
|
||||
y_scale_ = y_scale;
|
||||
|
||||
if (y_axis_enabled_) {
|
||||
|
||||
@@ -424,7 +424,6 @@ void ImportTool::DropGhosts(bool insert, MultiUndoCommand *parent_command)
|
||||
ClipBlock* clip = new ClipBlock();
|
||||
block = clip;
|
||||
clip->set_media_in(ghost->GetMediaIn());
|
||||
clip->SetLabel(footage_stream.footage->GetLabel());
|
||||
command->add_child(new NodeAddCommand(dst_graph, clip));
|
||||
|
||||
// Position clip in its own context
|
||||
|
||||
@@ -718,6 +718,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
|
||||
|
||||
if (!relinks.empty()) {
|
||||
for (auto it=relinks.cbegin(); it!=relinks.cend(); it++) {
|
||||
// Re-connect links on duplicate clips
|
||||
for (auto jt=it.key()->links().cbegin(); jt!=it.key()->links().cend(); jt++) {
|
||||
Node *link = *jt;
|
||||
Node *copy_link = relinks.value(link);
|
||||
@@ -725,6 +726,24 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
|
||||
command->add_child(new NodeLinkCommand(it.value(), copy_link, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Re-connect transitions where applicable
|
||||
if (ClipBlock *og_clip = dynamic_cast<ClipBlock *>(it.key())) {
|
||||
ClipBlock *cp_clip = static_cast<ClipBlock *>(it.value());
|
||||
|
||||
TransitionBlock *og_in_transition = og_clip->in_transition();
|
||||
TransitionBlock *og_out_transition = og_clip->out_transition();
|
||||
|
||||
if (og_in_transition && relinks.contains(og_in_transition)) {
|
||||
TransitionBlock *cp_in_transition = static_cast<TransitionBlock *>(relinks.value(og_in_transition));
|
||||
command->add_child(new NodeEdgeAddCommand(cp_clip, NodeInput(cp_in_transition, TransitionBlock::kInBlockInput)));
|
||||
}
|
||||
|
||||
if (og_out_transition && relinks.contains(og_out_transition)) {
|
||||
TransitionBlock *cp_out_transition = static_cast<TransitionBlock *>(relinks.value(og_out_transition));
|
||||
command->add_child(new NodeEdgeAddCommand(cp_clip, NodeInput(cp_out_transition, TransitionBlock::kOutBlockInput)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1376,10 +1376,10 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
|
||||
Menu* zoom_menu = new Menu(tr("Zoom"), &menu);
|
||||
menu.addMenu(zoom_menu);
|
||||
|
||||
zoom_menu->addAction(tr("Fit"))->setData(0);
|
||||
zoom_menu->addAction(tr("Fit"))->setData(-1);
|
||||
for (int i=0;i<ViewerSizer::kZoomLevelCount;i++) {
|
||||
int z = ViewerSizer::kZoomLevels[i];
|
||||
zoom_menu->addAction(tr("%1%").arg(z))->setData(z);
|
||||
double z = ViewerSizer::kZoomLevels[i];
|
||||
zoom_menu->addAction(tr("%1%").arg(z * 100.0))->setData(z);
|
||||
}
|
||||
|
||||
connect(zoom_menu, &QMenu::triggered, this, &ViewerWidget::SetZoomFromMenu);
|
||||
@@ -1822,7 +1822,8 @@ void ViewerWidget::UpdateRendererAudioParameters()
|
||||
|
||||
void ViewerWidget::SetZoomFromMenu(QAction *action)
|
||||
{
|
||||
sizer_->SetZoom(action->data().toInt());
|
||||
auto s = sizer_->GetContainerSize();
|
||||
sizer_->SetZoomAnchored(action->data().toDouble(), s.width()/2, s.height()/2);
|
||||
}
|
||||
|
||||
void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range)
|
||||
|
||||
@@ -677,6 +677,10 @@ QTransform ViewerDisplayWidget::GenerateGizmoTransform(NodeTraverser >, const
|
||||
|
||||
NodeGizmo *ViewerDisplayWidget::TryGizmoPress(const NodeValueRow &row, const QPointF &p)
|
||||
{
|
||||
if (!gizmos_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto it=gizmos_->GetGizmos().crbegin(); it!=gizmos_->GetGizmos().crend(); it++) {
|
||||
NodeGizmo *gizmo = *it;
|
||||
if (gizmo->IsVisible()) {
|
||||
@@ -704,7 +708,11 @@ NodeGizmo *ViewerDisplayWidget::TryGizmoPress(const NodeValueRow &row, const QPo
|
||||
|
||||
void ViewerDisplayWidget::OpenTextGizmo(TextGizmo *text, QMouseEvent *event)
|
||||
{
|
||||
GenerateGizmoTransforms();
|
||||
gizmos_->UpdateGizmoPositions(gizmo_db_, NodeGlobals(gizmo_params_, gizmo_audio_params_, gizmo_draw_time_, LoopMode::kLoopModeOff));
|
||||
|
||||
active_text_gizmo_ = text;
|
||||
connect(active_text_gizmo_, &TextGizmo::RectChanged, this, &ViewerDisplayWidget::UpdateActiveTextGizmoSize);
|
||||
text_transform_ = GenerateGizmoTransform();
|
||||
text_transform_inverted_ = text_transform_.inverted();
|
||||
|
||||
@@ -736,9 +744,7 @@ void ViewerDisplayWidget::OpenTextGizmo(TextGizmo *text, QMouseEvent *event)
|
||||
connect(text_edit_, &ViewerTextEditor::destroyed, this, &ViewerDisplayWidget::TextEditDestroyed);
|
||||
|
||||
// Set text editor's size to logical size
|
||||
QRectF text_rect = text->GetRect();
|
||||
text_edit_pos_ = text_rect.topLeft();
|
||||
text_edit_->setGeometry(text_rect.toRect());
|
||||
QRectF text_rect = UpdateActiveTextGizmoSize();
|
||||
|
||||
// Emit text gizmo activation signal
|
||||
emit text->Activated();
|
||||
@@ -808,9 +814,9 @@ bool ViewerDisplayWidget::OnMousePress(QMouseEvent *event)
|
||||
|
||||
return true;
|
||||
|
||||
} else if (text_edit_) {
|
||||
} else if (text_edit_ && ForwardMouseEventToTextEdit(event, true)) {
|
||||
|
||||
return ForwardMouseEventToTextEdit(event, true);
|
||||
return true;
|
||||
|
||||
} else if (event->button() == Qt::LeftButton) {
|
||||
|
||||
@@ -821,8 +827,7 @@ bool ViewerDisplayWidget::OnMousePress(QMouseEvent *event)
|
||||
add_band_end_ = add_band_start_;
|
||||
add_band_ = true;
|
||||
|
||||
} else if (gizmos_
|
||||
&& (current_gizmo_ = TryGizmoPress(gizmo_db_, gizmo_last_draw_transform_inverted_.map(event->pos())))) {
|
||||
} else if ((current_gizmo_ = TryGizmoPress(gizmo_db_, gizmo_last_draw_transform_inverted_.map(event->pos())))) {
|
||||
|
||||
// Handle gizmo click
|
||||
gizmo_start_drag_ = event->pos();
|
||||
@@ -856,18 +861,9 @@ bool ViewerDisplayWidget::OnMouseMove(QMouseEvent *event)
|
||||
|
||||
return true;
|
||||
|
||||
} else if (text_edit_) {
|
||||
} else if (text_edit_ && ForwardMouseEventToTextEdit(event)) {
|
||||
|
||||
if (event->buttons() == Qt::NoButton) {
|
||||
QPointF mapped = text_transform_inverted_.map(event->pos()) - text_edit_pos_;
|
||||
if (mapped.x() >= 0 && mapped.y() >= 0 && mapped.x() < text_edit_->width() && mapped.y() < text_edit_->height()) {
|
||||
inner_widget()->setCursor(Qt::IBeamCursor);
|
||||
} else {
|
||||
inner_widget()->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
return ForwardMouseEventToTextEdit(event);
|
||||
return true;
|
||||
|
||||
} else if (add_band_) {
|
||||
|
||||
@@ -927,9 +923,9 @@ bool ViewerDisplayWidget::OnMouseRelease(QMouseEvent *e)
|
||||
|
||||
return true;
|
||||
|
||||
} else if (text_edit_) {
|
||||
} else if (text_edit_ && ForwardMouseEventToTextEdit(e)) {
|
||||
|
||||
return ForwardMouseEventToTextEdit(e);
|
||||
return true;
|
||||
|
||||
} else if (add_band_) {
|
||||
|
||||
@@ -964,8 +960,8 @@ bool ViewerDisplayWidget::OnMouseRelease(QMouseEvent *e)
|
||||
|
||||
bool ViewerDisplayWidget::OnMouseDoubleClick(QMouseEvent *event)
|
||||
{
|
||||
if (text_edit_) {
|
||||
return ForwardMouseEventToTextEdit(event);
|
||||
if (text_edit_ && ForwardMouseEventToTextEdit(event)) {
|
||||
return true;
|
||||
} else if (event->button() == Qt::LeftButton && gizmos_) {
|
||||
QPointF ptr = TransformViewerSpaceToBufferSpace(event->pos());
|
||||
foreach (NodeGizmo *g, gizmos_->GetGizmos()) {
|
||||
@@ -1148,13 +1144,31 @@ void ViewerDisplayWidget::ForwardDragEventToTextEdit(T *e)
|
||||
|
||||
bool ViewerDisplayWidget::ForwardMouseEventToTextEdit(QMouseEvent *event, bool check_if_outside)
|
||||
{
|
||||
if (current_gizmo_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Transform screen mouse coords to world mouse coords
|
||||
QPointF local_pos = GetVirtualPosForTextEdit(event->pos());
|
||||
|
||||
if (event->type() == QEvent::MouseMove && event->buttons() == Qt::NoButton) {
|
||||
QPointF mapped = text_transform_inverted_.map(event->pos()) - text_edit_pos_;
|
||||
if (mapped.x() >= 0 && mapped.y() >= 0 && mapped.x() < text_edit_->width() && mapped.y() < text_edit_->height()) {
|
||||
inner_widget()->setCursor(Qt::IBeamCursor);
|
||||
} else {
|
||||
inner_widget()->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
if (check_if_outside) {
|
||||
if (local_pos.x() < 0 || local_pos.x() >= text_edit_->width() || local_pos.y() < 0 || local_pos.y() >= text_edit_->height()) {
|
||||
CloseTextEditor();
|
||||
return true;
|
||||
// Allow clicking other gizmos so the user can resize while the text editor is active
|
||||
if ((current_gizmo_ = TryGizmoPress(gizmo_db_, gizmo_last_draw_transform_inverted_.map(event->pos())))) {
|
||||
return false;
|
||||
} else {
|
||||
CloseTextEditor();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1167,7 +1181,11 @@ bool ViewerDisplayWidget::ForwardMouseEventToTextEdit(QMouseEvent *event, bool c
|
||||
bool ViewerDisplayWidget::ForwardEventToTextEdit(QEvent *event)
|
||||
{
|
||||
qApp->sendEvent(text_edit_->viewport(), event);
|
||||
return event->isAccepted();
|
||||
bool e = event->isAccepted();
|
||||
if (e) {
|
||||
update();
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
QPointF ViewerDisplayWidget::AdjustPosByVAlign(QPointF p)
|
||||
@@ -1191,6 +1209,9 @@ void ViewerDisplayWidget::CloseTextEditor()
|
||||
{
|
||||
text_edit_->deleteLater();
|
||||
text_edit_ = nullptr;
|
||||
|
||||
disconnect(active_text_gizmo_, &TextGizmo::RectChanged, this, &ViewerDisplayWidget::UpdateActiveTextGizmoSize);
|
||||
active_text_gizmo_ = nullptr;
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::GenerateGizmoTransforms()
|
||||
@@ -1382,4 +1403,12 @@ void ViewerDisplayWidget::FocusChanged(QWidget *old, QWidget *now)
|
||||
}
|
||||
}
|
||||
|
||||
QRectF ViewerDisplayWidget::UpdateActiveTextGizmoSize()
|
||||
{
|
||||
QRectF text_rect = active_text_gizmo_->GetRect();
|
||||
text_edit_pos_ = text_rect.topLeft();
|
||||
text_edit_->setGeometry(text_rect.toRect());
|
||||
return text_rect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -438,6 +438,8 @@ private slots:
|
||||
|
||||
void FocusChanged(QWidget *old, QWidget *now);
|
||||
|
||||
QRectF UpdateActiveTextGizmoSize();
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ ViewerSizer::ViewerSizer(QWidget *parent) :
|
||||
width_(0),
|
||||
height_(0),
|
||||
pixel_aspect_(1),
|
||||
zoom_(0),
|
||||
zoom_(-1),
|
||||
current_widget_scale_(0)
|
||||
{
|
||||
horiz_scrollbar_ = new QScrollBar(Qt::Horizontal, this);
|
||||
@@ -64,6 +64,12 @@ void ViewerSizer::SetWidget(QWidget *widget)
|
||||
}
|
||||
}
|
||||
|
||||
QSize ViewerSizer::GetContainerSize() const
|
||||
{
|
||||
double s = GetRealCurrentZoom();
|
||||
return QSize(std::min(this->width(), int(width_ * s)) - vert_scrollbar_->width(), std::min(int(height_ * s), this->height()) - horiz_scrollbar_->height());
|
||||
}
|
||||
|
||||
void ViewerSizer::SetChildSize(int width, int height)
|
||||
{
|
||||
width_ = width;
|
||||
@@ -79,13 +85,36 @@ void ViewerSizer::SetPixelAspectRatio(const rational &pixel_aspect)
|
||||
UpdateSize();
|
||||
}
|
||||
|
||||
void ViewerSizer::SetZoom(int percent)
|
||||
void ViewerSizer::SetZoom(double percent)
|
||||
{
|
||||
zoom_ = percent;
|
||||
|
||||
UpdateSize();
|
||||
}
|
||||
|
||||
void ViewerSizer::SetZoomAnchored(double next_scale, double cursor_x, double cursor_y)
|
||||
{
|
||||
if (next_scale > 0) {
|
||||
double cur_scale = GetRealCurrentZoom();
|
||||
|
||||
// Clamp scale within safe values
|
||||
next_scale = std::clamp(next_scale, kZoomLevels[0], kZoomLevels[kZoomLevelCount-1]);
|
||||
|
||||
int anchor_x = qRound(double(cursor_x + horiz_scrollbar_->value()) / cur_scale * next_scale - cursor_x);
|
||||
int anchor_y = qRound(double(cursor_y + vert_scrollbar_->value()) / cur_scale * next_scale - cursor_y);
|
||||
|
||||
SetZoom(next_scale);
|
||||
|
||||
horiz_scrollbar_->setValue(anchor_x);
|
||||
vert_scrollbar_->setValue(anchor_y);
|
||||
} else {
|
||||
SetZoom(-1);
|
||||
|
||||
horiz_scrollbar_->setValue(0);
|
||||
vert_scrollbar_->setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerSizer::HandDragMove(int x, int y)
|
||||
{
|
||||
if (horiz_scrollbar_->isVisible()) {
|
||||
@@ -104,31 +133,9 @@ bool ViewerSizer::eventFilter(QObject *watched, QEvent *event)
|
||||
QWheelEvent *w = static_cast<QWheelEvent*>(event);
|
||||
|
||||
if (HandMovableView::WheelEventIsAZoomEvent(w)) {
|
||||
int x = w->angleDelta().x() + w->angleDelta().y();
|
||||
|
||||
int current_percent = zoom_;
|
||||
if (current_percent == 0) {
|
||||
// Currently set to "fit"
|
||||
current_percent = current_widget_scale_;
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
// Zoom in
|
||||
for (int i=kZoomLevelCount-2; i>=0; i--) {
|
||||
if (current_percent >= kZoomLevels[i]) {
|
||||
SetZoom(kZoomLevels[i+1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (x < 0) {
|
||||
// Zoom out
|
||||
for (int i=1; i<kZoomLevelCount; i++) {
|
||||
if (current_percent <= kZoomLevels[i]) {
|
||||
SetZoom(kZoomLevels[i-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
double next_scale = GetRealCurrentZoom() * HandMovableView::GetScrollZoomMultiplier(w);
|
||||
QPointF cursor_pos = w->position();
|
||||
SetZoomAnchored(next_scale, cursor_pos.x(), cursor_pos.y());
|
||||
} else {
|
||||
// Pass scroll values to scrollbars
|
||||
QPoint p = w->pixelDelta();
|
||||
@@ -221,12 +228,12 @@ void ViewerSizer::UpdateSize()
|
||||
|
||||
}
|
||||
|
||||
current_widget_scale_ = current_scale * 100;
|
||||
current_widget_scale_ = current_scale;
|
||||
|
||||
if (zoom_ > 0) {
|
||||
|
||||
// Scale to get to the requested zoom
|
||||
double zoom_diff = (zoom_ * 0.01) / current_scale;
|
||||
double zoom_diff = zoom_ / current_scale;
|
||||
child_matrix.scale(zoom_diff, zoom_diff, 1.0);
|
||||
|
||||
}
|
||||
@@ -238,7 +245,18 @@ void ViewerSizer::UpdateSize()
|
||||
|
||||
int ViewerSizer::GetZoomedValue(int value)
|
||||
{
|
||||
return qRound(value * static_cast<double>(zoom_) * 0.01);
|
||||
return qRound(value * zoom_);
|
||||
}
|
||||
|
||||
double ViewerSizer::GetRealCurrentZoom() const
|
||||
{
|
||||
if (zoom_ < 0) {
|
||||
// Currently set to "fit"
|
||||
return current_widget_scale_;
|
||||
} else {
|
||||
// Explicit zoom set
|
||||
return zoom_;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerSizer::ScrollBarMoved()
|
||||
|
||||
@@ -51,8 +51,10 @@ public:
|
||||
*/
|
||||
void SetWidget(QWidget* widget);
|
||||
|
||||
static constexpr int kZoomLevelCount = 8;
|
||||
static constexpr int kZoomLevels[kZoomLevelCount] = {10, 25, 50, 75, 100, 150, 200, 400};
|
||||
QSize GetContainerSize() const;
|
||||
|
||||
static constexpr int kZoomLevelCount = 10;
|
||||
static constexpr double kZoomLevels[kZoomLevelCount] = {0.05, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 4.0, 8.0};
|
||||
|
||||
public slots:
|
||||
/**
|
||||
@@ -72,7 +74,8 @@ public slots:
|
||||
*
|
||||
* The number is an integer percentage (100 = 100%). Set to 0 to auto-fit.
|
||||
*/
|
||||
void SetZoom(int percent);
|
||||
void SetZoom(double percent);
|
||||
void SetZoomAnchored(double percent, double cursor_x, double cursor_y);
|
||||
|
||||
void HandDragMove(int x, int y);
|
||||
|
||||
@@ -97,6 +100,8 @@ private:
|
||||
|
||||
int GetZoomedValue(int value);
|
||||
|
||||
double GetRealCurrentZoom() const;
|
||||
|
||||
/**
|
||||
* @brief Reference to widget
|
||||
*
|
||||
@@ -115,8 +120,8 @@ private:
|
||||
/**
|
||||
* @brief Internal zoom value
|
||||
*/
|
||||
int zoom_;
|
||||
int current_widget_scale_;
|
||||
double zoom_;
|
||||
double current_widget_scale_;
|
||||
|
||||
QScrollBar* horiz_scrollbar_;
|
||||
QScrollBar* vert_scrollbar_;
|
||||
|
||||
@@ -138,6 +138,7 @@ void ViewerTextEditor::Paint(QPainter *p, Qt::Alignment valign)
|
||||
|
||||
const bool use_transparent_clone = true;
|
||||
if (transparent_clone_ && use_transparent_clone) {
|
||||
transparent_clone_->setPageSize(this->document()->pageSize());
|
||||
transparent_clone_->documentLayout()->draw(p, ctx);
|
||||
} else {
|
||||
document()->documentLayout()->draw(p, ctx);
|
||||
@@ -294,6 +295,9 @@ void ViewerTextEditor::DocumentChanged()
|
||||
forced_default_ = true;
|
||||
}
|
||||
} else {
|
||||
if (default_fmt_.isEmpty()) {
|
||||
default_fmt_ = document()->firstBlock().charFormat();
|
||||
}
|
||||
forced_default_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,13 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
audio_monitor_panel_ = new AudioMonitorPanel();
|
||||
scope_panel_ = new ScopePanel();
|
||||
|
||||
// HACK: The pixel sampler is closed by default, which signals to Core that
|
||||
// it's no longer visible. However KDDockWidgets doesn't appear to
|
||||
// emit the "shown" signal before emitting the "hidden" signals, resulting
|
||||
// in Core thinking there are -1 pixel samplers open. To mitigate that,
|
||||
// we force "shown" to emit ourselves here.
|
||||
emit pixel_sampler_panel_->shown();
|
||||
|
||||
// Make node-related connections
|
||||
connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, param_panel_, &ParamPanel::SetSelectedNodes);
|
||||
connect(node_panel_, &NodePanel::NodeGroupOpened, this, &MainWindow::NodePanelGroupOpenedOrClosed);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "node/distort/transform/transformdistortnode.h"
|
||||
#include "node/generator/solid/solid.h"
|
||||
#include "node/math/merge/merge.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project.h"
|
||||
#include "render/rendermanager.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include "node/block/transition/crossdissolve/crossdissolvetransition.h"
|
||||
#include "node/math/math/math.h"
|
||||
#include "node/math/merge/merge.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "undo/undocommand.h"
|
||||
#include "widget/timelinewidget/undo/timelineundogeneral.h"
|
||||
#include "widget/timelinewidget/undo/timelineundopointer.h"
|
||||
#include "testutil.h"
|
||||
#include "timeline/timelineundogeneral.h"
|
||||
#include "timeline/timelineundopointer.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user