added some more timeline functions
This commit is contained in:
@@ -59,9 +59,16 @@ const rational &Block::out()
|
||||
return out_point_;
|
||||
}
|
||||
|
||||
const rational& Block::length()
|
||||
{
|
||||
return length_;
|
||||
}
|
||||
|
||||
void Block::set_length(const rational &length)
|
||||
{
|
||||
Q_UNUSED(length)
|
||||
length_ = length;
|
||||
|
||||
RefreshFollowing();
|
||||
}
|
||||
|
||||
Block *Block::previous()
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
kEnd
|
||||
};
|
||||
|
||||
virtual Block* copy() = 0;
|
||||
|
||||
virtual Type type() = 0;
|
||||
|
||||
virtual QString Category() override;
|
||||
@@ -48,8 +50,8 @@ public:
|
||||
const rational& in();
|
||||
const rational& out();
|
||||
|
||||
virtual rational length() = 0;
|
||||
virtual void set_length(const rational& length);
|
||||
virtual const rational &length();
|
||||
virtual void set_length(const rational &length);
|
||||
|
||||
virtual Block* previous();
|
||||
virtual Block* next();
|
||||
@@ -106,6 +108,8 @@ private:
|
||||
rational in_point_;
|
||||
rational out_point_;
|
||||
|
||||
rational length_;
|
||||
|
||||
private slots:
|
||||
void BlockOrderChanged(NodeEdgePtr edge);
|
||||
|
||||
|
||||
@@ -29,6 +29,19 @@ ClipBlock::ClipBlock()
|
||||
AddParameter(texture_input_);
|
||||
}
|
||||
|
||||
Block *ClipBlock::copy()
|
||||
{
|
||||
ClipBlock* c = new ClipBlock();
|
||||
|
||||
// Duplicate connection
|
||||
// FIXME: This behavior should probably be configurable
|
||||
if (texture_input()->IsConnected()) {
|
||||
NodeParam::ConnectEdge(texture_input()->edges().first()->output(), c->texture_input());
|
||||
}
|
||||
|
||||
return new ClipBlock();
|
||||
}
|
||||
|
||||
Block::Type ClipBlock::type()
|
||||
{
|
||||
return kClip;
|
||||
@@ -49,18 +62,6 @@ QString ClipBlock::Description()
|
||||
return tr("A time-based node that represents a media source.");
|
||||
}
|
||||
|
||||
rational ClipBlock::length()
|
||||
{
|
||||
return length_;
|
||||
}
|
||||
|
||||
void ClipBlock::set_length(const rational &length)
|
||||
{
|
||||
length_ = length;
|
||||
|
||||
RefreshFollowing();
|
||||
}
|
||||
|
||||
NodeInput *ClipBlock::texture_input()
|
||||
{
|
||||
return texture_input_;
|
||||
|
||||
@@ -32,15 +32,14 @@ class ClipBlock : public Block
|
||||
public:
|
||||
ClipBlock();
|
||||
|
||||
virtual Block* copy() override;
|
||||
|
||||
virtual Type type() override;
|
||||
|
||||
virtual QString Name() override;
|
||||
virtual QString id() override;
|
||||
virtual QString Description() override;
|
||||
|
||||
virtual rational length() override;
|
||||
virtual void set_length(const rational &length) override;
|
||||
|
||||
NodeInput* texture_input();
|
||||
|
||||
public slots:
|
||||
@@ -51,7 +50,6 @@ private:
|
||||
|
||||
rational media_in_;
|
||||
|
||||
rational length_;
|
||||
};
|
||||
|
||||
#endif // TIMELINEBLOCK_H
|
||||
|
||||
@@ -24,6 +24,11 @@ GapBlock::GapBlock()
|
||||
{
|
||||
}
|
||||
|
||||
Block *GapBlock::copy()
|
||||
{
|
||||
return new GapBlock();
|
||||
}
|
||||
|
||||
Block::Type GapBlock::type()
|
||||
{
|
||||
return kGap;
|
||||
@@ -43,15 +48,3 @@ QString GapBlock::Description()
|
||||
{
|
||||
return tr("A time-based node that represents an empty space.");
|
||||
}
|
||||
|
||||
rational GapBlock::length()
|
||||
{
|
||||
return length_;
|
||||
}
|
||||
|
||||
void GapBlock::set_length(const rational &length)
|
||||
{
|
||||
length_ = length;
|
||||
|
||||
RefreshFollowing();
|
||||
}
|
||||
|
||||
@@ -32,17 +32,16 @@ class GapBlock : public Block
|
||||
public:
|
||||
GapBlock();
|
||||
|
||||
virtual Block * copy() override;
|
||||
|
||||
virtual Type type() override;
|
||||
|
||||
virtual QString Name() override;
|
||||
virtual QString id() override;
|
||||
virtual QString Description() override;
|
||||
|
||||
virtual rational length() override;
|
||||
virtual void set_length(const rational &length) override;
|
||||
|
||||
private:
|
||||
rational length_;
|
||||
|
||||
};
|
||||
|
||||
#endif // TIMELINEBLOCK_H
|
||||
|
||||
+17
-2
@@ -53,13 +53,13 @@ void NodeGraph::AddNodeWithDependencies(Node *node)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeGraph::RemoveNode(Node *node)
|
||||
void NodeGraph::TakeNode(Node *node, QObject* new_parent)
|
||||
{
|
||||
if (!ContainsNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->setParent(nullptr);
|
||||
node->setParent(new_parent);
|
||||
|
||||
disconnect(node, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr)));
|
||||
disconnect(node, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr)));
|
||||
@@ -67,6 +67,21 @@ void NodeGraph::RemoveNode(Node *node)
|
||||
emit NodeRemoved(node);
|
||||
}
|
||||
|
||||
QList<Node *> NodeGraph::TakeNodeWithItsDependencies(Node *node, QObject *new_parent)
|
||||
{
|
||||
if (!ContainsNode(node)) {
|
||||
return QList<Node*>();
|
||||
}
|
||||
|
||||
QList<Node*> deps = node->GetExclusiveDependencies();
|
||||
|
||||
foreach (Node* d, deps) {
|
||||
TakeNode(d, new_parent);
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
QList<Node *> NodeGraph::nodes()
|
||||
{
|
||||
return static_qobjectlist_cast<Node>(children());
|
||||
|
||||
+15
-3
@@ -49,14 +49,26 @@ public:
|
||||
* @brief Adds a node to this graph and all nodes connected to its inputs
|
||||
*
|
||||
* Adds the Node to the graph and runs through its inputs adding all of its dependencies (and all of their
|
||||
* dependencies and so forth).
|
||||
* dependencies and so forth). The graph takes ownershi of all Nodes added through this process.
|
||||
*/
|
||||
void AddNodeWithDependencies(Node* node);
|
||||
|
||||
/**
|
||||
* @brief Removes a Node from the graph BUT doesn't destroy it. Ownership is returned to the caller.
|
||||
* @brief Removes a Node from the graph BUT doesn't destroy it. Ownership is passed to `new_parent`.
|
||||
*/
|
||||
void TakeNode(Node* node);
|
||||
void TakeNode(Node* node, QObject* new_parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Removes a Node from the graph and its dependencies (ONLY if the dependencies are exclusive to this Node).
|
||||
*
|
||||
* Returns a list of all Nodes that were removed in this process (except the Node used as a parameter)
|
||||
*
|
||||
* Only dependencies that are exclusively dependencies of this Node are removed. If a dependency Node is also
|
||||
* used as the dependency of another Node, it is not removed and not returned in the list.
|
||||
*
|
||||
* Ownership of all Nodes is passed to `new_parent`.
|
||||
*/
|
||||
QList<Node*> TakeNodeWithItsDependencies(Node* node, QObject* new_parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a complete list of the nodes belonging to this graph
|
||||
|
||||
@@ -119,6 +119,41 @@ QList<Node *> Node::GetDependencies()
|
||||
return node_list;
|
||||
}
|
||||
|
||||
QList<Node *> Node::GetExclusiveDependencies()
|
||||
{
|
||||
QList<Node*> deps = GetDependencies();
|
||||
|
||||
// Filter out any dependencies that are used elsewhere
|
||||
for (int i=0;i<deps.size();i++) {
|
||||
QList<NodeParam*> params = deps.at(i)->parameters();
|
||||
|
||||
// See if any of this Node's outputs are used outside of this dep list
|
||||
for (int j=0;j<params.size();j++) {
|
||||
NodeParam* p = params.at(j);
|
||||
|
||||
if (p->type() == NodeParam::kOutput) {
|
||||
QVector<NodeEdgePtr> edges = p->edges();
|
||||
|
||||
for (int k=0;k<edges.size();k++) {
|
||||
NodeEdgePtr edge = edges.at(k);
|
||||
|
||||
// If any edge goes to from an output here to an input of a Node that isn't in this dep list, it's NOT an
|
||||
// exclusive dependency
|
||||
if (deps.contains(edge->input()->parent())) {
|
||||
deps.removeAt(i);
|
||||
|
||||
i--; // -1 since we just removed a Node here
|
||||
j = params.size(); // No need to keep looking at this Node's params
|
||||
break; // Or this param's edges
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
QVariant Node::PtrToValue(void *ptr)
|
||||
{
|
||||
return reinterpret_cast<quintptr>(ptr);
|
||||
|
||||
@@ -113,6 +113,14 @@ public:
|
||||
*/
|
||||
QList<Node*> GetDependencies();
|
||||
|
||||
/**
|
||||
* @brief Returns a list of Nodes that this Node is dependent on, provided no other Nodes are dependent on them
|
||||
* outside of this hierarchy.
|
||||
*
|
||||
* Similar to GetDependencies(), but excludes any Nodes that are used outside the dependency graph of this Node.
|
||||
*/
|
||||
QList<Node*> GetExclusiveDependencies();
|
||||
|
||||
/**
|
||||
* @brief Convert a pointer to a value that can be sent between NodeParams
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "node/graph.h"
|
||||
|
||||
TimelineOutput::TimelineOutput() :
|
||||
first_block_(nullptr),
|
||||
current_block_(this),
|
||||
attached_timeline_(nullptr)
|
||||
{
|
||||
@@ -37,6 +36,11 @@ Block::Type TimelineOutput::type()
|
||||
return kEnd;
|
||||
}
|
||||
|
||||
Block *TimelineOutput::copy()
|
||||
{
|
||||
return new TimelineOutput();
|
||||
}
|
||||
|
||||
QString TimelineOutput::Name()
|
||||
{
|
||||
return tr("Timeline");
|
||||
@@ -89,14 +93,16 @@ void TimelineOutput::AttachTimeline(TimelinePanel *timeline)
|
||||
previous_block = previous_block->previous();
|
||||
}
|
||||
|
||||
connect(attached_timeline_, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int)));
|
||||
connect(attached_timeline_, SIGNAL(RequestPlaceBlock(Block*, rational)), this, SLOT(PlaceBlock(Block*, rational)));
|
||||
TimelineView* view = attached_timeline_->view();
|
||||
|
||||
connect(view, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int)));
|
||||
connect(view, SIGNAL(RequestPlaceBlock(Block*, rational)), this, SLOT(PlaceBlock(Block*, rational)));
|
||||
}
|
||||
}
|
||||
|
||||
rational TimelineOutput::length()
|
||||
void TimelineOutput::set_length(const rational &)
|
||||
{
|
||||
return 0;
|
||||
// Prevent length changing on this Block
|
||||
}
|
||||
|
||||
void TimelineOutput::Refresh()
|
||||
@@ -167,13 +173,9 @@ void TimelineOutput::InsertBlockBetweenBlocks(Block *block, Block *before, Block
|
||||
Block::ConnectBlocks(block, after);
|
||||
}
|
||||
|
||||
Block *TimelineOutput::first_block()
|
||||
void TimelineOutput::InsertBlockAfter(Block *block, Block *before)
|
||||
{
|
||||
if (block_cache_.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return block_cache_.first();
|
||||
InsertBlockBetweenBlocks(block, before, before->next());
|
||||
}
|
||||
|
||||
Block *TimelineOutput::attached_block()
|
||||
@@ -248,6 +250,7 @@ void TimelineOutput::PlaceBlock(Block *block, rational start)
|
||||
{
|
||||
AddBlockToGraph(block);
|
||||
|
||||
// Place block at the beginning
|
||||
if (start == 0) {
|
||||
// FIXME: Remove existing
|
||||
|
||||
@@ -256,15 +259,16 @@ void TimelineOutput::PlaceBlock(Block *block, rational start)
|
||||
}
|
||||
|
||||
// Check if the placement location is past the end of the timeline
|
||||
if (start > in()) {
|
||||
// FIXME: Remove existing
|
||||
if (start >= in()) {
|
||||
if (start > in()) {
|
||||
// If so, insert a gap here
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(start - in());
|
||||
|
||||
// If so, insert a gap here
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(start - in());
|
||||
// Then append them
|
||||
AppendBlock(gap);
|
||||
}
|
||||
|
||||
// Then append them
|
||||
AppendBlock(gap);
|
||||
AppendBlock(block);
|
||||
|
||||
return;
|
||||
@@ -284,3 +288,74 @@ void TimelineOutput::PlaceBlock(Block *block, rational start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineOutput::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);
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineOutput::RippleRemoveBlock(Block *block)
|
||||
{
|
||||
Block* previous = block->previous();
|
||||
Block* next = block->next();
|
||||
|
||||
if (previous != nullptr) {
|
||||
Block::DisconnectBlocks(previous, block);
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
Block::DisconnectBlocks(block, next);
|
||||
}
|
||||
|
||||
if (previous != nullptr && next != nullptr) {
|
||||
Block::ConnectBlocks(previous, next);
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineOutput::SplitBlock(Block *block, rational time)
|
||||
{
|
||||
if (time < block->in() || time >= block->out()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rational original_length = block->length();
|
||||
|
||||
block->set_length(time - block->in());
|
||||
|
||||
Block* copy = block->copy();
|
||||
copy->set_length(original_length - block->length());
|
||||
InsertBlockAfter(copy, block);
|
||||
}
|
||||
|
||||
void TimelineOutput::SpliceBlock(Block *inner, Block *outer, rational inner_in)
|
||||
{
|
||||
Q_ASSERT(inner_in >= outer->in() && inner_in < outer->out());
|
||||
|
||||
// Cache original length
|
||||
rational original_length = outer->length();
|
||||
|
||||
// Set outer clip to the clip that PRECEDES the inner clip
|
||||
outer->set_length(inner_in - outer->in());
|
||||
|
||||
// Insert inner clip between BEFORE clip and its next clip
|
||||
InsertBlockAfter(inner, outer);
|
||||
|
||||
// Create the AFTER clip
|
||||
Block* copy = outer->copy();
|
||||
copy->set_length(original_length - outer->length() - inner->length());
|
||||
InsertBlockAfter(copy, inner);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ public:
|
||||
|
||||
virtual Type type() override;
|
||||
|
||||
virtual Block* copy() override;
|
||||
|
||||
virtual QString Name() override;
|
||||
virtual QString id() override;
|
||||
virtual QString Category() override;
|
||||
@@ -42,7 +44,7 @@ public:
|
||||
|
||||
void AttachTimeline(TimelinePanel* timeline);
|
||||
|
||||
virtual rational length() override;
|
||||
virtual void set_length(const rational &length) override;
|
||||
|
||||
virtual void Refresh() override;
|
||||
|
||||
@@ -67,13 +69,10 @@ private:
|
||||
*/
|
||||
void AddBlockToGraph(Block* block);
|
||||
|
||||
QVector<Block*> block_cache_;
|
||||
|
||||
Block* first_block();
|
||||
|
||||
Block* attached_block();
|
||||
|
||||
Block* first_block_;
|
||||
QVector<Block*> block_cache_;
|
||||
|
||||
Block* current_block_;
|
||||
|
||||
TimelinePanel* attached_timeline_;
|
||||
@@ -99,6 +98,13 @@ private slots:
|
||||
*/
|
||||
void InsertBlockBetweenBlocks(Block* block, Block* before, Block* after);
|
||||
|
||||
/**
|
||||
* @brief Inserts Block after another Block
|
||||
*
|
||||
* Equivalent to calling InsertBlockBetweenBlocks(block, before, before->next())
|
||||
*/
|
||||
void InsertBlockAfter(Block* block, Block* before);
|
||||
|
||||
/**
|
||||
* @brief Adds Block `block` at the very end of the Sequence after all other clips
|
||||
*/
|
||||
@@ -124,14 +130,15 @@ private slots:
|
||||
void RippleRemoveBlock(Block* block);
|
||||
|
||||
/**
|
||||
* @brief Removes the Block at the given index pushing all subsequent Blocks earlier to take up the space
|
||||
* @brief Splits `block` into two Blocks at the Sequence point `time`
|
||||
*/
|
||||
void RippleRemoveBlockAtIndex(int index);
|
||||
void SplitBlock(Block* block, rational time);
|
||||
|
||||
/**
|
||||
* @brief Removes the last Block of the Sequence at the given index
|
||||
* @brief Inserts Block `inner` between Block `outer`, splitting and shortening it to fit without changing the overall
|
||||
* length
|
||||
*/
|
||||
void RippleRemoveLast();
|
||||
void SpliceBlock(Block* inner, Block* outer, rational inner_in);
|
||||
};
|
||||
|
||||
#endif // TIMELINEOUTPUT_H
|
||||
|
||||
@@ -57,6 +57,11 @@ int NodeParam::index()
|
||||
return parent()->IndexOfParameter(this);
|
||||
}
|
||||
|
||||
bool NodeParam::IsConnected()
|
||||
{
|
||||
return !edges_.isEmpty();
|
||||
}
|
||||
|
||||
const QVector<NodeEdgePtr> &NodeParam::edges()
|
||||
{
|
||||
return edges_;
|
||||
|
||||
@@ -106,6 +106,11 @@ public:
|
||||
*/
|
||||
int index();
|
||||
|
||||
/**
|
||||
* @brief Returns whether anything is connected to this parameter or not
|
||||
*/
|
||||
bool IsConnected();
|
||||
|
||||
/**
|
||||
* @brief Return a list of edges (aka connections to other nodes)
|
||||
*
|
||||
|
||||
@@ -37,8 +37,6 @@ TimelinePanel::TimelinePanel(QWidget *parent) :
|
||||
layout->addWidget(ruler_);
|
||||
|
||||
view_ = new TimelineView(this);
|
||||
connect(view_, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SIGNAL(RequestInsertBlockAtIndex(Block*, int)));
|
||||
connect(view_, SIGNAL(RequestPlaceBlock(Block*, rational)), this, SIGNAL(RequestPlaceBlock(Block*, rational)));
|
||||
layout->addWidget(view_);
|
||||
|
||||
connect(view_->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int)));
|
||||
|
||||
@@ -88,4 +88,7 @@ private:
|
||||
|
||||
using StreamPtr = std::shared_ptr<Stream>;
|
||||
|
||||
#include <QMetaType>
|
||||
Q_DECLARE_METATYPE(StreamPtr)
|
||||
|
||||
#endif // STREAM_H
|
||||
|
||||
@@ -198,7 +198,11 @@ void TimelineView::ClearGhosts()
|
||||
|
||||
void TimelineView::BlockChanged()
|
||||
{
|
||||
clip_items_[static_cast<Block*>(sender())]->UpdateRect();
|
||||
TimelineViewRect* rect = clip_items_[static_cast<Block*>(sender())];
|
||||
|
||||
if (rect != nullptr) {
|
||||
rect->UpdateRect();
|
||||
}
|
||||
}
|
||||
|
||||
TimelineView::Tool::Tool(TimelineView *parent) :
|
||||
|
||||
@@ -40,6 +40,16 @@ const rational &TimelineViewGhostItem::Out()
|
||||
return out_;
|
||||
}
|
||||
|
||||
rational TimelineViewGhostItem::Length()
|
||||
{
|
||||
return out_ - in_;
|
||||
}
|
||||
|
||||
rational TimelineViewGhostItem::AdjustedLength()
|
||||
{
|
||||
return GetAdjustedOut() - GetAdjustedIn();
|
||||
}
|
||||
|
||||
void TimelineViewGhostItem::SetIn(const rational &in)
|
||||
{
|
||||
in_ = in;
|
||||
@@ -78,14 +88,14 @@ rational TimelineViewGhostItem::GetAdjustedOut()
|
||||
return out_ + out_adj_;
|
||||
}
|
||||
|
||||
StreamPtr TimelineViewGhostItem::stream()
|
||||
const QVariant &TimelineViewGhostItem::data()
|
||||
{
|
||||
return stream_;
|
||||
return data_;
|
||||
}
|
||||
|
||||
void TimelineViewGhostItem::SetStream(StreamPtr f)
|
||||
void TimelineViewGhostItem::SetData(const QVariant &data)
|
||||
{
|
||||
stream_ = f;
|
||||
data_ = data;
|
||||
}
|
||||
|
||||
void TimelineViewGhostItem::UpdateRect()
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef TIMELINEVIEWGHOSTITEM_H
|
||||
#define TIMELINEVIEWGHOSTITEM_H
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "timelineviewrect.h"
|
||||
|
||||
@@ -35,6 +37,9 @@ public:
|
||||
const rational& In();
|
||||
const rational& Out();
|
||||
|
||||
rational Length();
|
||||
rational AdjustedLength();
|
||||
|
||||
void SetIn(const rational& in);
|
||||
void SetOut(const rational& out);
|
||||
|
||||
@@ -44,8 +49,8 @@ public:
|
||||
rational GetAdjustedIn();
|
||||
rational GetAdjustedOut();
|
||||
|
||||
StreamPtr stream();
|
||||
void SetStream(StreamPtr f);
|
||||
const QVariant& data();
|
||||
void SetData(const QVariant& data);
|
||||
|
||||
virtual void UpdateRect() override;
|
||||
|
||||
@@ -59,6 +64,8 @@ private:
|
||||
rational out_adj_;
|
||||
|
||||
StreamPtr stream_;
|
||||
|
||||
QVariant data_;
|
||||
};
|
||||
|
||||
#endif // TIMELINEVIEWGHOSTITEM_H
|
||||
|
||||
@@ -47,6 +47,9 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event)
|
||||
quintptr item_ptr;
|
||||
int r;
|
||||
|
||||
// Set ghosts to start where the cursor entered
|
||||
rational ghost_start = parent()->ScreenToTime(event->pos().x());
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
stream >> r >> item_ptr;
|
||||
|
||||
@@ -65,14 +68,19 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event)
|
||||
rational footage_duration(stream->timebase().numerator() * stream->duration(),
|
||||
stream->timebase().denominator());
|
||||
|
||||
ghost->SetIn(0);
|
||||
ghost->SetOut(footage_duration);
|
||||
ghost->SetStream(stream);
|
||||
ghost->SetIn(ghost_start);
|
||||
ghost->SetOut(ghost_start + footage_duration);
|
||||
ghost->SetData(QVariant::fromValue(stream));
|
||||
|
||||
parent()->AddGhost(ghost);
|
||||
|
||||
// Stack each ghost one after the other
|
||||
ghost_start += footage_duration;
|
||||
}
|
||||
}
|
||||
|
||||
drag_start_ = event->pos();
|
||||
|
||||
event->accept();
|
||||
} else {
|
||||
// FIXME: Implement dropping from file
|
||||
@@ -85,10 +93,12 @@ void TimelineView::ImportTool::DragMove(QDragMoveEvent *event)
|
||||
if (parent()->HasGhosts()) {
|
||||
// Move ghosts to the mouse cursor
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
rational time = parent()->ScreenToTime(event->pos().x());
|
||||
QPoint movement = event->pos() - drag_start_;
|
||||
|
||||
ghost->SetOut(ghost->Out() - ghost->In() + time);
|
||||
ghost->SetIn(time);
|
||||
rational time_movement = parent()->ScreenToTime(movement.x());
|
||||
|
||||
ghost->SetInAdjustment(time_movement);
|
||||
ghost->SetOutAdjustment(time_movement);
|
||||
}
|
||||
|
||||
event->accept();
|
||||
@@ -125,15 +135,15 @@ void TimelineView::ImportTool::DragDrop(QDropEvent *event)
|
||||
clip->setParent(&node_memory_manager);
|
||||
media->setParent(&node_memory_manager);
|
||||
|
||||
clip->set_length(ghost->Out() - ghost->In());
|
||||
media->SetFootage(ghost->stream()->footage());
|
||||
clip->set_length(ghost->Length());
|
||||
media->SetFootage(ghost->data().value<StreamPtr>()->footage());
|
||||
|
||||
NodeParam::ConnectEdge(media->texture_output(), clip->texture_input());
|
||||
|
||||
if (event->keyboardModifiers() & Qt::ControlModifier) {
|
||||
emit parent()->RequestPlaceBlock(clip, ghost->In());
|
||||
emit parent()->RequestInsertBlockAtTime(clip, ghost->GetAdjustedIn());
|
||||
} else {
|
||||
emit parent()->RequestInsertBlockAtTime(clip, ghost->In());
|
||||
emit parent()->RequestPlaceBlock(clip, ghost->GetAdjustedIn());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event)
|
||||
parent()->QGraphicsView::mouseMoveEvent(event);
|
||||
|
||||
if (!dragging_) {
|
||||
|
||||
// Let's see if there's anything selected to drag
|
||||
if (parent()->itemAt(event->pos()) != nullptr) {
|
||||
QList<QGraphicsItem*> selected_items = parent()->scene_.selectedItems();
|
||||
@@ -76,6 +77,7 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event)
|
||||
}
|
||||
|
||||
dragging_ = true;
|
||||
|
||||
} else if (!parent()->ghost_items_.isEmpty()) {
|
||||
QPoint movement = event->pos() - drag_start_;
|
||||
|
||||
@@ -103,6 +105,12 @@ void TimelineView::PointerTool::MouseRelease(QMouseEvent *event)
|
||||
|
||||
parent()->QGraphicsView::mouseReleaseEvent(event);
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
|
||||
Block* b = Node::ValueToPtr<Block>(ghost->data());
|
||||
|
||||
emit parent()->RequestPlaceBlock(b, ghost->In());
|
||||
}
|
||||
|
||||
parent()->ClearGhosts();
|
||||
|
||||
dragging_ = false;
|
||||
|
||||
Reference in New Issue
Block a user