implemented new block system
Fixes recurring design issue that the Blocks were a frequent exception to the DAG concept. The Blocks connecting to each others inputs/outputs while not necessarily being "dependent" on each other to produce an image continually causes issues while trying to create a rendering code path. This redesign should provide a more "directed" approach to the directed acyclic graph.
This commit is contained in:
+25
-23
@@ -31,9 +31,6 @@ Block::Block() :
|
||||
|
||||
buffer_output_ = new NodeOutput("buffer_out");
|
||||
AddParameter(buffer_output_);
|
||||
|
||||
connect(this, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(EdgeAddedSlot(NodeEdgePtr)), Qt::DirectConnection);
|
||||
connect(this, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(EdgeRemovedSlot(NodeEdgePtr)), Qt::DirectConnection);
|
||||
}
|
||||
|
||||
QString Block::Category()
|
||||
@@ -51,6 +48,16 @@ const rational &Block::out()
|
||||
return out_point_;
|
||||
}
|
||||
|
||||
void Block::set_in(const rational &in)
|
||||
{
|
||||
in_point_ = in;
|
||||
}
|
||||
|
||||
void Block::set_out(const rational &out)
|
||||
{
|
||||
out_point_ = out;
|
||||
}
|
||||
|
||||
const rational& Block::length()
|
||||
{
|
||||
return length_;
|
||||
@@ -60,13 +67,17 @@ void Block::set_length(const rational &length)
|
||||
{
|
||||
Q_ASSERT(length > 0);
|
||||
|
||||
if (length == length_) {
|
||||
return;
|
||||
}
|
||||
|
||||
LockUserInput();
|
||||
|
||||
length_ = length;
|
||||
|
||||
UnlockUserInput();
|
||||
|
||||
Refresh();
|
||||
emit LengthChanged(length_);
|
||||
}
|
||||
|
||||
void Block::set_length_and_media_in(const rational &length)
|
||||
@@ -88,6 +99,16 @@ Block *Block::next()
|
||||
return next_;
|
||||
}
|
||||
|
||||
void Block::set_previous(Block *previous)
|
||||
{
|
||||
previous_ = previous;
|
||||
}
|
||||
|
||||
void Block::set_next(Block *next)
|
||||
{
|
||||
next_ = next;
|
||||
}
|
||||
|
||||
QVariant Block::Value(NodeOutput *output)
|
||||
{
|
||||
if (output == block_output_) {
|
||||
@@ -98,25 +119,6 @@ QVariant Block::Value(NodeOutput *output)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Block::Refresh()
|
||||
{
|
||||
// Set in point to the out point of the previous Node
|
||||
if (previous() != nullptr) {
|
||||
in_point_ = previous()->out();
|
||||
} else {
|
||||
in_point_ = 0;
|
||||
}
|
||||
|
||||
// Update out point by adding this clip's length to the just calculated in point
|
||||
out_point_ = in_point_ + length();
|
||||
|
||||
emit Refreshed();
|
||||
|
||||
if (next() != nullptr) {
|
||||
next()->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
NodeOutput *Block::buffer_output()
|
||||
{
|
||||
return buffer_output_;
|
||||
|
||||
+12
-20
@@ -42,7 +42,7 @@ public:
|
||||
enum Type {
|
||||
kClip,
|
||||
kGap,
|
||||
kEnd
|
||||
kTrack
|
||||
};
|
||||
|
||||
virtual Type type() = 0;
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
const rational& in();
|
||||
const rational& out();
|
||||
void set_in(const rational& in);
|
||||
void set_out(const rational& out);
|
||||
|
||||
const rational &length();
|
||||
void set_length(const rational &length);
|
||||
@@ -58,6 +60,8 @@ public:
|
||||
|
||||
Block* previous();
|
||||
Block* next();
|
||||
void set_previous(Block* previous);
|
||||
void set_next(Block* next);
|
||||
|
||||
NodeOutput* buffer_output();
|
||||
NodeOutput* block_output();
|
||||
@@ -80,20 +84,6 @@ public:
|
||||
virtual QVariant Value(NodeOutput* output) override;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Refreshes internal cache of in/out points up to date
|
||||
*
|
||||
* A block can only know truly know its in point by adding all the lengths of the clips before it. Since this can
|
||||
* become timeconsuming, blocks cache their in and out points for easy access, however this does mean their caches
|
||||
* need to stay up to date to provide accurate results. Whenever this or any surrounding Block is changed, it's
|
||||
* recommended to call Refresh().
|
||||
*
|
||||
* This function specifically sets the in point to the out point of the previous clip and sets its out point to the
|
||||
* in point + this block's length. Therefore, before calling Refresh() on a Block, it's necessary that all the
|
||||
* Blocks before it are accurate and up to date. You may need to traverse through the Block list (using previous())
|
||||
* and run Refresh() on all Blocks sequentially.
|
||||
*/
|
||||
virtual void Refresh();
|
||||
|
||||
signals:
|
||||
/**
|
||||
@@ -103,6 +93,8 @@ signals:
|
||||
*/
|
||||
void Refreshed();
|
||||
|
||||
void LengthChanged(const rational& length);
|
||||
|
||||
protected:
|
||||
rational SequenceToMediaTime(const rational& sequence_time);
|
||||
|
||||
@@ -110,18 +102,18 @@ protected:
|
||||
|
||||
static void CopyParameters(Block* source, Block* dest);
|
||||
|
||||
Block* previous_;
|
||||
Block* next_;
|
||||
|
||||
private:
|
||||
NodeOutput* block_output_;
|
||||
NodeOutput* buffer_output_;
|
||||
|
||||
rational in_point_;
|
||||
rational out_point_;
|
||||
|
||||
rational length_;
|
||||
rational media_in_;
|
||||
|
||||
Block* previous_;
|
||||
Block* next_;
|
||||
rational in_point_;
|
||||
rational out_point_;
|
||||
|
||||
QString block_name_;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ void TrackList::AttachTrack(TrackOutput *track)
|
||||
connect(current_track, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(TrackEdgeRemoved(NodeEdgePtr)));
|
||||
connect(current_track, SIGNAL(BlockAdded(Block*)), this, SLOT(TrackAddedBlock(Block*)));
|
||||
connect(current_track, SIGNAL(BlockRemoved(Block*)), this, SLOT(TrackRemovedBlock(Block*)));
|
||||
connect(current_track, SIGNAL(Refreshed()), this, SLOT(UpdateTotalLength()));
|
||||
connect(current_track, SIGNAL(TrackLengthChanged()), this, SLOT(UpdateTotalLength()));
|
||||
|
||||
current_track->SetIndex(track_cache_.size());
|
||||
current_track->set_track_type(type_);
|
||||
@@ -219,7 +219,7 @@ void TrackList::UpdateTotalLength()
|
||||
total_length_ = 0;
|
||||
|
||||
foreach (TrackOutput* track, track_cache_) {
|
||||
total_length_ = qMax(total_length_, track->in());
|
||||
total_length_ = qMax(total_length_, track->track_length());
|
||||
}
|
||||
|
||||
emit LengthChanged(total_length_);
|
||||
|
||||
+199
-145
@@ -32,6 +32,9 @@ TrackOutput::TrackOutput() :
|
||||
{
|
||||
block_input_ = new NodeInputArray("block_in");
|
||||
AddParameter(block_input_);
|
||||
connect(block_input_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(BlockConnected(NodeEdgePtr)));
|
||||
connect(block_input_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(BlockDisconnected(NodeEdgePtr)));
|
||||
connect(block_input_, SIGNAL(SizeChanged(int)), this, SLOT(BlockListSizeChanged(int)));
|
||||
|
||||
track_input_ = new NodeInput("track_in");
|
||||
track_input_->set_data_type(NodeParam::kTrack);
|
||||
@@ -54,7 +57,7 @@ const TrackType& TrackOutput::track_type()
|
||||
|
||||
Block::Type TrackOutput::type()
|
||||
{
|
||||
return kEnd;
|
||||
return kTrack;
|
||||
}
|
||||
|
||||
Block *TrackOutput::copy()
|
||||
@@ -83,33 +86,6 @@ QString TrackOutput::Description()
|
||||
"a Sequence.");
|
||||
}
|
||||
|
||||
void TrackOutput::Refresh()
|
||||
{
|
||||
QVector<Block*> detect_attached_blocks;
|
||||
|
||||
Block* prev = previous();
|
||||
while (prev != nullptr) {
|
||||
detect_attached_blocks.prepend(prev);
|
||||
|
||||
if (!block_cache_.contains(prev)) {
|
||||
emit BlockAdded(prev);
|
||||
}
|
||||
|
||||
prev = prev->previous();
|
||||
}
|
||||
|
||||
foreach (Block* b, block_cache_) {
|
||||
if (!detect_attached_blocks.contains(b)) {
|
||||
// If the current block was removed, stop referencing it
|
||||
emit BlockRemoved(b);
|
||||
}
|
||||
}
|
||||
|
||||
block_cache_ = detect_attached_blocks;
|
||||
|
||||
Block::Refresh();
|
||||
}
|
||||
|
||||
const int &TrackOutput::Index()
|
||||
{
|
||||
return index_;
|
||||
@@ -192,87 +168,42 @@ QVariant TrackOutput::Value(NodeOutput *output)
|
||||
if (output == track_output_) {
|
||||
// Set track output correctly
|
||||
return PtrToValue(this);
|
||||
/*} else if (output == buffer_output()) {
|
||||
ValidateCurrentBlock(in);
|
||||
|
||||
if (current_block_ != this) {
|
||||
// At this point, we must have found the correct block so we use its texture output to produce the image
|
||||
return current_block_->buffer_output()->get_value(in, out);
|
||||
}
|
||||
|
||||
// No texture is valid
|
||||
return 0;*/
|
||||
}
|
||||
|
||||
// Run default node processing
|
||||
return Block::Value(output);
|
||||
}
|
||||
|
||||
void TrackOutput::InsertBlockBetweenBlocks(Block *block, Block *before, Block *after)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
Block::DisconnectBlocks(before, after);
|
||||
Block::ConnectBlocks(before, block);
|
||||
Block::ConnectBlocks(block, after);
|
||||
}
|
||||
|
||||
void TrackOutput::InsertBlockBefore(Block* block, Block* after)
|
||||
{
|
||||
Block* before = after->previous();
|
||||
|
||||
// If a block precedes this one, just insert between them
|
||||
if (before != nullptr) {
|
||||
InsertBlockBetweenBlocks(block, before, after);
|
||||
} else {
|
||||
AddBlockToGraph(block);
|
||||
|
||||
// Otherwise, just connect the block since there's no before clip to insert between
|
||||
Block::ConnectBlocks(block, after);
|
||||
}
|
||||
InsertBlockAtIndex(block, block_cache_.indexOf(after));
|
||||
}
|
||||
|
||||
void TrackOutput::InsertBlockAfter(Block *block, Block *before)
|
||||
{
|
||||
InsertBlockBetweenBlocks(block, before, before->next());
|
||||
int before_index = block_cache_.indexOf(before);
|
||||
|
||||
Q_ASSERT(before_index >= 0);
|
||||
|
||||
if (before_index == block_cache_.size() - 1) {
|
||||
AppendBlock(block);
|
||||
} else {
|
||||
InsertBlockAtIndex(block, before_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::PrependBlock(Block *block)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
if (block_cache_.isEmpty()) {
|
||||
ConnectBlockInternal(block);
|
||||
} else {
|
||||
Block::ConnectBlocks(block, block_cache_.first());
|
||||
}
|
||||
InsertBlockAtIndex(block, 0);
|
||||
}
|
||||
|
||||
void TrackOutput::InsertBlockAtIndex(Block *block, int index)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
if (block_cache_.isEmpty()) {
|
||||
|
||||
// If there are no blocks connected, the index doesn't matter. Just connect it.
|
||||
ConnectBlockInternal(block);
|
||||
|
||||
} else if (index == 0) {
|
||||
|
||||
// If the index is 0, it goes at the very beginning
|
||||
PrependBlock(block);
|
||||
|
||||
} else if (index >= block_cache_.size()) {
|
||||
|
||||
// Append Block at the end
|
||||
AppendBlock(block);
|
||||
|
||||
} else {
|
||||
|
||||
// Insert Block just before the Block currently at that index so that it becomes the new Block at that index
|
||||
InsertBlockBetweenBlocks(block, block_cache_.at(index - 1), block_cache_.at(index));
|
||||
|
||||
}
|
||||
block_input_->InsertAt(index);
|
||||
NodeParam::ConnectEdge(block->block_output(),
|
||||
block_input_->ParamAt(index));
|
||||
}
|
||||
|
||||
void TrackOutput::AppendBlock(Block *block)
|
||||
@@ -281,23 +212,15 @@ void TrackOutput::AppendBlock(Block *block)
|
||||
|
||||
BlockInvalidateCache();
|
||||
|
||||
if (block_cache_.isEmpty()) {
|
||||
ConnectBlockInternal(block);
|
||||
} else {
|
||||
InsertBlockBetweenBlocks(block, block_cache_.last(), this);
|
||||
}
|
||||
int last_index = block_input_->GetSize();
|
||||
block_input_->Append();
|
||||
NodeParam::ConnectEdge(block->block_output(),
|
||||
block_input_->ParamAt(last_index));
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
// Invalidate area that block was added to
|
||||
InvalidateCache(block->in(), in());
|
||||
}
|
||||
|
||||
void TrackOutput::ConnectBlockInternal(Block *block)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
Block::ConnectBlocks(block, this);
|
||||
InvalidateCache(block->in(), track_length());
|
||||
}
|
||||
|
||||
void TrackOutput::AddBlockToGraph(Block *block)
|
||||
@@ -322,18 +245,7 @@ void TrackOutput::RemoveBlock(Block *block)
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(block->length());
|
||||
|
||||
Block* previous = block->previous();
|
||||
Block* next = block->next();
|
||||
|
||||
// Remove block
|
||||
RippleRemoveBlock(block);
|
||||
|
||||
if (previous == nullptr) {
|
||||
// Block must be at the beginning
|
||||
PrependBlock(gap);
|
||||
} else {
|
||||
InsertBlockBetweenBlocks(gap, previous, next);
|
||||
}
|
||||
ReplaceBlock(block, gap);
|
||||
}
|
||||
|
||||
void TrackOutput::RippleRemoveBlock(Block *block)
|
||||
@@ -342,24 +254,13 @@ void TrackOutput::RippleRemoveBlock(Block *block)
|
||||
|
||||
rational remove_in = block->in();
|
||||
|
||||
Block* previous = block->previous();
|
||||
Block* next = block->next();
|
||||
int index_of_block_to_remove = block_cache_.indexOf(block);
|
||||
|
||||
if (previous != nullptr) {
|
||||
Block::DisconnectBlocks(previous, block);
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
Block::DisconnectBlocks(block, next);
|
||||
}
|
||||
|
||||
if (previous != nullptr && next != nullptr) {
|
||||
Block::ConnectBlocks(previous, next);
|
||||
}
|
||||
block_input_->RemoveAt(index_of_block_to_remove);
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
InvalidateCache(remove_in, in());
|
||||
InvalidateCache(remove_in, track_length());
|
||||
|
||||
// FIXME: Should there be removing the Blocks from the graph?
|
||||
}
|
||||
@@ -368,23 +269,17 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace)
|
||||
{
|
||||
Q_ASSERT(old->length() == replace->length());
|
||||
|
||||
Block* previous = old->previous();
|
||||
Block* next = old->next();
|
||||
|
||||
BlockInvalidateCache();
|
||||
|
||||
AddBlockToGraph(replace);
|
||||
|
||||
// Disconnect old block from its surroundings
|
||||
if (previous != nullptr) {
|
||||
Block::DisconnectBlocks(previous, old);
|
||||
Block::ConnectBlocks(previous, replace);
|
||||
}
|
||||
int index_of_old_block = block_cache_.indexOf(old);
|
||||
|
||||
if (next != nullptr) {
|
||||
Block::DisconnectBlocks(old, next);
|
||||
Block::ConnectBlocks(replace, next);
|
||||
}
|
||||
NodeParam::DisconnectEdge(old->block_output(),
|
||||
block_input_->ParamAt(index_of_old_block));
|
||||
|
||||
NodeParam::ConnectEdge(replace->block_output(),
|
||||
block_input_->ParamAt(index_of_old_block));
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
@@ -393,14 +288,173 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace)
|
||||
|
||||
TrackOutput *TrackOutput::TrackFromBlock(Block *block)
|
||||
{
|
||||
Block* n = block;
|
||||
NodeOutput* output = block->block_output();
|
||||
|
||||
// Find last valid block in Sequence and assume its a track
|
||||
while (n->next() != nullptr) {
|
||||
n = n->next();
|
||||
foreach (NodeEdgePtr edge, output->edges()) {
|
||||
TrackOutput* track_test = dynamic_cast<TrackOutput*>(edge->input()->parentNode());
|
||||
|
||||
if (track_test) {
|
||||
return track_test;
|
||||
}
|
||||
}
|
||||
|
||||
// Downside of this approach is the usage of dynamic_cast, alternative would be looping through all known tracks and
|
||||
// seeing if the contain the Block, but this seems slower
|
||||
return dynamic_cast<TrackOutput*>(n);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const rational &TrackOutput::track_length()
|
||||
{
|
||||
return track_length_;
|
||||
}
|
||||
|
||||
bool TrackOutput::IsTrack()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void TrackOutput::UpdateInOutFrom(int index)
|
||||
{
|
||||
Q_ASSERT(index >= 0);
|
||||
Q_ASSERT(index < block_cache_.size());
|
||||
|
||||
rational new_track_length;
|
||||
|
||||
for (int i=index;i<block_cache_.size();i++) {
|
||||
Block* b = block_cache_.at(i);
|
||||
|
||||
if (b) {
|
||||
rational prev_out;
|
||||
|
||||
// Find previous block and retrieve its out point (if there isn't one, this in will be set to 0)
|
||||
for (int j=i-1;j>=0;j--) {
|
||||
Block* previous = block_cache_.at(j);
|
||||
if (previous) {
|
||||
prev_out = previous->out();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rational new_out = prev_out + b->length();
|
||||
|
||||
b->set_in(prev_out);
|
||||
b->set_out(new_out);
|
||||
|
||||
new_track_length = new_out;
|
||||
|
||||
emit b->Refreshed();
|
||||
}
|
||||
}
|
||||
|
||||
// Update track length
|
||||
if (new_track_length != track_length_) {
|
||||
track_length_ = new_track_length;
|
||||
emit TrackLengthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::UpdatePreviousAndNextOfIndex(int index)
|
||||
{
|
||||
Block* ref = block_cache_.at(index);
|
||||
|
||||
Block* previous = nullptr;
|
||||
Block* next = nullptr;
|
||||
|
||||
// Find previous
|
||||
for (int i=index-1;i>=0;i--) {
|
||||
previous = block_cache_.at(i);
|
||||
|
||||
if (previous) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find next
|
||||
for (int i=index+1;i<block_cache_.size();i++) {
|
||||
next = block_cache_.at(i);
|
||||
|
||||
if (next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
// Link blocks together
|
||||
ref->set_previous(previous);
|
||||
ref->set_next(next);
|
||||
|
||||
if (previous)
|
||||
previous->set_next(ref);
|
||||
|
||||
if (next)
|
||||
next->set_previous(ref);
|
||||
} else {
|
||||
// Link previous and next together
|
||||
if (previous)
|
||||
previous->set_next(next);
|
||||
|
||||
if (next)
|
||||
next->set_previous(previous);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::BlockConnected(NodeEdgePtr edge)
|
||||
{
|
||||
int block_index = block_input_->IndexOfSubParameter(edge->input());
|
||||
|
||||
Q_ASSERT(block_index >= 0);
|
||||
|
||||
Block* connected_block = dynamic_cast<Block*>(edge->output()->parentNode());
|
||||
block_cache_.replace(block_index, connected_block);
|
||||
UpdatePreviousAndNextOfIndex(block_index);
|
||||
UpdateInOutFrom(block_index);
|
||||
|
||||
if (connected_block) {
|
||||
connect(connected_block, SIGNAL(LengthChanged(const rational&)), this, SLOT(BlockLengthChanged()));
|
||||
|
||||
emit BlockAdded(connected_block);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::BlockDisconnected(NodeEdgePtr edge)
|
||||
{
|
||||
int block_index = block_input_->IndexOfSubParameter(edge->input());
|
||||
|
||||
Q_ASSERT(block_index >= 0);
|
||||
|
||||
block_cache_.replace(block_index, nullptr);
|
||||
UpdatePreviousAndNextOfIndex(block_index);
|
||||
UpdateInOutFrom(block_index);
|
||||
|
||||
Block* connected_block = dynamic_cast<Block*>(edge->output()->parentNode());
|
||||
if (connected_block) {
|
||||
disconnect(connected_block, SIGNAL(LengthChanged(const rational&)), this, SLOT(BlockLengthChanged()));
|
||||
|
||||
// Update previous and next references
|
||||
emit BlockRemoved(connected_block);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::BlockListSizeChanged(int size)
|
||||
{
|
||||
int old_size = block_cache_.size();
|
||||
|
||||
block_cache_.resize(size);
|
||||
|
||||
if (size > old_size) {
|
||||
// Fill new slots with nullptr
|
||||
for (int i=old_size;i<size;i++) {
|
||||
block_cache_.replace(i, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackOutput::BlockLengthChanged()
|
||||
{
|
||||
// Assumes sender is a Block
|
||||
Block* b = static_cast<Block*>(sender());
|
||||
|
||||
int index = block_cache_.indexOf(b);
|
||||
|
||||
Q_ASSERT(index >= 0);
|
||||
|
||||
UpdateInOutFrom(index);
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ public:
|
||||
virtual QString Category() override;
|
||||
virtual QString Description() override;
|
||||
|
||||
virtual void Refresh() override;
|
||||
|
||||
const int& Index();
|
||||
void SetIndex(const int& index);
|
||||
|
||||
@@ -79,13 +77,6 @@ public:
|
||||
*/
|
||||
void InsertBlockAtIndex(Block* block, int index);
|
||||
|
||||
/**
|
||||
* @brief Inserts a Block between two other Blocks
|
||||
*
|
||||
* Disconnects `before` and `after`, and connects them to `block` with `block` in between.
|
||||
*/
|
||||
void InsertBlockBetweenBlocks(Block* block, Block* before, Block* after);
|
||||
|
||||
/**
|
||||
* @brief Inserts Block after another Block
|
||||
*
|
||||
@@ -131,6 +122,12 @@ public:
|
||||
*/
|
||||
void AddBlockToGraph(Block* block);
|
||||
|
||||
static TrackOutput* TrackFromBlock(Block* block);
|
||||
|
||||
const rational& track_length();
|
||||
|
||||
virtual bool IsTrack() override;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when a Block is added to this Track
|
||||
@@ -142,21 +139,18 @@ signals:
|
||||
*/
|
||||
void BlockRemoved(Block* block);
|
||||
|
||||
/**
|
||||
* @brief Signal emitted when the length of the track has changed
|
||||
*/
|
||||
void TrackLengthChanged();
|
||||
|
||||
protected:
|
||||
virtual QVariant Value(NodeOutput* output) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Sets this Block as the only block in the Timeline (creating essentially a one clip sequence)
|
||||
*/
|
||||
void ConnectBlockInternal(Block* block);
|
||||
void UpdateInOutFrom(int index);
|
||||
|
||||
/**
|
||||
* @brief Disconnects t
|
||||
*/
|
||||
void RemoveBlockInternal();
|
||||
|
||||
static TrackOutput* TrackFromBlock(Block* block);
|
||||
void UpdatePreviousAndNextOfIndex(int index);
|
||||
|
||||
QVector<Block*> block_cache_;
|
||||
|
||||
@@ -168,11 +162,20 @@ private:
|
||||
|
||||
TrackType track_type_;
|
||||
|
||||
rational track_length_;
|
||||
|
||||
int block_invalidate_cache_stack_;
|
||||
|
||||
int index_;
|
||||
|
||||
private slots:
|
||||
void BlockConnected(NodeEdgePtr edge);
|
||||
|
||||
void BlockDisconnected(NodeEdgePtr edge);
|
||||
|
||||
void BlockListSizeChanged(int size);
|
||||
|
||||
void BlockLengthChanged();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ void TimelineWidget::GoToNextCut()
|
||||
int64_t closest_cut = INT64_MAX;
|
||||
|
||||
foreach (TrackOutput* track, timeline_node_->Tracks()) {
|
||||
int64_t this_track_closest_cut = olive::time_to_timestamp(track->in(), timebase());
|
||||
int64_t this_track_closest_cut = olive::time_to_timestamp(track->track_length(), timebase());
|
||||
|
||||
if (this_track_closest_cut <= playhead_) {
|
||||
this_track_closest_cut = INT64_MAX;
|
||||
@@ -592,7 +592,7 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track)
|
||||
connect(block, SIGNAL(Refreshed()), this, SLOT(BlockChanged()));
|
||||
break;
|
||||
}
|
||||
case Block::kEnd:
|
||||
case Block::kTrack:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ rational TimelineWidget::PointerTool::ValidateOutTrimming(rational movement,
|
||||
if (prevent_overwriting) {
|
||||
// Determine if there's a block in the way
|
||||
Block* next = block->next();
|
||||
while (next != nullptr && next->type() != Block::kEnd) {
|
||||
while (next != nullptr) {
|
||||
if (next->type() == Block::kClip) {
|
||||
latest_out = qMin(latest_out, next->in());
|
||||
break;
|
||||
|
||||
@@ -129,9 +129,7 @@ void TimelineWidget::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_i
|
||||
Block* block_before_ripple = track->NearestBlockBefore(earliest_ripple);
|
||||
|
||||
// If block is null, there will be no blocks after to ripple
|
||||
if (block_before_ripple != nullptr
|
||||
&& block_before_ripple->type() != Block::kEnd
|
||||
&& block_before_ripple->next()->type() != Block::kEnd) {
|
||||
if (block_before_ripple != nullptr) {
|
||||
TimelineViewGhostItem* ghost;
|
||||
|
||||
TrackReference track_ref(track->track_type(), track->Index());
|
||||
|
||||
@@ -90,7 +90,7 @@ void TimelineWidget::RollingTool::InitiateGhosts(TimelineViewBlockItem *clicked_
|
||||
if (ghost->mode() == olive::timeline::kTrimIn && ghost_block->previous() != nullptr) {
|
||||
// Add an extra Ghost for the previous block
|
||||
AddGhostFromBlock(ghost_block->previous(), ghost->Track(), olive::timeline::kTrimOut);
|
||||
} else if (ghost->mode() == olive::timeline::kTrimOut && ghost_block->next() != nullptr && ghost_block->next()->type() != Block::kEnd) {
|
||||
} else if (ghost->mode() == olive::timeline::kTrimOut && ghost_block->next() != nullptr) {
|
||||
AddGhostFromBlock(ghost_block->next(), ghost->Track(), olive::timeline::kTrimIn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ void TimelineWidget::SlideTool::InitiateGhosts(TimelineViewBlockItem *clicked_it
|
||||
AddGhostFromBlock(ghost_block->previous(), ghost->Track(), olive::timeline::kTrimOut);
|
||||
}
|
||||
|
||||
if (ghost_block->next() != nullptr && ghost_block->next()->type() != Block::kEnd) {
|
||||
if (ghost_block->next() != nullptr) {
|
||||
AddGhostFromBlock(ghost_block->next(), ghost->Track(), olive::timeline::kTrimIn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,18 +38,6 @@ Node* TakeNodeFromParentGraph(Node* n, QObject* new_parent = nullptr)
|
||||
return n;
|
||||
}
|
||||
|
||||
TrackOutput* TrackFromBlock(Block* b)
|
||||
{
|
||||
Block* next = b;
|
||||
|
||||
do {
|
||||
next = next->next();
|
||||
} while (next != nullptr && next->type() != Block::kEnd);
|
||||
|
||||
// A little hacky, but this should either be a TrackOutput* or nullptr
|
||||
return static_cast<TrackOutput*>(next);
|
||||
}
|
||||
|
||||
BlockResizeCommand::BlockResizeCommand(Block *block, rational new_length, QUndoCommand* parent) :
|
||||
QUndoCommand(parent),
|
||||
block_(block),
|
||||
@@ -108,8 +96,7 @@ TrackRippleRemoveBlockCommand::TrackRippleRemoveBlockCommand(TrackOutput *track,
|
||||
QUndoCommand(parent),
|
||||
track_(track),
|
||||
block_(block),
|
||||
before_(block->previous()),
|
||||
after_(block->next())
|
||||
before_(block->previous())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -120,7 +107,7 @@ void TrackRippleRemoveBlockCommand::redo()
|
||||
|
||||
void TrackRippleRemoveBlockCommand::undo()
|
||||
{
|
||||
track_->InsertBlockBetweenBlocks(block_, before_, after_);
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
|
||||
TrackInsertBlockBetweenBlocksCommand::TrackInsertBlockBetweenBlocksCommand(TrackOutput *track,
|
||||
@@ -138,7 +125,7 @@ TrackInsertBlockBetweenBlocksCommand::TrackInsertBlockBetweenBlocksCommand(Track
|
||||
|
||||
void TrackInsertBlockBetweenBlocksCommand::redo()
|
||||
{
|
||||
track_->InsertBlockBetweenBlocks(block_, before_, after_);
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
|
||||
void TrackInsertBlockBetweenBlocksCommand::undo()
|
||||
@@ -245,7 +232,7 @@ void TrackRippleRemoveAreaCommand::redo()
|
||||
track_->AppendBlock(insert_);
|
||||
} else {
|
||||
// This is somewhere in the middle of the Sequence
|
||||
track_->InsertBlockBetweenBlocks(insert_, trim_out_, trim_in_);
|
||||
track_->InsertBlockAfter(insert_, trim_out_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,14 +307,14 @@ void TrackPlaceBlockCommand::redo()
|
||||
|
||||
track_ = timeline_->TrackAt(track_index_);
|
||||
|
||||
append_ = (in_ >= track_->in());
|
||||
append_ = (in_ >= track_->track_length());
|
||||
|
||||
// Check if the placement location is past the end of the timeline
|
||||
if (append_) {
|
||||
if (in_ > track_->in()) {
|
||||
if (in_ > track_->track_length()) {
|
||||
// If so, insert a gap here
|
||||
gap_ = new GapBlock();
|
||||
gap_->set_length(in_ - track_->in());
|
||||
gap_->set_length(in_ - track_->track_length());
|
||||
track_->AppendBlock(gap_);
|
||||
}
|
||||
|
||||
@@ -471,7 +458,11 @@ BlockSplitPreservingLinksCommand::BlockSplitPreservingLinksCommand(const QVector
|
||||
Block* b = blocks.at(j);
|
||||
|
||||
if (b->in() < time && b->out() > time) {
|
||||
BlockSplitCommand* split_command = new BlockSplitCommand(TrackFromBlock(b), b, time, this);
|
||||
TrackOutput* track = TrackOutput::TrackFromBlock(b);
|
||||
|
||||
Q_ASSERT(track);
|
||||
|
||||
BlockSplitCommand* split_command = new BlockSplitCommand(track, b, time, this);
|
||||
splits.replace(j, split_command->new_block());
|
||||
} else {
|
||||
splits.replace(j, nullptr);
|
||||
|
||||
@@ -80,7 +80,6 @@ private:
|
||||
Block* block_;
|
||||
|
||||
Block* before_;
|
||||
Block* after_;
|
||||
};
|
||||
|
||||
class TrackPrependBlockCommand : public QUndoCommand {
|
||||
|
||||
@@ -118,7 +118,7 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
|
||||
painter->fillRect(rect(), Qt::white);
|
||||
}
|
||||
break;
|
||||
case Block::kEnd:
|
||||
case Block::kTrack:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user