diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 0cc53e91f..7fe968bcf 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -46,9 +46,6 @@ Block::Block() : IgnoreHashingFrom(kLengthInput); AddInput(kEnabledInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); - - // A block's length must be greater than 0 - set_length_and_media_out(1); } QVector Block::Category() const diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 6e8932098..dce6845ff 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -23,6 +23,7 @@ #include "common/clamp.h" #include "node/block/clip/clip.h" #include "node/output/track/track.h" +#include "widget/slider/rationalslider.h" namespace olive { @@ -31,8 +32,7 @@ namespace olive { const QString TransitionBlock::kOutBlockInput = QStringLiteral("out_block_in"); const QString TransitionBlock::kInBlockInput = QStringLiteral("in_block_in"); const QString TransitionBlock::kCurveInput = QStringLiteral("curve_in"); -const QString TransitionBlock::kInOffsetInput = QStringLiteral("in_offset_in"); -const QString TransitionBlock::kOutOffsetInput = QStringLiteral("out_offset_in"); +const QString TransitionBlock::kCenterInput = QStringLiteral("center_in"); TransitionBlock::TransitionBlock() : connected_out_block_(nullptr), @@ -44,11 +44,10 @@ TransitionBlock::TransitionBlock() : AddInput(kCurveInput, NodeValue::kCombo, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kInOffsetInput, NodeValue::kRational, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - AddInput(kOutOffsetInput, NodeValue::kRational, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - set_length_and_media_out(0); + AddInput(kCenterInput, NodeValue::kRational, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); + SetInputProperty(kCenterInput, QStringLiteral("view"), RationalSlider::kTime); + SetInputProperty(kCenterInput, QStringLiteral("viewlock"), true); + IgnoreHashingFrom(kCenterInput); } void TransitionBlock::Retranslate() @@ -58,8 +57,7 @@ void TransitionBlock::Retranslate() SetInputName(kOutBlockInput, tr("From")); SetInputName(kInBlockInput, tr("To")); SetInputName(kCurveInput, tr("Curve")); - SetInputName(kInOffsetInput, tr("In Offset")); - SetInputName(kOutOffsetInput, tr("Out Offset")); + SetInputName(kCenterInput, tr("Center Offset")); // These must correspond to the CurveType enum SetComboBoxStrings(kCurveInput, { tr("Linear"), tr("Exponential"), tr("Logarithmic") }); @@ -67,22 +65,43 @@ void TransitionBlock::Retranslate() rational TransitionBlock::in_offset() const { - return GetStandardValue(kInOffsetInput).value(); -} - -void TransitionBlock::set_in_offset(const rational &os) -{ - SetStandardValue(kInOffsetInput, QVariant::fromValue(os)); + if (is_dual_transition()) { + return length()/2 + offset_center(); + } else if (connected_in_block()) { + return length(); + } else { + return 0; + } } rational TransitionBlock::out_offset() const { - return GetStandardValue(kOutOffsetInput).value(); + if (is_dual_transition()) { + return length()/2 - offset_center(); + } else if (connected_out_block()) { + return length(); + } else { + return 0; + } } -void TransitionBlock::set_out_offset(const rational &os) +rational TransitionBlock::offset_center() const { - SetStandardValue(kOutOffsetInput, QVariant::fromValue(os)); + return GetStandardValue(kCenterInput).value(); +} + +void TransitionBlock::set_offset_center(const rational &r) +{ + SetStandardValue(kCenterInput, QVariant::fromValue(r)); +} + +void TransitionBlock::set_offsets_and_length(const rational &in_offset, const rational &out_offset) +{ + rational len = in_offset + out_offset; + rational center = len / 2 - in_offset; + + set_length_and_media_out(len); + set_offset_center(center); } Block *TransitionBlock::connected_out_block() const diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 4156ee4d9..f14dd4ef3 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -38,9 +38,25 @@ public: virtual void Retranslate() override; rational in_offset() const; - void set_in_offset(const rational &os); rational out_offset() const; - void set_out_offset(const rational &os); + + /** + * @brief Return the "middle point" of the transition, relative to the transition + * + * Used to calculate in/out offsets. + * + * 0 means the center of the transition is right in the middle and the in and out offsets will + * be equal. + */ + rational offset_center() const; + void set_offset_center(const rational &r); + + void set_offsets_and_length(const rational &in_offset, const rational &out_offset); + + bool is_dual_transition() const + { + return connected_out_block() && connected_in_block(); + } Block* connected_out_block() const; Block* connected_in_block() const; @@ -58,8 +74,7 @@ public: static const QString kOutBlockInput; static const QString kInBlockInput; static const QString kCurveInput; - static const QString kInOffsetInput; - static const QString kOutOffsetInput; + static const QString kCenterInput; protected: virtual void ShaderJobEvent(NodeValueDatabase &value, ShaderJob& job) const; diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index 11b10e716..a4408142c 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -186,8 +186,7 @@ bool LoadOTIOTask::Run() OTIO::Transition* otio_block_transition = static_cast(otio_block); // Set how far the transition eats into the previous clip - transition_block->set_in_offset(rational::fromRationalTime(otio_block_transition->in_offset())); - transition_block->set_out_offset(rational::fromRationalTime(otio_block_transition->out_offset())); + transition_block->set_offsets_and_length(rational::fromRationalTime(otio_block_transition->in_offset()), rational::fromRationalTime(otio_block_transition->out_offset())); if (previous_block) { Node::ConnectEdge(previous_block, NodeInput(transition_block, TransitionBlock::kOutBlockInput)); diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index 46c05a004..f1a1f4fdd 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -103,22 +103,24 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) transition = static_cast(NodeFactory::CreateFromID(Core::instance()->GetSelectedTransition())); } + // Set transition length + rational len = ghost_->GetAdjustedLength(); + transition->set_length_and_media_out(len); + MultiUndoCommand* command = new MultiUndoCommand(); // Place transition in place command->add_child(new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), transition)); + command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0), false)); + command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()), track.index(), transition, ghost_->GetAdjustedIn())); if (dual_transition_) { - rational half_len = ghost_->GetAdjustedLength()/2; - transition->set_in_offset(half_len); - transition->set_out_offset(half_len); - // Block mouse is hovering over Block* active_block = Node::ValueToPtr(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock)); @@ -135,21 +137,24 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(new NodeEdgeAddCommand(in_block, NodeInput(transition, TransitionBlock::kInBlockInput))); + + command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5), false)); + command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5), false)); } else { Block* block_to_transition = Node::ValueToPtr(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock)); QString transition_input_to_connect; if (ghost_->GetMode() == Timeline::kTrimIn) { - transition->set_length_and_media_out(ghost_->GetAdjustedLength()); transition_input_to_connect = TransitionBlock::kInBlockInput; } else { - transition->set_length_and_media_out(ghost_->GetAdjustedLength()); transition_input_to_connect = TransitionBlock::kOutBlockInput; } // Connect block to transition command->add_child(new NodeEdgeAddCommand(block_to_transition, NodeInput(transition, transition_input_to_connect))); + + command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0), false)); } Core::instance()->undo_stack()->push(command);