began new infrastructure

Yep, this is another one of my "famous" sweeping rewrites. Expect things to break.

Goals for this are:
- Greatly simplify node connections (particularly with arrays) so the code requires less maintenance/is more stable
- Redesign node structure to address issues where UI would stall for lengthy periods of time
- Less reliance on shared ptrs/greater reliance on QObject system for inheritance/memory management
- General code cleanup and improvements
This commit is contained in:
itsmattkc
2021-01-05 11:20:38 +11:00
parent 19eabf2830
commit 181235f6ce
152 changed files with 3932 additions and 8166 deletions
+1 -1
View File
@@ -29,9 +29,9 @@ add_subdirectory(keyframeview)
add_subdirectory(manageddisplay)
add_subdirectory(menu)
add_subdirectory(nodecombobox)
add_subdirectory(nodeparamview)
add_subdirectory(nodetableview)
add_subdirectory(nodetreeview)
add_subdirectory(nodeparamview)
add_subdirectory(nodeview)
add_subdirectory(panel)
add_subdirectory(path)
@@ -29,7 +29,7 @@
namespace olive {
BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem *parent) :
BezierControlPointItem::BezierControlPointItem(NodeKeyframe* key, NodeKeyframe::BezierType mode, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
mode_(mode),
@@ -38,12 +38,12 @@ BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe
{
setFlag(QGraphicsItem::ItemIsMovable);
connect(key.get(), &NodeKeyframe::TimeChanged, this, &BezierControlPointItem::UpdatePos);
connect(key, &NodeKeyframe::TimeChanged, this, &BezierControlPointItem::UpdatePos);
if (mode_ == NodeKeyframe::kInHandle) {
connect(key.get(), &NodeKeyframe::BezierControlInChanged, this, &BezierControlPointItem::UpdatePos);
connect(key, &NodeKeyframe::BezierControlInChanged, this, &BezierControlPointItem::UpdatePos);
} else {
connect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &BezierControlPointItem::UpdatePos);
connect(key, &NodeKeyframe::BezierControlOutChanged, this, &BezierControlPointItem::UpdatePos);
}
@@ -64,7 +64,7 @@ void BezierControlPointItem::SetYScale(double scale)
UpdatePos();
}
NodeKeyframePtr BezierControlPointItem::key() const
NodeKeyframe* BezierControlPointItem::key() const
{
return key_;
}
@@ -30,13 +30,13 @@ namespace olive {
class BezierControlPointItem : public QObject, public QGraphicsRectItem
{
public:
BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem* parent = nullptr);
BezierControlPointItem(NodeKeyframe* key, NodeKeyframe::BezierType mode, QGraphicsItem* parent = nullptr);
void SetXScale(double scale);
void SetYScale(double scale);
NodeKeyframePtr key() const;
NodeKeyframe* key() const;
const NodeKeyframe::BezierType& mode() const;
@@ -50,7 +50,7 @@ protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
NodeKeyframe::BezierType mode_;
+108 -84
View File
@@ -20,8 +20,9 @@
#include "curveview.h"
#include <QScrollBar>
#include <QHash>
#include <QMouseEvent>
#include <QScrollBar>
#include <QtMath>
#include <cfloat>
@@ -67,16 +68,9 @@ void CurveView::ConnectInput(NodeInput *input)
return;
}
// Add keyframes from this input
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
this->AddKeyframe(key);
}
if (!keyframe_colors_.contains(&track)) {
// Generate a random color for this input
keyframe_colors_.insert(&track, QColor::fromHsv(std::rand()%360, std::rand()%255, 255));
}
// Add keyframes from each subelement including primary (-1)
for (int i=-1; i<input->ArraySize(); i++) {
ConnectInputElement(input, i);
}
// Append to the list
@@ -89,9 +83,7 @@ void CurveView::ConnectInput(NodeInput *input)
void CurveView::DisconnectNode(Node *node)
{
QVector<NodeInput*> inputs = node->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
foreach (NodeInput* i, node->parameters()) {
DisconnectInput(i);
}
}
@@ -166,82 +158,89 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
// Draw keyframe lines
foreach (NodeInput* input, connected_inputs_) {
if (input->is_keyframing()) {
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
if (!track.isEmpty()) {
painter->setPen(QPen(keyframe_colors_.value(&track), qMax(1, fontMetrics().height() / 4)));
for (int j=-1; j<input->ArraySize(); j++) {
if (input->IsKeyframing(j)) {
const QVector<NodeKeyframeTrack>& tracks = input->GetKeyframeTracks(j);
QVector<QLineF> keyframe_lines;
for (int k=0; k<tracks.size(); k++) {
const NodeKeyframeTrack& track = tracks.at(k);
// Draw straight line leading to first keyframe
QPointF first_key_pos = item_map().value(track.first().get())->pos();
keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos));
if (!track.isEmpty()) {
painter->setPen(QPen(keyframe_colors_.value(GetKeyframeTrackUniqueID(input, j, k)),
qMax(1, fontMetrics().height() / 4)));
// Draw lines between each keyframe
for (int i=1;i<track.size();i++) {
NodeKeyframePtr before = track.at(i-1);
NodeKeyframePtr after = track.at(i);
QVector<QLineF> keyframe_lines;
KeyframeViewItem* before_item = item_map().value(before.get());
KeyframeViewItem* after_item = item_map().value(after.get());
// Draw straight line leading to first keyframe
QPointF first_key_pos = item_map().value(track.first())->pos();
keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos));
if (before->type() == NodeKeyframe::kHold) {
// Draw a hold keyframe (basically a right angle)
keyframe_lines.append(QLineF(before_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
before_item->pos().y()));
keyframe_lines.append(QLineF(after_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
after_item->pos().y()));
} else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// Draw a cubic bezier
// Draw lines between each keyframe
for (int i=1;i<track.size();i++) {
NodeKeyframe* before = track.at(i-1);
NodeKeyframe* after = track.at(i);
// Cubic beziers have two control points, so we can just use both
QPointF before_control_point = before_item->pos() + ScalePoint(before->bezier_control_out());
QPointF after_control_point = after_item->pos() + ScalePoint(after->bezier_control_in());
KeyframeViewItem* before_item = item_map().value(before);
KeyframeViewItem* after_item = item_map().value(after);
QPainterPath path;
path.moveTo(before_item->pos());
path.cubicTo(before_control_point, after_control_point, after_item->pos());
painter->drawPath(path);
if (before->type() == NodeKeyframe::kHold) {
// Draw a hold keyframe (basically a right angle)
keyframe_lines.append(QLineF(before_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
before_item->pos().y()));
keyframe_lines.append(QLineF(after_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
after_item->pos().y()));
} else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// Draw a cubic bezier
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
// Draw a quadratic bezier
// Cubic beziers have two control points, so we can just use both
QPointF before_control_point = before_item->pos() + ScalePoint(before->bezier_control_out());
QPointF after_control_point = after_item->pos() + ScalePoint(after->bezier_control_in());
// Quadratic beziers have a single control point, we just have to determine which it is
QPointF key_anchor;
QPointF control_point;
QPainterPath path;
path.moveTo(before_item->pos());
path.cubicTo(before_control_point, after_control_point, after_item->pos());
painter->drawPath(path);
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
// Draw a quadratic bezier
// Quadratic beziers have a single control point, we just have to determine which it is
QPointF key_anchor;
QPointF control_point;
if (before->type() == NodeKeyframe::kBezier) {
key_anchor = before_item->pos();
control_point = before->bezier_control_out();
} else {
key_anchor = after_item->pos();
control_point = after->bezier_control_in();
}
// Scale control point
control_point = key_anchor + ScalePoint(control_point);
// Create the path from both keyframes
QPainterPath path;
path.moveTo(before_item->pos());
path.quadTo(control_point, after_item->pos());
painter->drawPath(path);
if (before->type() == NodeKeyframe::kBezier) {
key_anchor = before_item->pos();
control_point = before->bezier_control_out();
} else {
key_anchor = after_item->pos();
control_point = after->bezier_control_in();
// Linear to linear
keyframe_lines.append(QLineF(before_item->pos(), after_item->pos()));
}
// Scale control point
control_point = key_anchor + ScalePoint(control_point);
// Create the path from both keyframes
QPainterPath path;
path.moveTo(before_item->pos());
path.quadTo(control_point, after_item->pos());
painter->drawPath(path);
} else {
// Linear to linear
keyframe_lines.append(QLineF(before_item->pos(), after_item->pos()));
}
// Draw straight line leading from end keyframe
QPointF last_key_pos = item_map().value(track.last())->pos();
keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y())));
painter->drawLines(keyframe_lines);
}
// Draw straight line leading from end keyframe
QPointF last_key_pos = item_map().value(track.last().get())->pos();
keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y())));
painter->drawLines(keyframe_lines);
}
}
}
@@ -284,7 +283,7 @@ void CurveView::VerticalScaleChangedEvent(double scale)
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
for (iterator=item_map().begin();iterator!=item_map().end();iterator++) {
SetItemYFromKeyframeValue(iterator.value()->key().get(), iterator.value());
SetItemYFromKeyframeValue(iterator.value()->key(), iterator.value());
}
}
@@ -306,6 +305,26 @@ void CurveView::ContextMenuEvent(Menu &m)
//QAction* reset_zoom_action = m.addAction(tr("Reset Zoom"));
}
void CurveView::ConnectInputElement(NodeInput *input, int element)
{
const QVector<NodeKeyframeTrack>& tracks = input->GetKeyframeTracks(element);
for (int i=0; i<tracks.size(); i++) {
const NodeKeyframeTrack& track = tracks.at(i);
foreach (NodeKeyframe* key, track) {
this->AddKeyframe(key);
}
uint h = GetKeyframeTrackUniqueID(input, element, i);
if (!keyframe_colors_.contains(h)) {
// Generate a random color for this input
keyframe_colors_.insert(h, QColor::fromHsv(std::rand()%360, std::rand()%255, 255));
}
}
}
qreal CurveView::GetItemYFromKeyframeValue(NodeKeyframe *key)
{
return GetItemYFromKeyframeValue(key->value().toDouble());
@@ -340,6 +359,11 @@ void CurveView::CreateBezierControlPoints(KeyframeViewItem* item)
connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);
}
uint CurveView::GetKeyframeTrackUniqueID(NodeInput *input, int element, int track)
{
return ::qHash(input) ^ ::qHash(element) ^ ::qHash(track);
}
void CurveView::KeyframeValueChanged()
{
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
@@ -398,10 +422,10 @@ void CurveView::ZoomToFit()
double max_val = DBL_MIN;
for (auto i=item_map().constBegin(); i!=item_map().constEnd(); i++) {
rational transformed_time = GetAdjustedTime(i.key()->parent()->parentNode(),
rational transformed_time = GetAdjustedTime(i.key()->parent()->parent(),
GetTimeTarget(),
i.key()->time(),
NodeParam::kOutput);
false);
min_time = qMin(transformed_time, min_time);
max_time = qMax(transformed_time, max_time);
@@ -421,14 +445,14 @@ void CurveView::ZoomToFit()
verticalScrollBar()->setValue(GetItemYFromKeyframeValue(max_val) - CalculatePaddingFromDimensionScale(this->height()));
}
void CurveView::AddKeyframe(NodeKeyframePtr key)
void CurveView::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = AddKeyframeInternal(key);
SetItemYFromKeyframeValue(key.get(), item);
item->SetOverrideBrush(keyframe_colors_.value(&key->parent()->keyframe_tracks().at(key->track())));
SetItemYFromKeyframeValue(key, item);
item->SetOverrideBrush(keyframe_colors_.value(GetKeyframeTrackUniqueID(key->parent(), key->element(), key->track())));
connect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
connect(key.get(), &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged);
connect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
connect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged);
}
}
+6 -2
View File
@@ -45,7 +45,7 @@ public:
void DisconnectInput(NodeInput* input);
public slots:
void AddKeyframe(NodeKeyframePtr key);
void AddKeyframe(NodeKeyframe* key);
void ZoomToFit();
@@ -63,6 +63,8 @@ protected:
virtual void ContextMenuEvent(Menu &m) override;
private:
void ConnectInputElement(NodeInput* input, int element);
qreal GetItemYFromKeyframeValue(NodeKeyframe* key);
qreal GetItemYFromKeyframeValue(double value);
@@ -74,7 +76,9 @@ private:
void CreateBezierControlPoints(KeyframeViewItem *item);
QMap<const NodeInput::KeyframeTrack*, QColor> keyframe_colors_;
uint GetKeyframeTrackUniqueID(NodeInput* input, int element, int track);
QMap<uint, QColor> keyframe_colors_;
int text_padding_;
+1 -3
View File
@@ -215,9 +215,7 @@ void CurveWidget::UpdateBridgeTime(const int64_t &timestamp)
void CurveWidget::ConnectNode(Node *n)
{
QVector<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
foreach (NodeInput* i, n->parameters()) {
if (tree_view_->IsInputEnabled(i)) {
view_->ConnectInput(i);
}
+1 -1
View File
@@ -42,7 +42,7 @@ void KeyframeView::SceneRectUpdateEvent(QRectF &rect)
rect.setHeight(max_scroll_);
}
void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
void KeyframeView::AddKeyframe(NodeKeyframe* key, int y)
{
QPoint global_pt(0, y);
QPoint local_pt = mapFromGlobal(global_pt);
+1 -1
View File
@@ -42,7 +42,7 @@ protected:
virtual void SceneRectUpdateEvent(QRectF& rect) override;
public slots:
void AddKeyframe(NodeKeyframePtr key, int y);
void AddKeyframe(NodeKeyframe* key, int y);
private:
int max_scroll_;
+23 -27
View File
@@ -63,11 +63,7 @@ void KeyframeViewBase::DeleteSelected()
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
if (i.value()->isSelected()) {
NodeInput* input_parent = i.key()->parent();
new NodeParamRemoveKeyframeCommand(input_parent,
input_parent->get_keyframe_shared_ptr_from_raw(i.key()),
command);
new NodeParamRemoveKeyframeCommand(i.key(), command);
}
}
@@ -76,38 +72,38 @@ void KeyframeViewBase::DeleteSelected()
void KeyframeViewBase::RemoveKeyframesOfNode(Node *n)
{
QVector<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
foreach (NodeInput* i, n->inputs()) {
RemoveKeyframesOfInput(i);
}
}
void KeyframeViewBase::RemoveKeyframesOfInput(NodeInput *i)
void KeyframeViewBase::RemoveKeyframesOfInput(NodeInput *input)
{
foreach (const NodeInput::KeyframeTrack& track, i->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
RemoveKeyframe(key);
for (int i=-1; i<input->ArraySize(); i++) {
foreach (const NodeKeyframeTrack& track, input->GetKeyframeTracks(i)) {
foreach (NodeKeyframe* key, track) {
RemoveKeyframe(key);
}
}
}
}
void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key)
void KeyframeViewBase::RemoveKeyframe(NodeKeyframe* key)
{
KeyframeAboutToBeRemoved(key.get());
KeyframeAboutToBeRemoved(key);
delete item_map_.take(key.get());
delete item_map_.take(key);
}
KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key)
KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframe* key)
{
KeyframeViewItem* item = item_map_.value(key.get());
KeyframeViewItem* item = item_map_.value(key);
if (!item) {
item = new KeyframeViewItem(key);
item->SetTimeTarget(GetTimeTarget());
item->SetScale(GetScale());
item_map_.insert(key.get(), item);
item_map_.insert(key, item);
scene()->addItem(item);
}
@@ -151,7 +147,7 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
selected_keys_.replace(i, {key,
key->x(),
GetAdjustedTime(key->key()->parent()->parentNode(), GetTimeTarget(), key->key()->time(), NodeParam::kOutput),
GetAdjustedTime(key->key()->parent()->parent(), GetTimeTarget(), key->key()->time(), false),
key->key()->value().toDouble()});
}
}
@@ -184,9 +180,9 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
//input_parent->blockSignals(true);
rational node_time = GetAdjustedTime(GetTimeTarget(),
keypair.key->key()->parent()->parentNode(),
keypair.key->key()->parent()->parent(),
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
NodeParam::kInput);
true);
keypair.key->key()->set_time(node_time);
@@ -235,9 +231,9 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
// Calculate the new time for this keyframe
rational node_time = GetAdjustedTime(GetTimeTarget(),
keypair.key->key()->parent()->parentNode(),
keypair.key->key()->parent()->parent(),
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
NodeParam::kInput);
true);
@@ -493,7 +489,7 @@ void KeyframeViewBase::ShowContextMenu()
void KeyframeViewBase::ShowKeyframePropertiesDialog()
{
QList<QGraphicsItem*> items = scene()->selectedItems();
QList<NodeKeyframePtr> keys;
QVector<NodeKeyframe*> keys;
foreach (QGraphicsItem* item, items) {
keys.append(static_cast<KeyframeViewItem*>(item)->key());
@@ -521,15 +517,15 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors()
rational key_time = key_item->key()->time();
QList<NodeKeyframePtr> keys = key_item->key()->parent()->get_keyframe_at_time(key_time);
QVector<NodeKeyframe*> keys = key_item->key()->parent()->GetKeyframesAtTime(key_time, key_item->key()->element());
foreach (NodeKeyframePtr k, keys) {
foreach (NodeKeyframe* k, keys) {
if (k == key_item->key()) {
continue;
}
// Ensure this key is not already selected
KeyframeViewItem* item = item_map_.value(k.get());
KeyframeViewItem* item = item_map_.value(k);
item->setSelected(true);
}
+3 -3
View File
@@ -42,13 +42,13 @@ public:
void RemoveKeyframesOfNode(Node* n);
void RemoveKeyframesOfInput(NodeInput* i);
void RemoveKeyframesOfInput(NodeInput* input);
public slots:
void RemoveKeyframe(NodeKeyframePtr key);
void RemoveKeyframe(NodeKeyframe* key);
protected:
virtual KeyframeViewItem* AddKeyframeInternal(NodeKeyframePtr key);
virtual KeyframeViewItem* AddKeyframeInternal(NodeKeyframe* key);
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
+5 -5
View File
@@ -30,7 +30,7 @@
namespace olive {
KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) :
KeyframeViewItem::KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
scale_(1.0),
@@ -39,8 +39,8 @@ KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) :
{
setFlag(QGraphicsItem::ItemIsSelectable);
connect(key.get(), &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos);
connect(key.get(), &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw);
connect(key, &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos);
connect(key, &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw);
int keyframe_size = QtUtils::QFontMetricsWidth(qApp->fontMetrics(), "Oi");
int half_sz = keyframe_size/2;
@@ -69,7 +69,7 @@ void KeyframeViewItem::SetOverrideBrush(const QBrush &b)
setBrush(b);
}
NodeKeyframePtr KeyframeViewItem::key() const
NodeKeyframe* KeyframeViewItem::key() const
{
return key_;
}
@@ -117,7 +117,7 @@ void KeyframeViewItem::TimeTargetChangedEvent(Node *)
void KeyframeViewItem::UpdatePos()
{
rational adjusted = GetAdjustedTime(key_->parent()->parentNode(), GetTimeTarget(), key_->time(), NodeParam::kOutput);
rational adjusted = GetAdjustedTime(key_->parent()->parent(), GetTimeTarget(), key_->time(), false);
setPos(adjusted.toDouble() * scale_, vert_center_);
}
+3 -3
View File
@@ -32,7 +32,7 @@ class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTa
{
Q_OBJECT
public:
KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent = nullptr);
KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent = nullptr);
void SetOverrideY(qreal vertical_center);
@@ -40,7 +40,7 @@ public:
void SetOverrideBrush(const QBrush& b);
NodeKeyframePtr key() const;
NodeKeyframe* key() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
@@ -48,7 +48,7 @@ protected:
virtual void TimeTargetChangedEvent(Node* ) override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
double scale_;
+5 -5
View File
@@ -26,7 +26,7 @@
namespace olive {
KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand *parent) :
KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframe* key, NodeKeyframe::Type type, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
old_type_(key->type()),
@@ -36,7 +36,7 @@ KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe
Project *KeyframeSetTypeCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(key_->parent()->parentNode()->parent())->project();
return key_->parent()->parent()->parent()->project();
}
void KeyframeSetTypeCommand::redo_internal()
@@ -49,7 +49,7 @@ void KeyframeSetTypeCommand::undo_internal()
key_->set_type(old_type_);
}
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand *parent) :
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframe* key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
mode_(mode),
@@ -58,7 +58,7 @@ KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key
{
}
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF &new_point, const QPointF &old_point, QUndoCommand *parent) :
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframe* key, NodeKeyframe::BezierType mode, const QPointF &new_point, const QPointF &old_point, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
mode_(mode),
@@ -69,7 +69,7 @@ KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key
Project *KeyframeSetBezierControlPoint::GetRelevantProject() const
{
return static_cast<Sequence*>(key_->parent()->parentNode()->parent())->project();
return key_->parent()->parent()->parent()->project();
}
void KeyframeSetBezierControlPoint::redo_internal()
+5 -5
View File
@@ -28,7 +28,7 @@ namespace olive {
class KeyframeSetTypeCommand : public UndoCommand {
public:
KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand* parent = nullptr);
KeyframeSetTypeCommand(NodeKeyframe* key, NodeKeyframe::Type type, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -37,7 +37,7 @@ protected:
virtual void undo_internal() override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
NodeKeyframe::Type old_type_;
@@ -47,8 +47,8 @@ private:
class KeyframeSetBezierControlPoint : public UndoCommand {
public:
KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand* parent = nullptr);
KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& new_point, const QPointF& old_point, QUndoCommand* parent = nullptr);
KeyframeSetBezierControlPoint(NodeKeyframe* key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand* parent = nullptr);
KeyframeSetBezierControlPoint(NodeKeyframe* key, NodeKeyframe::BezierType mode, const QPointF& new_point, const QPointF& old_point, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -57,7 +57,7 @@ protected:
virtual void undo_internal() override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
NodeKeyframe::BezierType mode_;
@@ -151,7 +151,6 @@ void NodeParamView::SelectNodes(const QVector<Node *> &nodes)
connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged);
connect(item, &NodeParamViewItem::InputDoubleClicked, this, &NodeParamView::InputDoubleClicked);
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
connect(item, &NodeParamViewItem::dockLocationChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::dockLocationChanged, this, &NodeParamView::SignalNodeOrder);
-2
View File
@@ -73,8 +73,6 @@ public:
void DeleteSelected();
signals:
void InputDoubleClicked(NodeInput* input);
void RequestSelectNode(const QVector<Node*>& target);
void NodeOrderChanged(const QVector<Node*>& nodes);
@@ -24,7 +24,7 @@
namespace olive {
NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidget* parent) :
NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInput *array, QWidget* parent) :
QWidget(parent),
array_(array)
{
@@ -40,19 +40,19 @@ NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidge
layout->addWidget(plus_btn_);
connect(plus_btn_, &QPushButton::clicked, this, &NodeParamViewArrayWidget::AddElement);
connect(array_, &NodeInputArray::SizeChanged, this, &NodeParamViewArrayWidget::UpdateCounter);
connect(array_, &NodeInput::ArraySizeChanged, this, &NodeParamViewArrayWidget::UpdateCounter);
UpdateCounter();
}
void NodeParamViewArrayWidget::UpdateCounter()
{
count_lbl_->setText(tr("%1 element(s)").arg(array_->GetSize()));
count_lbl_->setText(tr("%1 element(s)").arg(array_->ArraySize()));
}
void NodeParamViewArrayWidget::AddElement()
{
array_->Append();
array_->ArrayResize(array_->ArraySize() + 1);
}
}
@@ -25,7 +25,7 @@
#include <QPushButton>
#include <QWidget>
#include "node/inputarray.h"
#include "node/input.h"
namespace olive {
@@ -33,10 +33,10 @@ class NodeParamViewArrayWidget : public QWidget
{
Q_OBJECT
public:
NodeParamViewArrayWidget(NodeInputArray* array, QWidget* parent = nullptr);
NodeParamViewArrayWidget(NodeInput* array, QWidget* parent = nullptr);
private:
NodeInputArray* array_;
NodeInput* array_;
QLabel* count_lbl_;
@@ -30,9 +30,10 @@
namespace olive {
NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, QWidget *parent) :
NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, int element, QWidget *parent) :
QWidget(parent),
input_(input)
input_(input),
element_(element)
{
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setSpacing(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral(" ")));
@@ -55,18 +56,25 @@ NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, QWidg
connected_to_lbl_->setForegroundRole(QPalette::Link);
connected_to_lbl_->setFont(link_font);
UpdateConnected();
UpdateConnected(nullptr, element_);
connect(input_, &NodeInput::EdgeAdded, this, &NodeParamViewConnectedLabel::UpdateConnected);
connect(input_, &NodeInput::EdgeRemoved, this, &NodeParamViewConnectedLabel::UpdateConnected);
connect(input_, &NodeInput::InputConnected, this, &NodeParamViewConnectedLabel::UpdateConnected);
connect(input_, &NodeInput::InputDisconnected, this, &NodeParamViewConnectedLabel::UpdateConnected);
}
void NodeParamViewConnectedLabel::UpdateConnected()
void NodeParamViewConnectedLabel::UpdateConnected(Node *src, int element)
{
Q_UNUSED(src)
if (element_ != element) {
// Do nothing
return;
}
QString connection_str;
if (input_->is_connected()) {
connection_str = input_->get_connected_node()->Name();
if (input_->IsConnected(element_)) {
connection_str = input_->GetConnectedNode(element_)->Name();
} else {
connection_str = tr("Nothing");
}
@@ -80,7 +88,7 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu()
QAction* disconnect_action = m.addAction(tr("Disconnect"));
connect(disconnect_action, &QAction::triggered, this, [this](){
Core::instance()->undo_stack()->push(new NodeEdgeRemoveCommand(input_->get_connected_output(), input_));
Core::instance()->undo_stack()->push(new NodeEdgeRemoveCommand(input_->GetConnectedNode(element_), input_, element_));
});
m.exec(QCursor::pos());
@@ -29,13 +29,13 @@ namespace olive {
class NodeParamViewConnectedLabel : public QWidget {
Q_OBJECT
public:
NodeParamViewConnectedLabel(NodeInput* input, QWidget* parent = nullptr);
NodeParamViewConnectedLabel(NodeInput* input, int element, QWidget* parent = nullptr);
signals:
void ConnectionClicked();
private slots:
void UpdateConnected();
void UpdateConnected(Node* src, int element);
void ShowLabelContextMenu();
@@ -44,6 +44,8 @@ private:
NodeInput* input_;
int element_;
};
}
+50 -62
View File
@@ -43,17 +43,14 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
this->setTitleBarWidget(title_bar_);
// Create and add contents widget
QVector<NodeInput*> inputs;
QVector<Node::InputConnection> inputs;
// Filter out inputs
foreach (NodeParam* p, node->parameters()) {
if (p->type() == NodeParam::kInput) {
inputs.append(static_cast<NodeInput*>(p));
}
foreach (NodeInput* p, node->parameters()) {
inputs.append({p, -1});
}
body_ = new NodeParamViewItemBody(inputs);
connect(body_, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItem::InputDoubleClicked);
connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode);
connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime);
connect(body_, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItem::KeyframeAdded);
@@ -206,7 +203,7 @@ void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
collapse_btn_->click();
}
NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs, QWidget *parent) :
NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeConnectable::InputConnection> &inputs, QWidget *parent) :
QWidget(parent)
{
int row_count = 0;
@@ -215,14 +212,13 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
QGridLayout* content_layout = new QGridLayout(this);
foreach (NodeInput* input, inputs) {
foreach (const NodeConnectable::InputConnection& conn, inputs) {
InputUI ui_objects;
// Add descriptor label
ui_objects.main_label = new ClickableLabel();
connect(ui_objects.main_label, &ClickableLabel::MouseDoubleClicked, this, &NodeParamViewItemBody::LabelDoubleClicked);
if (input->IsArray()) {
if (conn.input->IsArray()) {
QHBoxLayout* array_label_layout = new QHBoxLayout();
array_label_layout->setMargin(0);
@@ -233,7 +229,13 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
content_layout->addLayout(array_label_layout, row_count, 0);
NodeParamViewItemBody* sub_body = new NodeParamViewItemBody(static_cast<NodeInputArray*>(input)->sub_params());
QVector<NodeConnectable::InputConnection> subelements(conn.input->ArraySize());
for (int i=0; i<conn.input->ArraySize(); i++) {
subelements[i] = {conn.input, i};
}
NodeParamViewItemBody* sub_body = new NodeParamViewItemBody(subelements);
sub_bodies_.append(sub_body);
sub_body->layout()->setMargin(0);
content_layout->addWidget(sub_body, row_count + 1, 0, 1, max_col + 1);
@@ -243,14 +245,13 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
connect(sub_body, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItemBody::KeyframeAdded);
connect(sub_body, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
connect(sub_body, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(sub_body, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItemBody::InputDoubleClicked);
connect(sub_body, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);
} else {
content_layout->addWidget(ui_objects.main_label, row_count, 0);
}
// Create a widget/input bridge for this input
ui_objects.widget_bridge = new NodeParamViewWidgetBridge(input, this);
ui_objects.widget_bridge = new NodeParamViewWidgetBridge(conn.input, conn.element, this);
// Add widgets for this parameter to the layout
{
@@ -261,42 +262,44 @@ NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs,
}
}
if (input->is_connectable()) {
if (conn.input->IsConnectable()) {
// Create clickable label used when an input is connected
ui_objects.connected_label = new NodeParamViewConnectedLabel(input);
ui_objects.connected_label = new NodeParamViewConnectedLabel(conn.input, conn.element);
connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::ConnectionClicked, this, &NodeParamViewItemBody::ConnectionClicked);
content_layout->addWidget(ui_objects.connected_label, row_count, 1);
connect(input, &NodeInput::EdgeAdded, this, &NodeParamViewItemBody::EdgeChanged);
connect(input, &NodeInput::EdgeRemoved, this, &NodeParamViewItemBody::EdgeChanged);
connect(conn.input, &NodeInput::InputConnected, this, &NodeParamViewItemBody::EdgeChanged);
connect(conn.input, &NodeInput::InputDisconnected, this, &NodeParamViewItemBody::EdgeChanged);
}
// Add keyframe control to this layout if parameter is keyframable
if (input->is_keyframable()) {
if (conn.input->IsKeyframable()) {
// Hacky but effective way to make sure this widget is always as far right as possible
int control_column = max_col;
ui_objects.key_control = new NodeParamViewKeyframeControl();
ui_objects.key_control->SetInput(input);
ui_objects.key_control->SetInput(conn.input, conn.element);
content_layout->addWidget(ui_objects.key_control, row_count, control_column);
connect(ui_objects.key_control, &NodeParamViewKeyframeControl::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItemBody::InputKeyframeEnableChanged);
connect(input, &NodeInput::KeyframeAdded, this, &NodeParamViewItemBody::InputAddedKeyframe);
connect(input, &NodeInput::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
connect(conn.input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItemBody::InputKeyframeEnableChanged);
connect(conn.input, &NodeInput::KeyframeAdded, this, &NodeParamViewItemBody::InputAddedKeyframe);
connect(conn.input, &NodeInput::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
}
input_ui_map_.insert(input, ui_objects);
input_ui_map_.insert(conn, ui_objects);
// Update "connected" label
if (input->is_connectable()) {
UpdateUIForEdgeConnection(input);
if (conn.input->IsConnectable()) {
for (int i=-1; i<conn.input->ArraySize(); i++) {
UpdateUIForEdgeConnection(conn.input, i);
}
}
row_count++;
// If the row count is an array, we put an extra body widget in the next row so we skip over it here
if (input->IsArray()) {
if (conn.input->IsArray()) {
row_count++;
}
}
@@ -336,10 +339,8 @@ void NodeParamViewItemBody::SetTime(const rational &time)
void NodeParamViewItemBody::Retranslate()
{
QMap<NodeInput*, InputUI>::const_iterator i;
for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
i.value().main_label->setText(tr("%1:").arg(i.key()->name()));
for (auto i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
i.value().main_label->setText(tr("%1:").arg(i.key().input->name()));
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
@@ -349,13 +350,11 @@ void NodeParamViewItemBody::Retranslate()
void NodeParamViewItemBody::SignalAllKeyframes()
{
QMap<NodeInput*, InputUI>::const_iterator i;
for (auto i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
NodeInput* input = i.key().input;
for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
NodeInput* input = i.key();
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
foreach (const NodeKeyframeTrack& track, input->GetKeyframeTracks(i.key().element)) {
foreach (NodeKeyframe* key, track) {
InputAddedKeyframeInternal(input, key);
}
}
@@ -366,30 +365,32 @@ void NodeParamViewItemBody::SignalAllKeyframes()
}
}
void NodeParamViewItemBody::EdgeChanged()
void NodeParamViewItemBody::EdgeChanged(Node* src, int element)
{
UpdateUIForEdgeConnection(static_cast<NodeInput*>(sender()));
Q_UNUSED(src)
UpdateUIForEdgeConnection(static_cast<NodeInput*>(sender()), element);
}
void NodeParamViewItemBody::UpdateUIForEdgeConnection(NodeInput *input)
void NodeParamViewItemBody::UpdateUIForEdgeConnection(NodeInput *input, int element)
{
// Show/hide bridge widgets
const InputUI& ui_objects = input_ui_map_[input];
const InputUI& ui_objects = input_ui_map_[{input, element}];
foreach (QWidget* w, ui_objects.widget_bridge->widgets()) {
w->setVisible(!input->is_connected());
w->setVisible(!input->IsConnected(element));
}
// Show/hide connection label
ui_objects.connected_label->setVisible(input->is_connected());
ui_objects.connected_label->setVisible(input->IsConnected(element));
}
void NodeParamViewItemBody::InputKeyframeEnableChanged(bool e)
void NodeParamViewItemBody::InputKeyframeEnableChanged(bool e, int element)
{
NodeInput* input = static_cast<NodeInput*>(sender());
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
foreach (const NodeKeyframeTrack& track, input->GetKeyframeTracks(element)) {
foreach (NodeKeyframe* key, track) {
if (e) {
// Add a keyframe item for each keyframe
InputAddedKeyframeInternal(input, key);
@@ -401,7 +402,7 @@ void NodeParamViewItemBody::InputKeyframeEnableChanged(bool e)
}
}
void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframePtr key)
void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframe* key)
{
// Get NodeInput that emitted this signal
NodeInput* input = static_cast<NodeInput*>(sender());
@@ -409,24 +410,11 @@ void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframePtr key)
InputAddedKeyframeInternal(input, key);
}
void NodeParamViewItemBody::LabelDoubleClicked()
{
QMap<NodeInput*, InputUI>::const_iterator iterator;
for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().main_label == sender()) {
emit InputDoubleClicked(iterator.key());
return;
}
}
}
void NodeParamViewItemBody::ConnectionClicked()
{
QMap<NodeInput*, InputUI>::const_iterator iterator;
for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
for (auto iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().connected_label == sender()) {
Node* connected = iterator.key()->get_connected_node();
Node* connected = iterator.key().input->parent();
if (connected) {
emit RequestSelectNode({connected});
@@ -437,7 +425,7 @@ void NodeParamViewItemBody::ConnectionClicked()
}
}
void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframePtr keyframe)
void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframe* keyframe)
{
// Find its row in the parameters
QLabel* lbl = input_ui_map_.value(input).main_label;
+11 -17
View File
@@ -72,7 +72,7 @@ private:
class NodeParamViewItemBody : public QWidget {
Q_OBJECT
public:
NodeParamViewItemBody(const QVector<NodeInput*>& inputs, QWidget* parent = nullptr);
NodeParamViewItemBody(const QVector<Node::InputConnection>& inputs, QWidget* parent = nullptr);
void SetTimeTarget(Node* target);
@@ -83,20 +83,18 @@ public:
void SignalAllKeyframes();
signals:
void KeyframeAdded(NodeKeyframePtr key, int y);
void KeyframeAdded(NodeKeyframe* key, int y);
void KeyframeRemoved(NodeKeyframePtr key);
void KeyframeRemoved(NodeKeyframe* key);
void RequestSetTime(const rational& time);
void InputDoubleClicked(NodeInput* input);
void RequestSelectNode(const QVector<Node*>& node);
private:
void UpdateUIForEdgeConnection(NodeInput* input);
void UpdateUIForEdgeConnection(NodeInput* input, int element);
void InputAddedKeyframeInternal(NodeInput* input, NodeKeyframePtr keyframe);
void InputAddedKeyframeInternal(NodeInput* input, NodeKeyframe* keyframe);
struct InputUI {
InputUI();
@@ -107,18 +105,16 @@ private:
NodeParamViewKeyframeControl* key_control;
};
QMap<NodeInput*, InputUI> input_ui_map_;
QHash<Node::InputConnection, InputUI> input_ui_map_;
QVector<NodeParamViewItemBody*> sub_bodies_;
private slots:
void EdgeChanged();
void EdgeChanged(Node *src, int element);
void InputKeyframeEnableChanged(bool e);
void InputKeyframeEnableChanged(bool e, int element);
void InputAddedKeyframe(NodeKeyframePtr key);
void LabelDoubleClicked();
void InputAddedKeyframe(NodeKeyframe* key);
void ConnectionClicked();
@@ -153,14 +149,12 @@ public slots:
void ToggleExpanded();
signals:
void KeyframeAdded(NodeKeyframePtr key, int y);
void KeyframeAdded(NodeKeyframe* key, int y);
void KeyframeRemoved(NodeKeyframePtr key);
void KeyframeRemoved(NodeKeyframe* key);
void RequestSetTime(const rational& time);
void InputDoubleClicked(NodeInput* input);
void RequestSelectNode(const QVector<Node*>& node);
void PinToggled(bool e);
@@ -67,16 +67,11 @@ NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWi
connect(enable_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged);
// Set defaults
SetInput(nullptr);
SetInput(nullptr, -1);
ShowButtonsFromKeyframeEnable(false);
}
NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const
{
return input_;
}
void NodeParamViewKeyframeControl::SetInput(NodeInput *input)
void NodeParamViewKeyframeControl::SetInput(NodeInput *input, int element)
{
if (input_ != nullptr) {
disconnect(input_, &NodeInput::KeyframeEnableChanged, enable_key_btn_, &QPushButton::setChecked);
@@ -85,10 +80,11 @@ void NodeParamViewKeyframeControl::SetInput(NodeInput *input)
}
input_ = input;
element_ = element;
SetButtonsEnabled(input_);
// Pick up keyframing value
enable_key_btn_->setChecked(input_ && input_->is_keyframing());
enable_key_btn_->setChecked(input_ && input_->IsKeyframing(element_));
// Update buttons
UpdateState();
@@ -126,12 +122,12 @@ void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e)
rational NodeParamViewKeyframeControl::GetCurrentTimeAsNodeTime() const
{
return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput);
return GetAdjustedTime(GetTimeTarget(), input_->parent(), time_, true);
}
rational NodeParamViewKeyframeControl::ConvertToViewerTime(const rational &r) const
{
return GetAdjustedTime(input_->parentNode(), GetTimeTarget(), r, NodeParam::kOutput);
return GetAdjustedTime(input_->parent(), GetTimeTarget(), r, false);
}
void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e)
@@ -145,30 +141,34 @@ void NodeParamViewKeyframeControl::ToggleKeyframe(bool e)
{
rational node_time = GetCurrentTimeAsNodeTime();
QList<NodeKeyframePtr> keys = input_->get_keyframe_at_time(node_time);
QVector<NodeKeyframe*> keys = input_->GetKeyframesAtTime(node_time, element_);
QUndoCommand* command = new QUndoCommand();
int nb_tracks = input_->GetNumberOfKeyframeTracks();
if (e && keys.isEmpty()) {
// Add a keyframe here (one for each track)
for (int i=0;i<input_->get_number_of_keyframe_tracks();i++) {
NodeKeyframePtr key = NodeKeyframe::Create(node_time,
input_->get_value_at_time_for_track(node_time, i),
input_->get_best_keyframe_type_for_time(node_time, i),
i);
for (int i=0;i<nb_tracks;i++) {
NodeKeyframe* key = new NodeKeyframe(node_time,
input_->GetValueAtTimeForTrack(node_time, i, element_),
input_->GetBestKeyframeTypeForTime(node_time, i, element_),
i,
element_);
new NodeParamInsertKeyframeCommand(input_, key, command);
}
} else if (!e && !keys.isEmpty()) {
// Remove all keyframes at this time
foreach (NodeKeyframePtr key, keys) {
new NodeParamRemoveKeyframeCommand(input_, key, command);
foreach (NodeKeyframe* key, keys) {
new NodeParamRemoveKeyframeCommand(key, command);
if (input_->keyframe_tracks().at(key->track()).size() == 1) {
if (input_->GetKeyframeTracks(key->track()).size() == 1) {
// If this was the last keyframe on this track, set the standard value to the value at this time too
new NodeParamSetStandardValueCommand(input_,
key->track(),
input_->get_value_at_time_for_track(node_time, key->track()),
element_,
input_->GetValueAtTimeForTrack(node_time, key->track(), element_),
command);
}
}
@@ -183,21 +183,21 @@ void NodeParamViewKeyframeControl::UpdateState()
return;
}
NodeKeyframePtr earliest_key = input_->get_earliest_keyframe();
NodeKeyframePtr latest_key = input_->get_latest_keyframe();
NodeKeyframe* earliest_key = input_->GetEarliestKeyframe(element_);
NodeKeyframe* latest_key = input_->GetLatestKeyframe(element_);
rational node_time = GetCurrentTimeAsNodeTime();
prev_key_btn_->setEnabled(earliest_key && node_time > earliest_key->time());
next_key_btn_->setEnabled(latest_key && node_time < latest_key->time());
toggle_key_btn_->setChecked(input_->has_keyframe_at_time(node_time));
toggle_key_btn_->setChecked(input_->HasKeyframeAtTime(node_time, element_));
}
void NodeParamViewKeyframeControl::GoToPreviousKey()
{
rational node_time = GetCurrentTimeAsNodeTime();
NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(node_time);
NodeKeyframe* previous_key = input_->GetClosestKeyframeBeforeTime(node_time, element_);
if (previous_key) {
rational key_time = ConvertToViewerTime(previous_key->time());
@@ -210,7 +210,7 @@ void NodeParamViewKeyframeControl::GoToNextKey()
{
rational node_time = GetCurrentTimeAsNodeTime();
NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(node_time);
NodeKeyframe* next_key = input_->GetClosestKeyframeAfterTime(node_time, element_);
if (next_key) {
rational key_time = ConvertToViewerTime(next_key->time());
@@ -221,7 +221,7 @@ void NodeParamViewKeyframeControl::GoToNextKey()
void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e)
{
if (e == input_->is_keyframing()) {
if (e == input_->IsKeyframing(element_)) {
// No-op
return;
}
@@ -233,13 +233,14 @@ void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e)
new NodeParamSetKeyframingCommand(input_, true, command);
// Create one keyframe across all tracks here
QVector<QVariant> key_vals = input_->get_split_standard_value();
const QVector<QVariant>& key_vals = input_->GetSplitStandardValue(element_);
for (int i=0;i<key_vals.size();i++) {
NodeKeyframePtr key = NodeKeyframe::Create(GetCurrentTimeAsNodeTime(),
key_vals.at(i),
NodeKeyframe::kDefaultType,
i);
NodeKeyframe* key = new NodeKeyframe(GetCurrentTimeAsNodeTime(),
key_vals.at(i),
NodeKeyframe::kDefaultType,
i,
element_);
new NodeParamInsertKeyframeCommand(input_, key, command);
}
@@ -251,18 +252,18 @@ void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e)
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
// Store value at this time, we'll set this as the persistent value later
QVector<QVariant> stored_vals = input_->get_split_values_at_time(GetCurrentTimeAsNodeTime());
const QVector<QVariant>& stored_vals = input_->GetSplitValuesAtTime(GetCurrentTimeAsNodeTime(), element_);
// Delete all keyframes
foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) {
foreach (const NodeKeyframeTrack& track, input_->GetKeyframeTracks(element_)) {
for (int i=track.size()-1;i>=0;i--) {
new NodeParamRemoveKeyframeCommand(input_, track.at(i), command);
new NodeParamRemoveKeyframeCommand(track.at(i), command);
}
}
// Update standard value
for (int i=0;i<stored_vals.size();i++) {
new NodeParamSetStandardValueCommand(input_, i, stored_vals.at(i), command);
new NodeParamSetStandardValueCommand(input_, i, element_, stored_vals.at(i), command);
}
// Disable keyframing
@@ -35,9 +35,17 @@ class NodeParamViewKeyframeControl : public QWidget, public TimeTargetObject
public:
NodeParamViewKeyframeControl(bool right_align = true, QWidget* parent = nullptr);
NodeInput* GetConnectedInput() const;
NodeInput* GetConnectedInput() const
{
return input_;
}
void SetInput(NodeInput* input);
int GetConnectedElement() const
{
return element_;
}
void SetInput(NodeInput* input, int element);
void SetTime(const rational& time);
@@ -59,6 +67,7 @@ private:
QPushButton* enable_key_btn_;
NodeInput* input_;
int element_;
rational time_;
+33 -40
View File
@@ -25,30 +25,31 @@
namespace olive {
NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(NodeInput *input, bool setting, QUndoCommand *parent) :
NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(NodeInput *input, int element, bool setting, QUndoCommand *parent) :
UndoCommand(parent),
input_(input),
setting_(setting)
setting_(setting),
element_(element)
{
Q_ASSERT(setting != input_->is_keyframing());
Q_ASSERT(setting != input_->IsKeyframing());
}
Project *NodeParamSetKeyframingCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(input_->parentNode()->parent())->project();
return static_cast<Sequence*>(input_->parent()->parent())->project();
}
void NodeParamSetKeyframingCommand::redo_internal()
{
input_->set_is_keyframing(setting_);
input_->SetIsKeyframing(setting_, element_);
}
void NodeParamSetKeyframingCommand::undo_internal()
{
input_->set_is_keyframing(!setting_);
input_->SetIsKeyframing(!setting_, element_);
}
NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent) :
NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframe* key, const QVariant& value, QUndoCommand* parent) :
UndoCommand(parent),
key_(key),
old_value_(key_->value()),
@@ -56,7 +57,7 @@ NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframeP
{
}
NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) :
NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframe* key, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
old_value_(old_value),
@@ -67,7 +68,7 @@ NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframeP
Project *NodeParamSetKeyframeValueCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(key_->parent()->parentNode()->parent())->project();
return static_cast<Sequence*>(key_->parent()->parent()->parent()->parent())->project();
}
void NodeParamSetKeyframeValueCommand::redo_internal()
@@ -80,63 +81,53 @@ void NodeParamSetKeyframeValueCommand::undo_internal()
key_->set_value(old_value_);
}
NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand* parent) :
NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframe* keyframe, QUndoCommand* parent) :
UndoCommand(parent),
input_(input),
keyframe_(keyframe),
done_(false)
{
}
NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, bool already_done, QUndoCommand *parent) :
UndoCommand(parent),
input_(input),
keyframe_(keyframe),
done_(already_done)
keyframe_(keyframe)
{
keyframe_->setParent(&memory_manager_);
}
Project *NodeParamInsertKeyframeCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(input_->parentNode()->parent())->project();
return static_cast<Sequence*>(input_->parent()->parent())->project();
}
void NodeParamInsertKeyframeCommand::redo_internal()
{
if (!done_) {
input_->insert_keyframe(keyframe_);
}
keyframe_->setParent(input_);
}
void NodeParamInsertKeyframeCommand::undo_internal()
{
input_->remove_keyframe(keyframe_);
done_ = false;
keyframe_->setParent(&memory_manager_);
}
NodeParamRemoveKeyframeCommand::NodeParamRemoveKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand *parent) :
NodeParamRemoveKeyframeCommand::NodeParamRemoveKeyframeCommand(NodeKeyframe* keyframe, QUndoCommand *parent) :
UndoCommand(parent),
input_(input),
input_(keyframe->parent()),
keyframe_(keyframe)
{
}
Project *NodeParamRemoveKeyframeCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(input_->parentNode()->parent())->project();
return static_cast<Sequence*>(input_->parent()->parent())->project();
}
void NodeParamRemoveKeyframeCommand::redo_internal()
{
input_->remove_keyframe(keyframe_);
// Removes from input
keyframe_->setParent(&memory_manager_);
}
void NodeParamRemoveKeyframeCommand::undo_internal()
{
input_->insert_keyframe(keyframe_);
keyframe_->setParent(input_);
}
NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational &time, QUndoCommand *parent) :
NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframe* key, const rational &time, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
old_time_(key->time()),
@@ -144,7 +135,7 @@ NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr
{
}
NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational &new_time, const rational &old_time, QUndoCommand *parent) :
NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframe* key, const rational &new_time, const rational &old_time, QUndoCommand *parent) :
UndoCommand(parent),
key_(key),
old_time_(old_time),
@@ -154,7 +145,7 @@ NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr
Project *NodeParamSetKeyframeTimeCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(key_->parent()->parentNode()->parent())->project();
return static_cast<Sequence*>(key_->parent()->parent()->parent())->project();
}
void NodeParamSetKeyframeTimeCommand::redo_internal()
@@ -167,18 +158,20 @@ void NodeParamSetKeyframeTimeCommand::undo_internal()
key_->set_time(old_time_);
}
NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, const QVariant &value, QUndoCommand *parent) :
NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, int element, const QVariant &value, QUndoCommand *parent) :
UndoCommand(parent),
input_(input),
element_(element),
track_(track),
old_value_(input_->get_standard_value()),
old_value_(input_->GetStandardValue(element_)),
new_value_(value)
{
}
NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) :
NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, int element, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) :
UndoCommand(parent),
input_(input),
element_(element),
track_(track),
old_value_(old_value),
new_value_(new_value)
@@ -187,17 +180,17 @@ NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *in
Project *NodeParamSetStandardValueCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(input_->parentNode()->parent())->project();
return static_cast<Sequence*>(input_->parent()->parent())->project();
}
void NodeParamSetStandardValueCommand::redo_internal()
{
input_->set_standard_value(new_value_, track_);
input_->SetStandardValueOnTrack(new_value_, track_, element_);
}
void NodeParamSetStandardValueCommand::undo_internal()
{
input_->set_standard_value(old_value_, track_);
input_->SetStandardValueOnTrack(old_value_, track_, element_);
}
}
+19 -15
View File
@@ -28,7 +28,7 @@ namespace olive {
class NodeParamSetKeyframingCommand : public UndoCommand {
public:
NodeParamSetKeyframingCommand(NodeInput* input, bool setting, QUndoCommand* parent = nullptr);
NodeParamSetKeyframingCommand(NodeInput* input, int element, bool setting, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -39,12 +39,13 @@ protected:
private:
NodeInput* input_;
bool setting_;
int element_;
};
class NodeParamInsertKeyframeCommand : public UndoCommand {
public:
NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr);
NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, bool already_done, QUndoCommand *parent = nullptr);
NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframe* keyframe, QUndoCommand *parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -55,15 +56,15 @@ protected:
private:
NodeInput* input_;
NodeKeyframePtr keyframe_;
NodeKeyframe* keyframe_;
bool done_;
QObject memory_manager_;
};
class NodeParamRemoveKeyframeCommand : public UndoCommand {
public:
NodeParamRemoveKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr);
NodeParamRemoveKeyframeCommand(NodeKeyframe* keyframe, QUndoCommand *parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -74,14 +75,16 @@ protected:
private:
NodeInput* input_;
NodeKeyframePtr keyframe_;
NodeKeyframe* keyframe_;
QObject memory_manager_;
};
class NodeParamSetKeyframeTimeCommand : public UndoCommand {
public:
NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational& time, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational& new_time, const rational& old_time, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeTimeCommand(NodeKeyframe* key, const rational& time, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeTimeCommand(NodeKeyframe* key, const rational& new_time, const rational& old_time, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -90,7 +93,7 @@ protected:
virtual void undo_internal() override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
rational old_time_;
rational new_time_;
@@ -99,8 +102,8 @@ private:
class NodeParamSetKeyframeValueCommand : public UndoCommand {
public:
NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeValueCommand(NodeKeyframe* key, const QVariant& value, QUndoCommand* parent = nullptr);
NodeParamSetKeyframeValueCommand(NodeKeyframe* key, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -109,7 +112,7 @@ protected:
virtual void undo_internal() override;
private:
NodeKeyframePtr key_;
NodeKeyframe* key_;
QVariant old_value_;
QVariant new_value_;
@@ -118,8 +121,8 @@ private:
class NodeParamSetStandardValueCommand : public UndoCommand {
public:
NodeParamSetStandardValueCommand(NodeInput* input, int track, const QVariant& value, QUndoCommand* parent = nullptr);
NodeParamSetStandardValueCommand(NodeInput* input, int track, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr);
NodeParamSetStandardValueCommand(NodeInput* input, int track, int element, const QVariant& value, QUndoCommand* parent = nullptr);
NodeParamSetStandardValueCommand(NodeInput* input, int track, int element, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -129,6 +132,7 @@ protected:
private:
NodeInput* input_;
int element_;
int track_;
QVariant old_value_;
@@ -40,9 +40,10 @@
namespace olive {
NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) :
NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, int element, QObject *parent) :
QObject(parent),
input_(input)
input_(input),
element_(element)
{
CreateWidgets();
@@ -69,30 +70,24 @@ void NodeParamViewWidgetBridge::CreateWidgets()
if (input_->IsArray()) {
NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(static_cast<NodeInputArray*>(input_));
NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(input_);
widgets_.append(w);
} else {
// We assume the first data type is the "primary" type
switch (input_->data_type()) {
switch (input_->GetDataType()) {
// None of these inputs have applicable UI widgets
case NodeParam::kNone:
case NodeParam::kAny:
case NodeParam::kTexture:
case NodeParam::kMatrix:
case NodeParam::kRational:
case NodeParam::kSamples:
case NodeParam::kDecimal:
case NodeParam::kNumber:
case NodeParam::kString:
case NodeParam::kBuffer:
case NodeParam::kVector:
case NodeParam::kShaderJob:
case NodeParam::kSampleJob:
case NodeParam::kGenerateJob:
case NodeValue::kNone:
case NodeValue::kTexture:
case NodeValue::kMatrix:
case NodeValue::kRational:
case NodeValue::kSamples:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
break;
case NodeParam::kInt:
case NodeValue::kInt:
{
IntegerSlider* slider = new IntegerSlider();
slider->SetDefaultValue(input_->GetDefaultValue());
@@ -101,27 +96,27 @@ void NodeParamViewWidgetBridge::CreateWidgets()
connect(slider, &IntegerSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kFloat:
case NodeValue::kFloat:
{
CreateSliders(1);
break;
}
case NodeParam::kVec2:
case NodeValue::kVec2:
{
CreateSliders(2);
break;
}
case NodeParam::kVec3:
case NodeValue::kVec3:
{
CreateSliders(3);
break;
}
case NodeParam::kVec4:
case NodeValue::kVec4:
{
CreateSliders(4);
break;
}
case NodeParam::kCombo:
case NodeValue::kCombo:
{
QComboBox* combobox = new QComboBox();
@@ -134,42 +129,42 @@ void NodeParamViewWidgetBridge::CreateWidgets()
connect(combobox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kFile:
case NodeValue::kFile:
// FIXME: File selector
break;
case NodeParam::kColor:
case NodeValue::kColor:
{
// NOTE: Very convoluted way to get back to the project's color manager
ColorButton* color_button = new ColorButton(static_cast<Sequence*>(input_->parentNode()->parent())->project()->color_manager());
ColorButton* color_button = new ColorButton(input_->parent()->parent()->project()->color_manager());
widgets_.append(color_button);
connect(color_button, &ColorButton::ColorChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kText:
case NodeValue::kText:
{
NodeParamViewRichText* line_edit = new NodeParamViewRichText();
widgets_.append(line_edit);
connect(line_edit, &NodeParamViewRichText::textEdited, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kBoolean:
case NodeValue::kBoolean:
{
QCheckBox* check_box = new QCheckBox();
widgets_.append(check_box);
connect(check_box, &QCheckBox::clicked, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kFont:
case NodeValue::kFont:
{
QFontComboBox* font_combobox = new QFontComboBox();
widgets_.append(font_combobox);
connect(font_combobox, &QFontComboBox::currentFontChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeParam::kFootage:
case NodeValue::kFootage:
{
FootageComboBox* footage_combobox = new FootageComboBox();
footage_combobox->SetRoot(static_cast<Sequence*>(input_->parentNode()->parent())->project()->root());
footage_combobox->SetRoot(input_->parent()->parent()->project()->root());
connect(footage_combobox, &FootageComboBox::FootageChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
@@ -207,22 +202,23 @@ void NodeParamViewWidgetBridge::SetInputValueInternal(const QVariant &value, int
{
rational node_time = GetCurrentTimeAsNodeTime();
if (input_->is_keyframing()) {
NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(node_time, track);
if (input_->IsKeyframing(element_)) {
NodeKeyframe* existing_key = input_->GetKeyframeAtTimeOnTrack(node_time, track, element_);
if (existing_key) {
new NodeParamSetKeyframeValueCommand(existing_key, value, command);
} else {
// No existing key, create a new one
NodeKeyframePtr new_key = NodeKeyframe::Create(node_time,
value,
input_->get_best_keyframe_type_for_time(node_time, track),
track);
NodeKeyframe* new_key = new NodeKeyframe(node_time,
value,
input_->GetBestKeyframeTypeForTime(node_time, track, element_),
track,
element_);
new NodeParamInsertKeyframeCommand(input_, new_key, command);
}
} else {
new NodeParamSetStandardValueCommand(input_, track, value, command);
new NodeParamSetStandardValueCommand(input_, track, element_, value, command);
}
}
@@ -257,24 +253,18 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant
void NodeParamViewWidgetBridge::WidgetCallback()
{
switch (input_->data_type()) {
switch (input_->GetDataType()) {
// None of these inputs have applicable UI widgets
case NodeParam::kNone:
case NodeParam::kAny:
case NodeParam::kTexture:
case NodeParam::kMatrix:
case NodeParam::kSamples:
case NodeParam::kRational:
case NodeParam::kDecimal:
case NodeParam::kNumber:
case NodeParam::kString:
case NodeParam::kVector:
case NodeParam::kBuffer:
case NodeParam::kShaderJob:
case NodeParam::kSampleJob:
case NodeParam::kGenerateJob:
case NodeValue::kNone:
case NodeValue::kTexture:
case NodeValue::kMatrix:
case NodeValue::kSamples:
case NodeValue::kRational:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
break;
case NodeParam::kInt:
case NodeValue::kInt:
{
// Widget is a IntegerSlider
IntegerSlider* slider = static_cast<IntegerSlider*>(sender());
@@ -284,7 +274,7 @@ void NodeParamViewWidgetBridge::WidgetCallback()
ProcessSlider(slider, QVariant::fromValue(slider->GetValue() - offset));
break;
}
case NodeParam::kFloat:
case NodeValue::kFloat:
{
// Widget is a FloatSlider
FloatSlider* slider = static_cast<FloatSlider*>(sender());
@@ -294,7 +284,7 @@ void NodeParamViewWidgetBridge::WidgetCallback()
ProcessSlider(slider, slider->GetValue() - offset);
break;
}
case NodeParam::kVec2:
case NodeValue::kVec2:
{
// Widget is a FloatSlider
FloatSlider* slider = static_cast<FloatSlider*>(sender());
@@ -304,7 +294,7 @@ void NodeParamViewWidgetBridge::WidgetCallback()
ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]);
break;
}
case NodeParam::kVec3:
case NodeValue::kVec3:
{
// Widget is a FloatSlider
FloatSlider* slider = static_cast<FloatSlider*>(sender());
@@ -314,7 +304,7 @@ void NodeParamViewWidgetBridge::WidgetCallback()
ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]);
break;
}
case NodeParam::kVec4:
case NodeValue::kVec4:
{
// Widget is a FloatSlider
FloatSlider* slider = static_cast<FloatSlider*>(sender());
@@ -324,10 +314,10 @@ void NodeParamViewWidgetBridge::WidgetCallback()
ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]);
break;
}
case NodeParam::kFile:
case NodeValue::kFile:
// FIXME: File selector
break;
case NodeParam::kColor:
case NodeValue::kColor:
{
// Sender is a ColorButton
ManagedColor c = static_cast<ColorButton*>(sender())->GetColor();
@@ -349,31 +339,31 @@ void NodeParamViewWidgetBridge::WidgetCallback()
Core::instance()->undo_stack()->pushIfHasChildren(command);
break;
}
case NodeParam::kText:
case NodeValue::kText:
{
// Sender is a NodeParamViewRichText
SetInputValue(static_cast<NodeParamViewRichText*>(sender())->text(), 0);
break;
}
case NodeParam::kBoolean:
case NodeValue::kBoolean:
{
// Widget is a QCheckBox
SetInputValue(static_cast<QCheckBox*>(sender())->isChecked(), 0);
break;
}
case NodeParam::kFont:
case NodeValue::kFont:
{
// Widget is a QFontComboBox
SetInputValue(static_cast<QFontComboBox*>(sender())->currentFont().family(), 0);
break;
}
case NodeParam::kFootage:
case NodeValue::kFootage:
{
// Widget is a FootageComboBox
SetInputValue(QVariant::fromValue(static_cast<FootageComboBox*>(sender())->SelectedFootage()), 0);
break;
}
case NodeParam::kCombo:
case NodeValue::kCombo:
{
// Widget is a QComboBox
QComboBox* cb = static_cast<QComboBox*>(widgets_.first());
@@ -412,49 +402,43 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
rational node_time = GetCurrentTimeAsNodeTime();
// We assume the first data type is the "primary" type
switch (input_->data_type()) {
switch (input_->GetDataType()) {
// None of these inputs have applicable UI widgets
case NodeParam::kNone:
case NodeParam::kAny:
case NodeParam::kTexture:
case NodeParam::kMatrix:
case NodeParam::kRational:
case NodeParam::kSamples:
case NodeParam::kDecimal:
case NodeParam::kNumber:
case NodeParam::kString:
case NodeParam::kBuffer:
case NodeParam::kShaderJob:
case NodeParam::kSampleJob:
case NodeParam::kGenerateJob:
case NodeParam::kVector:
case NodeValue::kNone:
case NodeValue::kTexture:
case NodeValue::kMatrix:
case NodeValue::kRational:
case NodeValue::kSamples:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
break;
case NodeParam::kInt:
case NodeValue::kInt:
{
int64_t offset = input_->property("offset").toLongLong();
static_cast<IntegerSlider*>(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toLongLong() + offset);
static_cast<IntegerSlider*>(widgets_.first())->SetValue(input_->GetValueAtTime(node_time, element_).toLongLong() + offset);
break;
}
case NodeParam::kFloat:
case NodeValue::kFloat:
{
double offset = input_->property("offset").toDouble();
static_cast<FloatSlider*>(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble() + offset);
static_cast<FloatSlider*>(widgets_.first())->SetValue(input_->GetValueAtTime(node_time, element_).toDouble() + offset);
break;
}
case NodeParam::kVec2:
case NodeValue::kVec2:
{
QVector2D vec2 = input_->get_value_at_time(node_time).value<QVector2D>();
QVector2D vec2 = input_->GetValueAtTime(node_time, -1).value<QVector2D>();
QVector2D offset = input_->property("offset").value<QVector2D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec2.x() + offset.x()));
static_cast<FloatSlider*>(widgets_.at(1))->SetValue(static_cast<double>(vec2.y() + offset.y()));
break;
}
case NodeParam::kVec3:
case NodeValue::kVec3:
{
QVector3D vec3 = input_->get_value_at_time(node_time).value<QVector3D>();
QVector3D vec3 = input_->GetValueAtTime(node_time, element_).value<QVector3D>();
QVector3D offset = input_->property("offset").value<QVector3D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec3.x() + offset.x()));
@@ -462,9 +446,9 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
static_cast<FloatSlider*>(widgets_.at(2))->SetValue(static_cast<double>(vec3.z() + offset.z()));
break;
}
case NodeParam::kVec4:
case NodeValue::kVec4:
{
QVector4D vec4 = input_->get_value_at_time(node_time).value<QVector4D>();
QVector4D vec4 = input_->GetValueAtTime(node_time, element_).value<QVector4D>();
QVector4D offset = input_->property("offset").value<QVector4D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec4.x() + offset.x()));
@@ -473,12 +457,12 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
static_cast<FloatSlider*>(widgets_.at(3))->SetValue(static_cast<double>(vec4.w() + offset.w()));
break;
}
case NodeParam::kFile:
case NodeValue::kFile:
// FIXME: File selector
break;
case NodeParam::kColor:
case NodeValue::kColor:
{
ManagedColor mc = input_->get_value_at_time(node_time).value<Color>();
ManagedColor mc = input_->GetValueAtTime(node_time, element_).value<Color>();
mc.set_color_input(input_->property("col_input").toString());
@@ -491,40 +475,40 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
static_cast<ColorButton*>(widgets_.first())->SetColor(mc);
break;
}
case NodeParam::kText:
case NodeValue::kText:
{
NodeParamViewRichText* e = static_cast<NodeParamViewRichText*>(widgets_.first());
e->setTextPreservingCursor(input_->get_value_at_time(node_time).toString());
e->setTextPreservingCursor(input_->GetValueAtTime(node_time, element_).toString());
break;
}
case NodeParam::kBoolean:
static_cast<QCheckBox*>(widgets_.first())->setChecked(input_->get_value_at_time(node_time).toBool());
case NodeValue::kBoolean:
static_cast<QCheckBox*>(widgets_.first())->setChecked(input_->GetValueAtTime(node_time, element_).toBool());
break;
case NodeParam::kFont:
case NodeValue::kFont:
{
QFontComboBox* fc = static_cast<QFontComboBox*>(widgets_.first());
fc->blockSignals(true);
fc->setCurrentFont(input_->get_value_at_time(node_time).toString());
fc->setCurrentFont(input_->GetValueAtTime(node_time, element_).toString());
fc->blockSignals(false);
break;
}
case NodeParam::kCombo:
case NodeValue::kCombo:
{
QComboBox* cb = static_cast<QComboBox*>(widgets_.first());
cb->blockSignals(true);
cb->setCurrentIndex(input_->get_value_at_time(node_time).toInt());
cb->setCurrentIndex(input_->GetValueAtTime(node_time, element_).toInt());
cb->blockSignals(false);
break;
}
case NodeParam::kFootage:
static_cast<FootageComboBox*>(widgets_.first())->SetFootage(Node::ValueToPtr<Stream>(input_->get_value_at_time(node_time)));
case NodeValue::kFootage:
static_cast<FootageComboBox*>(widgets_.first())->SetFootage(Node::ValueToPtr<Stream>(input_->GetValueAtTime(node_time, element_)));
break;
}
}
rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const
{
return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput);
return GetAdjustedTime(GetTimeTarget(), input_->parent(), time_, true);
}
void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range)
@@ -538,7 +522,7 @@ void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range)
void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVariant &value)
{
// Parameters for vectors only
if (input_->data_type() & NodeParam::kVector) {
if (NodeValue::type_is_vector(input_->GetDataType())) {
if (key == QStringLiteral("disablex")) {
static_cast<FloatSlider*>(widgets_.at(0))->setEnabled(!value.toBool());
} else if (key == QStringLiteral("disabley")) {
@@ -551,26 +535,26 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
}
// Parameters for integers, floats, and vectors
if (input_->data_type() & NodeParam::kNumber || input_->data_type() & NodeParam::kVector) {
if (NodeValue::type_is_numeric(input_->GetDataType()) || NodeValue::type_is_vector(input_->GetDataType())) {
if (key == QStringLiteral("min")) {
switch (input_->data_type()) {
case NodeParam::kInt:
switch (input_->GetDataType()) {
case NodeValue::kInt:
static_cast<IntegerSlider*>(widgets_.first())->SetMinimum(value.value<int64_t>());
break;
case NodeParam::kFloat:
case NodeValue::kFloat:
static_cast<FloatSlider*>(widgets_.first())->SetMinimum(value.toDouble());
break;
case NodeParam::kRational:
case NodeValue::kRational:
// FIXME: Rational doesn't have a UI implementation yet
break;
case NodeParam::kVec2:
case NodeValue::kVec2:
{
QVector2D min = value.value<QVector2D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMinimum(min.x());
static_cast<FloatSlider*>(widgets_.at(1))->SetMinimum(min.y());
break;
}
case NodeParam::kVec3:
case NodeValue::kVec3:
{
QVector3D min = value.value<QVector3D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMinimum(min.x());
@@ -578,7 +562,7 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
static_cast<FloatSlider*>(widgets_.at(2))->SetMinimum(min.z());
break;
}
case NodeParam::kVec4:
case NodeValue::kVec4:
{
QVector4D min = value.value<QVector4D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMinimum(min.x());
@@ -591,24 +575,24 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
break;
}
} else if (key == QStringLiteral("max")) {
switch (input_->data_type()) {
case NodeParam::kInt:
switch (input_->GetDataType()) {
case NodeValue::kInt:
static_cast<IntegerSlider*>(widgets_.first())->SetMaximum(value.value<int64_t>());
break;
case NodeParam::kFloat:
case NodeValue::kFloat:
static_cast<FloatSlider*>(widgets_.first())->SetMaximum(value.toDouble());
break;
case NodeParam::kRational:
case NodeValue::kRational:
// FIXME: Rational doesn't have a UI implementation yet
break;
case NodeParam::kVec2:
case NodeValue::kVec2:
{
QVector2D max = value.value<QVector2D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMaximum(max.x());
static_cast<FloatSlider*>(widgets_.at(1))->SetMaximum(max.y());
break;
}
case NodeParam::kVec3:
case NodeValue::kVec3:
{
QVector3D max = value.value<QVector3D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMaximum(max.x());
@@ -616,7 +600,7 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
static_cast<FloatSlider*>(widgets_.at(2))->SetMaximum(max.z());
break;
}
case NodeParam::kVec4:
case NodeValue::kVec4:
{
QVector4D max = value.value<QVector4D>();
static_cast<FloatSlider*>(widgets_.at(0))->SetMaximum(max.x());
@@ -634,7 +618,7 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
}
// ComboBox strings changing
if (input_->data_type() & NodeParam::kCombo) {
if (input_->GetDataType() & NodeValue::kCombo) {
QComboBox* cb = static_cast<QComboBox*>(widgets_.first());
int old_index = cb->currentIndex();
@@ -665,7 +649,7 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria
}
// Parameters for floats and vectors only
if (input_->data_type() & NodeParam::kFloat || input_->data_type() & NodeParam::kVector) {
if (input_->GetDataType() == NodeValue::kFloat || NodeValue::type_is_vector(input_->GetDataType())) {
if (key == QStringLiteral("view")) {
FloatSlider::DisplayType display_type;
@@ -41,7 +41,7 @@ class NodeParamViewWidgetBridge : public QObject, public TimeTargetObject
{
Q_OBJECT
public:
NodeParamViewWidgetBridge(NodeInput* input, QObject* parent);
NodeParamViewWidgetBridge(NodeInput* input, int element, QObject* parent);
void SetTime(const rational& time);
@@ -64,6 +64,8 @@ private:
NodeInput* input_;
int element_;
QList<QWidget*> widgets_;
rational time_;
+4 -5
View File
@@ -23,7 +23,6 @@
#include <QCheckBox>
#include <QHeaderView>
#include "node/param.h"
#include "nodetabletraverser.h"
namespace olive {
@@ -130,7 +129,7 @@ void NodeTableView::SetTime(const rational &time)
QTreeWidgetItem* sub_item = input_item->child(j);
// Set data type name
sub_item->setText(0, NodeParam::GetPrettyDataTypeName(value.type()));
sub_item->setText(0, NodeValue::GetPrettyDataTypeName(value.type()));
// Determine source
QString source_name;
@@ -142,7 +141,7 @@ void NodeTableView::SetTime(const rational &time)
sub_item->setText(1, source_name);
switch (value.type()) {
case NodeParam::kTexture:
case NodeValue::kTexture:
{
// NodeTableTraverser puts video params in here
for (int k=0;k<VideoParams::kRGBAChannelCount;k++) {
@@ -152,9 +151,9 @@ void NodeTableView::SetTime(const rational &time)
}
default:
{
QVector<QVariant> split_values = input->split_normal_value_into_track_values(value.data());
QVector<QVariant> split_values = NodeValue::split_normal_value_into_track_values(input->GetDataType(), value.data());
for (int k=0;k<split_values.size();k++) {
sub_item->setText(2 + k, NodeInput::ValueToString(value.type(), split_values.at(k), true));
sub_item->setText(2 + k, NodeValue::ValueToString(value.type(), split_values.at(k), true));
}
}
}
+2 -3
View File
@@ -34,9 +34,8 @@ void NodeTreeView::SetNodes(const QVector<Node *> &nodes)
node_item->setData(0, kItemType, kItemTypeNode);
node_item->setData(0, kItemPointer, reinterpret_cast<quintptr>(n));
QVector<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
if (only_show_keyframable_ && !i->is_keyframable()) {
foreach (NodeInput* i, n->inputs()) {
if (only_show_keyframable_ && !i->IsKeyframable()) {
continue;
}
+2 -11
View File
@@ -16,18 +16,9 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/nodeview/nodeview.h
widget/nodeview/nodeview.cpp
widget/nodeview/nodeviewcommon.h
widget/nodeview/nodeviewedge.h
widget/nodeview/nodeviewedge.cpp
widget/nodeview/nodeviewitem.h
widget/nodeview/nodeviewitem.cpp
widget/nodeview/nodeviewitemwidgetproxy.h
widget/nodeview/nodeviewitemwidgetproxy.cpp
widget/nodeview/nodeviewscene.h
widget/nodeview/nodeviewscene.cpp
widget/nodeview/nodeviewundo.h
widget/nodeview/nodeview.h
widget/nodeview/nodeviewundo.cpp
widget/nodeview/nodeviewundo.h
PARENT_SCOPE
)
+3 -876
View File
@@ -20,887 +20,14 @@
#include "nodeview.h"
#include <QInputDialog>
#include <QMouseEvent>
#include "core.h"
#include "nodeviewundo.h"
#include "node/factory.h"
#include "widget/menu/menushared.h"
#define super HandMovableView
namespace olive {
NodeView::NodeView(QWidget *parent) :
NodeView::NodeView(QWidget* parent) :
HandMovableView(parent),
graph_(nullptr),
drop_edge_(nullptr),
filter_mode_(kFilterShowSelectedBlocks),
scale_(1.0)
graph_(nullptr)
{
setScene(&scene_);
SetDefaultDragMode(RubberBandDrag);
setContextMenuPolicy(Qt::CustomContextMenu);
setMouseTracking(true);
setRenderHint(QPainter::Antialiasing);
setViewportUpdateMode(FullViewportUpdate);
connect(&scene_, &QGraphicsScene::changed, this, &NodeView::ItemsChanged);
connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu);
ConnectSelectionChangedSignal();
SetFlowDirection(NodeViewCommon::kTopToBottom);
// Set massive scene rect and hide the scrollbars to create an "infinite space" effect
scene_.setSceneRect(-1000000, -1000000, 2000000, 2000000);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
select_blocks_internal_timer_.setSingleShot(true);
select_blocks_internal_timer_.setInterval(100);
connect(&select_blocks_internal_timer_, &QTimer::timeout, this, &NodeView::SelectBlocksInternal);
}
NodeView::~NodeView()
{
// Unset the current graph
SetGraph(nullptr);
}
void NodeView::SetGraph(NodeGraph *graph)
{
if (graph_ == graph) {
return;
}
if (graph_ != nullptr) {
disconnect(graph_, &NodeGraph::NodeAdded, &scene_, &NodeViewScene::AddNode);
disconnect(graph_, &NodeGraph::NodeRemoved, &scene_, &NodeViewScene::RemoveNode);
disconnect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::GraphNodeRemoved);
disconnect(graph_, &NodeGraph::EdgeAdded, this, &NodeView::GraphEdgeAdded);
disconnect(graph_, &NodeGraph::EdgeRemoved, this, &NodeView::GraphEdgeRemoved);
}
// Clear the scene of all UI objects
scene_.clear();
// Set reference to the graph
graph_ = graph;
scene_.SetGraph(graph_);
// If the graph is valid, add UI objects for each of its Nodes
if (graph_ != nullptr) {
connect(graph_, &NodeGraph::NodeAdded, &scene_, &NodeViewScene::AddNode);
connect(graph_, &NodeGraph::NodeRemoved, &scene_, &NodeViewScene::RemoveNode);
connect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::GraphNodeRemoved);
connect(graph_, &NodeGraph::EdgeAdded, this, &NodeView::GraphEdgeAdded);
connect(graph_, &NodeGraph::EdgeRemoved, this, &NodeView::GraphEdgeRemoved);
foreach (Node* n, graph_->nodes()) {
scene_.AddNode(n);
}
ValidateFilter();
}
}
void NodeView::DeleteSelected()
{
if (!graph_) {
return;
}
QUndoCommand* command = new QUndoCommand();
{
QVector<NodeEdge*> selected_edges = scene_.GetSelectedEdges();
foreach (NodeEdge* edge, selected_edges) {
new NodeEdgeRemoveCommand(edge->output(), edge->input(), command);
}
}
{
QVector<Node*> selected_nodes = scene_.GetSelectedNodes();
// Ensure no nodes are "undeletable"
for (int i=0;i<selected_nodes.size();i++) {
if (!selected_nodes.at(i)->CanBeDeleted()) {
selected_nodes.removeAt(i);
i--;
}
}
if (!selected_nodes.isEmpty()) {
new NodeRemoveCommand(graph_, selected_nodes, command);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void NodeView::SelectAll()
{
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
scene_.SelectAll();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::DeselectAll()
{
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
scene_.DeselectAll();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::Select(const QVector<Node *> &nodes)
{
if (!graph_) {
return;
}
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
scene_.DeselectAll();
foreach (Node* n, nodes) {
NodeViewItem* item = scene_.NodeToUIObject(n);
item->setSelected(true);
}
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::SelectWithDependencies(QVector<Node *> nodes)
{
if (!graph_) {
return;
}
int original_length = nodes.size();
for (int i=0;i<original_length;i++) {
nodes.append(nodes.at(i)->GetDependencies());
}
Select(nodes);
}
void NodeView::SelectBlocks(const QVector<Block *> &blocks)
{
if (!graph_) {
return;
}
selected_blocks_.append(blocks);
QueueSelectBlocksInternal();
}
void NodeView::DeselectBlocks(const QVector<Block *> &blocks)
{
if (!graph_) {
return;
}
// Remove temporary associations
foreach (Block* b, selected_blocks_) {
if (!blocks.contains(b)) {
temporary_association_map_.remove(b);
}
}
// Remove blocks from selected array
foreach (Block* b, blocks) {
selected_blocks_.removeOne(b);
}
QueueSelectBlocksInternal();
}
void NodeView::CopySelected(bool cut)
{
if (!graph_) {
return;
}
QVector<Node*> selected = scene_.GetSelectedNodes();
if (selected.isEmpty()) {
return;
}
CopyNodesToClipboard(selected);
if (cut) {
DeleteSelected();
}
}
void NodeView::Paste()
{
if (!graph_) {
return;
}
QUndoCommand* command = new QUndoCommand();
QVector<Node*> pasted_nodes = PasteNodesFromClipboard(static_cast<Sequence*>(graph_), command);
Core::instance()->undo_stack()->pushIfHasChildren(command);
if (!pasted_nodes.isEmpty()) {
foreach (Node* n, pasted_nodes) {
AssociateNodeWithSelectedBlocks(n);
}
AttachNodesToCursor(pasted_nodes);
}
}
void NodeView::Duplicate()
{
if (!graph_) {
return;
}
QVector<Node*> selected = scene_.GetSelectedNodes();
if (selected.isEmpty()) {
return;
}
QUndoCommand* command = new QUndoCommand();
QVector<Node*> duplicated_nodes = Node::CopyDependencyGraph(selected, command);
Core::instance()->undo_stack()->pushIfHasChildren(command);
AttachNodesToCursor(duplicated_nodes);
}
void NodeView::ItemsChanged()
{
QHash<NodeEdge *, NodeViewEdge *>::const_iterator i;
for (i=scene_.edge_map().constBegin(); i!=scene_.edge_map().constEnd(); i++) {
i.value()->Adjust();
}
}
void NodeView::keyPressEvent(QKeyEvent *event)
{
super::keyPressEvent(event);
if (event->key() == Qt::Key_Escape && !attached_items_.isEmpty()) {
DetachItemsFromCursor();
// We undo the last action which SHOULD be adding the node
// FIXME: Possible danger of this not being the case?
Core::instance()->undo_stack()->undo();
}
}
void NodeView::mousePressEvent(QMouseEvent *event)
{
if (HandPress(event)) return;
if (event->button() == Qt::RightButton) {
// Qt doesn't do this by default for some reason
if (!(event->modifiers() & Qt::ShiftModifier)) {
scene_.clearSelection();
}
// If there's an item here, select it
QGraphicsItem* item = itemAt(event->pos());
if (item) {
item->setSelected(true);
}
}
super::mousePressEvent(event);
}
void NodeView::mouseMoveEvent(QMouseEvent *event)
{
if (HandMove(event)) return;
super::mouseMoveEvent(event);
if (!attached_items_.isEmpty()) {
MoveAttachedNodesToCursor(event->pos());
// See if the user clicked on an edge (only when dropping single nodes)
if (attached_items_.size() == 1) {
Node* attached_node = attached_items_.first().item->GetNode();
QRect edge_detect_rect(event->pos(), event->pos());
int edge_detect_radius = fontMetrics().height();
edge_detect_rect.adjust(-edge_detect_radius, -edge_detect_radius, edge_detect_radius, edge_detect_radius);
QList<QGraphicsItem*> items = this->items(edge_detect_rect);
NodeViewEdge* new_drop_edge = nullptr;
// See if there is an edge here
foreach (QGraphicsItem* item, items) {
new_drop_edge = dynamic_cast<NodeViewEdge*>(item);
if (new_drop_edge) {
drop_input_ = nullptr;
foreach (NodeParam* param, attached_node->parameters()) {
if (param->type() == NodeParam::kInput) {
NodeInput* input = static_cast<NodeInput*>(param);
if (input->is_connectable()) {
if (input->data_type() & new_drop_edge->edge()->input()->data_type()) {
drop_input_ = input;
break;
} else if (!drop_input_) {
drop_input_ = input;
}
}
}
}
if (drop_input_) {
break;
} else {
new_drop_edge = nullptr;
}
}
}
if (drop_edge_ != new_drop_edge) {
if (drop_edge_) {
drop_edge_->SetHighlighted(false);
}
drop_edge_ = new_drop_edge;
if (drop_edge_) {
drop_edge_->SetHighlighted(true);
}
}
}
}
}
void NodeView::mouseReleaseEvent(QMouseEvent *event)
{
if (HandRelease(event)) return;
if (!attached_items_.isEmpty()) {
if (attached_items_.size() == 1) {
Node* dropping_node = attached_items_.first().item->GetNode();
if (drop_edge_) {
NodeEdgePtr old_edge = drop_edge_->edge();
// We have everything we need to place the node in between
QUndoCommand* command = new QUndoCommand();
// Remove old edge
new NodeEdgeRemoveCommand(old_edge, command);
// Place new edges
new NodeEdgeAddCommand(old_edge->output(), drop_input_, command);
new NodeEdgeAddCommand(dropping_node->output(), old_edge->input(), command);
Core::instance()->undo_stack()->push(command);
}
drop_edge_ = nullptr;
}
DetachItemsFromCursor();
}
super::mouseReleaseEvent(event);
}
void NodeView::wheelEvent(QWheelEvent *event)
{
if (event->modifiers() & Qt::ControlModifier) {
// FIXME: Hardcoded divider (0.001)
qreal multiplier = 1.0 + (static_cast<qreal>(event->angleDelta().x() + event->angleDelta().y()) * 0.001);
double test_scale = scale_ * multiplier;
if (test_scale > 0.1) {
scale(multiplier, multiplier);
scale_ = test_scale;
}
} else {
QWidget::wheelEvent(event);
}
}
void NodeView::SceneSelectionChangedSlot()
{
QVector<Node*> current_selection = scene_.GetSelectedNodes();
QVector<Node*> selected;
QVector<Node*> deselected;
// Determine which nodes are newly selected
if (selected_nodes_.isEmpty()) {
// All nodes in the current selection have just been selected
selected = current_selection;
} else {
foreach (Node* n, current_selection) {
if (!selected_nodes_.contains(n)) {
selected.append(n);
}
}
}
// Determine which nodes are newly deselected
if (current_selection.isEmpty()) {
// All nodes that were selected have been deselected
deselected = selected_nodes_;
} else {
foreach (Node* n, selected_nodes_) {
if (!current_selection.contains(n)) {
deselected.append(n);
}
}
}
selected_nodes_ = current_selection;
if (!selected.isEmpty()) {
emit NodesSelected(selected);
}
if (!deselected.isEmpty()) {
emit NodesDeselected(deselected);
}
}
void NodeView::ShowContextMenu(const QPoint &pos)
{
if (!graph_) {
return;
}
Menu m;
MenuShared::instance()->AddItemsForEditMenu(&m, false);
m.addSeparator();
QVector<NodeViewItem*> selected = scene_.GetSelectedItems();
if (itemAt(pos) && !selected.isEmpty()) {
// Label node action
QAction* label_action = m.addAction(tr("Label"));
connect(label_action, &QAction::triggered, this, [this](){
Core::instance()->LabelNodes(scene_.GetSelectedNodes());
});
m.addSeparator();
// Auto-position action
QAction* autopos = m.addAction(tr("Auto-Position"));
connect(autopos, &QAction::triggered, this, &NodeView::AutoPositionDescendents);
} else {
QAction* curved_action = m.addAction(tr("Smooth Edges"));
curved_action->setCheckable(true);
curved_action->setChecked(scene_.GetEdgesAreCurved());
connect(curved_action, &QAction::triggered, &scene_, &NodeViewScene::SetEdgesAreCurved);
m.addSeparator();
Menu* filter_menu = new Menu(tr("Filter"), &m);
m.addMenu(filter_menu);
filter_menu->AddActionWithData(tr("Show All"),
kFilterShowAll,
filter_mode_);
filter_menu->AddActionWithData(tr("Show Selected Blocks Only"),
kFilterShowSelectedBlocks,
filter_mode_);
connect(filter_menu, &Menu::triggered, this, &NodeView::ContextMenuFilterChanged);
Menu* direction_menu = new Menu(tr("Direction"), &m);
m.addMenu(direction_menu);
direction_menu->AddActionWithData(tr("Top to Bottom"),
NodeViewCommon::kTopToBottom,
scene_.GetFlowDirection());
direction_menu->AddActionWithData(tr("Bottom to Top"),
NodeViewCommon::kBottomToTop,
scene_.GetFlowDirection());
direction_menu->AddActionWithData(tr("Left to Right"),
NodeViewCommon::kLeftToRight,
scene_.GetFlowDirection());
direction_menu->AddActionWithData(tr("Right to Left"),
NodeViewCommon::kRightToLeft,
scene_.GetFlowDirection());
connect(direction_menu, &Menu::triggered, this, &NodeView::ContextMenuSetDirection);
m.addSeparator();
Menu* add_menu = NodeFactory::CreateMenu(&m);
add_menu->setTitle(tr("Add"));
connect(add_menu, &Menu::triggered, this, &NodeView::CreateNodeSlot);
m.addMenu(add_menu);
}
m.exec(mapToGlobal(pos));
}
void NodeView::CreateNodeSlot(QAction *action)
{
Node* new_node = NodeFactory::CreateFromMenuAction(action);
if (new_node) {
// Associate this new node with these blocks (allows it to be visible with them even while it
// isn't connected to anything)
AssociateNodeWithSelectedBlocks(new_node);
Core::instance()->undo_stack()->push(new NodeAddCommand(graph_, new_node));
NodeViewItem* item = scene_.NodeToUIObject(new_node);
AttachItemsToCursor({item});
}
}
void NodeView::ContextMenuSetDirection(QAction *action)
{
SetFlowDirection(static_cast<NodeViewCommon::FlowDirection>(action->data().toInt()));
}
void NodeView::AutoPositionDescendents()
{
QVector<Node*> selected = scene_.GetSelectedNodes();
foreach (Node* n, selected) {
scene_.ReorganizeFrom(n);
}
}
void NodeView::ContextMenuFilterChanged(QAction *action)
{
FilterMode filter = static_cast<FilterMode>(action->data().toInt());
if (filter_mode_ != filter) {
filter_mode_ = filter;
if (filter == kFilterShowAll) {
// Un-hide all blocks
foreach (NodeViewItem* item, scene_.item_map()) {
item->setVisible(true);
}
foreach (NodeViewEdge* edge, scene_.edge_map()) {
edge->setVisible(true);
}
}
ValidateFilter();
}
}
void NodeView::AttachNodesToCursor(const QVector<Node *> &nodes)
{
QVector<NodeViewItem*> items(nodes.size());
for (int i=0; i<nodes.size(); i++) {
items[i] = scene_.NodeToUIObject(nodes.at(i));
}
AttachItemsToCursor(items);
}
void NodeView::AttachItemsToCursor(const QVector<NodeViewItem*>& items)
{
DetachItemsFromCursor();
if (!items.isEmpty()) {
foreach (NodeViewItem* i, items) {
attached_items_.append({i, i->pos() - items.first()->pos()});
}
setMouseTracking(true);
MoveAttachedNodesToCursor(mapFromGlobal(QCursor::pos()));
}
}
void NodeView::DetachItemsFromCursor()
{
attached_items_.clear();
setMouseTracking(false);
}
void NodeView::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
scene_.SetFlowDirection(dir);
}
void NodeView::MoveAttachedNodesToCursor(const QPoint& p)
{
QPointF item_pos = mapToScene(p);
foreach (const AttachedItem& i, attached_items_) {
i.item->setPos(item_pos + i.original_pos);
}
}
void NodeView::ConnectSelectionChangedSignal()
{
connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
}
void NodeView::DisconnectSelectionChangedSignal()
{
disconnect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
}
void NodeView::UpdateBlockFilter()
{
// Hide all nodes
foreach (NodeViewItem* item, scene_.item_map()) {
item->setVisible(false);
}
bool first = true;
QPointF last_bottom_right;
QVector<Node*> currently_visible;
foreach (Block* b, selected_blocks_) {
// Auto-position this node's dependencies
scene_.ReorganizeFrom(b);
// Start calculating the bounding rect of this node's deps
QPointF node_pos = b->GetPosition();
QRectF anchor(node_pos, node_pos);
QVector<Node*> deps = b->GetDependencies();
foreach (Node* d, deps) {
QPointF dep_pos = d->GetPosition();
anchor.setLeft(qMin(anchor.left(), dep_pos.x()));
anchor.setRight(qMax(anchor.right(), dep_pos.x()));
anchor.setTop(qMin(anchor.top(), dep_pos.y()));
anchor.setBottom(qMax(anchor.bottom(), dep_pos.y()));
NodeViewItem* item = scene_.NodeToUIObject(d);
if (item) {
item->setVisible(true);
}
}
// Shift the bounding rect in relation to the other bounding rects
if (first) {
first = false;
} else {
QPointF desired_anchor_pos = last_bottom_right + QPointF(0, 2);
QPointF necessary_movement = anchor.topRight() - desired_anchor_pos;
// Calculate the bottom right from which we'll anchor the next rect
last_bottom_right = anchor.bottomRight() - necessary_movement;
b->SetPosition(b->GetPosition() - necessary_movement);
foreach (Node* d, deps) {
d->SetPosition(d->GetPosition() - necessary_movement);
}
}
// Now that we're done calculating the bounding rect, add this block...
deps.append(b);
// ...then add its associations
deps.append(temporary_association_map_[b]);
for (auto i=association_map_.begin(); i!=association_map_.end(); i++) {
if (i.value().contains(b)) {
deps.append(i.key());
}
}
// And make sure all nodes are shown
foreach (Node* n, deps) {
NodeViewItem* item = scene_.NodeToUIObject(n);
if (item) {
item->setVisible(true);
}
}
// And lastly, add them all to our currently visible list
currently_visible.append(deps);
}
// Show only edges between those dependencies
foreach (NodeViewEdge* edge, scene_.edge_map()) {
edge->setVisible((currently_visible.contains(edge->edge()->input_node())
&& currently_visible.contains(edge->edge()->output_node())));
}
}
void NodeView::AssociateNodeWithSelectedBlocks(Node *n)
{
association_map_.insert(n, selected_blocks_);
connect(n, &Node::destroyed, this, &NodeView::AssociatedNodeDestroyed, Qt::DirectConnection);
}
void NodeView::DisassociateNode(Node *n, bool remove_from_map)
{
if (remove_from_map) {
association_map_.remove(n);
}
disconnect(n, &Node::destroyed, this, &NodeView::AssociatedNodeDestroyed);
}
void NodeView::QueueSelectBlocksInternal()
{
select_blocks_internal_timer_.stop();
select_blocks_internal_timer_.start();
}
void NodeView::SelectBlocksInternal()
{
// Block scene signals while our selection is changing a lot
DisconnectSelectionChangedSignal();
if (filter_mode_ == kFilterShowSelectedBlocks) {
UpdateBlockFilter();
}
QVector<Node*> nodes;
nodes.reserve(selected_blocks_.size());
foreach (Block* b, selected_blocks_) {
nodes.append(b);
nodes.append(b->GetDependencies());
}
SelectWithDependencies(nodes);
// Stop blocking signals and send a change signal now that all of our processing is done
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
if (!selected_blocks_.isEmpty()) {
NodeViewItem* item = scene_.NodeToUIObject(selected_blocks_.first());
if (item) {
centerOn(item);
}
}
}
void NodeView::ValidateFilter()
{
// Force auto-positioning
switch (filter_mode_) {
case kFilterShowAll:
// NOTE: Assumes Sequence
scene_.ReorganizeFrom(static_cast<Sequence*>(graph_)->viewer_output());
break;
case kFilterShowSelectedBlocks:
UpdateBlockFilter();
break;
}
}
void NodeView::AssociatedNodeDestroyed()
{
DisassociateNode(static_cast<Node*>(sender()), true);
}
void NodeView::GraphNodeRemoved(Node *node)
{
if (selected_blocks_.contains(static_cast<Block*>(node))) {
DeselectBlocks({static_cast<Block*>(node)});
}
}
void NodeView::GraphEdgeAdded(NodeEdgePtr edge)
{
Node* input_node = edge->input()->parentNode();
if (input_node->OutputsTo(static_cast<Sequence*>(graph_)->viewer_output(), true)) {
auto i = association_map_.begin();
while (i != association_map_.end()) {
if (input_node->InputsFrom(i.key(), true)) {
i = association_map_.erase(i);
} else {
i++;
}
}
}
scene_.AddEdge(edge);
ValidateFilter();
}
void NodeView::GraphEdgeRemoved(NodeEdgePtr edge)
{
scene_.RemoveEdge(edge);
Node* output_node = edge->output_node();
// Check if this disconnected node still connects to a selected block, in which case do nothing
foreach (Block* b, selected_blocks_) {
if (output_node->OutputsTo(b, true)) {
return;
}
}
QVector<Node*> disconnected_nodes;
disconnected_nodes.append(output_node);
disconnected_nodes.append(output_node->GetDependencies());
if (output_node->OutputsTo(static_cast<Sequence*>(graph_)->viewer_output(), true)) {
// Check if this disconnected node still has a path to the viewer somewhere else
foreach (Block* b, selected_blocks_) {
QVector<Node*>& temp_assocs = temporary_association_map_[b];
temp_assocs.append(disconnected_nodes);
}
} else {
// Otherwise, we must associate these nodes
foreach (Node* n, disconnected_nodes) {
AssociateNodeWithSelectedBlocks(n);
}
}
}
}
+11 -136
View File
@@ -22,172 +22,47 @@
#define NODEVIEW_H
#include <QGraphicsView>
#include <QTimer>
#include "node/graph.h"
#include "node/nodecopypaste.h"
#include "nodeviewscene.h"
#include "widget/handmovableview/handmovableview.h"
namespace olive {
/**
* @brief A widget for viewing and editing node graphs
*
* This widget takes a NodeGraph object and constructs a QGraphicsScene representing its data, viewing and allowing
* the user to make modifications to it.
*/
class NodeView : public HandMovableView, public NodeCopyPasteService
{
Q_OBJECT
public:
NodeView(QWidget* parent);
virtual ~NodeView() override;
/**
* @brief Sets the graph to view
*/
void SetGraph(NodeGraph* graph);
void SetGraph(NodeGraph* graph){}
/**
* @brief Delete selected nodes from graph (user-friendly/undoable)
*/
void DeleteSelected();
void DeleteSelected(){}
void SelectAll();
void DeselectAll();
void SelectAll(){}
void DeselectAll(){}
void Select(const QVector<Node*>& nodes);
void SelectWithDependencies(QVector<Node *> nodes);
void Select(const QVector<Node*>& nodes){}
void SelectWithDependencies(QVector<Node *> nodes){}
void CopySelected(bool cut);
void Paste();
void CopySelected(bool cut){}
void Paste(){}
void Duplicate();
void Duplicate(){}
void SelectBlocks(const QVector<Block*>& blocks);
void SelectBlocks(const QVector<Block*>& blocks){}
void DeselectBlocks(const QVector<Block*>& blocks);
signals:
void NodesSelected(const QVector<Node*>& nodes);
void NodesDeselected(const QVector<Node*>& nodes);
protected:
virtual void keyPressEvent(QKeyEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void wheelEvent(QWheelEvent* event) override;
void DeselectBlocks(const QVector<Block*>& blocks){}
private:
void AttachNodesToCursor(const QVector<Node *> &nodes);
void AttachItemsToCursor(const QVector<NodeViewItem *> &items);
void DetachItemsFromCursor();
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
void MoveAttachedNodesToCursor(const QPoint &p);
void ConnectSelectionChangedSignal();
void DisconnectSelectionChangedSignal();
void UpdateBlockFilter();
void AssociateNodeWithSelectedBlocks(Node* n);
void DisassociateNode(Node* n, bool remove_from_map);
void QueueSelectBlocksInternal();
QTimer select_blocks_internal_timer_;
NodeGraph* graph_;
struct AttachedItem {
NodeViewItem* item;
QPointF original_pos;
};
QList<AttachedItem> attached_items_;
NodeViewEdge* drop_edge_;
NodeInput* drop_input_;
NodeViewScene scene_;
QVector<Node*> selected_nodes_;
QVector<Block*> selected_blocks_;
QHash<Node*, QVector<Block*> > association_map_;
QHash<Block*, QVector<Node*> > temporary_association_map_;
enum FilterMode {
kFilterShowAll,
kFilterShowSelectedBlocks
};
FilterMode filter_mode_;
double scale_;
private slots:
void ValidateFilter();
void AssociatedNodeDestroyed();
void GraphNodeRemoved(Node* node);
void GraphEdgeAdded(NodeEdgePtr edge);
void GraphEdgeRemoved(NodeEdgePtr edge);
/**
* @brief Internal function triggered when any change is signalled from the QGraphicsScene
*
* Current primary function is to inform all NodeViewEdges to re-adjust in case any Nodes have moved
*/
void ItemsChanged();
/**
* @brief Receiver for when the scene's selected items change
*/
void SceneSelectionChangedSlot();
/**
* @brief Receiver for when the user right clicks (or otherwise requests a context menu)
*/
void ShowContextMenu(const QPoint &pos);
/**
* @brief Receiver for when the user requests a new node from the add menu
*/
void CreateNodeSlot(QAction* action);
/**
* @brief Receiver for setting the direction from the context menu
*/
void ContextMenuSetDirection(QAction* action);
/**
* @brief Receiver for auto-position descendents menu action
*/
void AutoPositionDescendents();
/**
* @brief Receiver for the user changing the filter
*/
void ContextMenuFilterChanged(QAction* action);
void SelectBlocksInternal();
};
}
-58
View File
@@ -1,58 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEVIEWCOMMON_H
#define NODEVIEWCOMMON_H
#include <QtGlobal>
#include "common/define.h"
namespace olive {
class NodeViewCommon {
public:
enum FlowDirection {
kTopToBottom,
kBottomToTop,
kLeftToRight,
kRightToLeft
};
static Qt::Orientation GetFlowOrientation(FlowDirection dir) {
if (dir == kTopToBottom || dir == kBottomToTop) {
return Qt::Vertical;
} else {
return Qt::Horizontal;
}
}
static bool DirectionsAreOpposing(FlowDirection a, FlowDirection b) {
return ((a == NodeViewCommon::kLeftToRight && b == NodeViewCommon::kRightToLeft)
|| (a == NodeViewCommon::kRightToLeft && b == NodeViewCommon::kLeftToRight)
|| (a == NodeViewCommon::kTopToBottom && b == NodeViewCommon::kBottomToTop)
|| (a == NodeViewCommon::kBottomToTop && b == NodeViewCommon::kTopToBottom));
}
};
}
#endif // NODEVIEWCOMMON_H
-223
View File
@@ -1,223 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "nodeviewedge.h"
#include <QApplication>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QStyleOptionGraphicsItem>
#include "common/bezier.h"
#include "common/lerp.h"
#include "nodeview.h"
#include "nodeviewscene.h"
namespace olive {
NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
QGraphicsPathItem(parent),
edge_(nullptr),
connected_(false),
highlighted_(false),
flow_dir_(NodeViewCommon::kLeftToRight),
curved_(true)
{
setFlag(QGraphicsItem::ItemIsSelectable);
// Ensures this UI object is drawn behind other objects
setZValue(-1);
// Use font metrics to set edge width for basic high DPI support
edge_width_ = QFontMetrics(QFont()).height() / 12;
arrow_size_ = QFontMetrics(QFont()).height() / 2;
}
void NodeViewEdge::SetEdge(NodeEdgePtr edge)
{
SetConnected(true);
// Set the new edge pointer
edge_ = edge;
// Re-adjust the line positioning for this new edge
Adjust();
}
NodeEdgePtr NodeViewEdge::edge()
{
return edge_;
}
void NodeViewEdge::Adjust()
{
if (!edge_ || !scene()) {
return;
}
// Get the UI objects of both nodes that this edge connects
NodeViewItem* output = static_cast<NodeViewScene*>(scene())->NodeToUIObject(edge_->output()->parentNode());
NodeViewItem* input = static_cast<NodeViewScene*>(scene())->NodeToUIObject(edge_->input()->parentNode());
if (!output || !input) {
return;
}
// Draw a line between the two
SetPoints(output->GetParamPoint(edge_->output(), output->pos()),
input->GetParamPoint(edge_->input(), output->pos()),
input->IsExpanded());
}
void NodeViewEdge::SetConnected(bool c)
{
connected_ = c;
update();
}
void NodeViewEdge::SetHighlighted(bool e)
{
highlighted_ = e;
update();
}
void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool input_is_expanded)
{
QPainterPath path;
path.moveTo(start);
double angle = qAtan2(end.y() - start.y(), end.x() - start.x());
if (curved_) {
double half_x = lerp(start.x(), end.x(), 0.5);
double half_y = lerp(start.y(), end.y(), 0.5);
QPointF cp1, cp2;
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
cp1 = QPointF(half_x, start.y());
} else {
cp1 = QPointF(start.x(), half_y);
}
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal || input_is_expanded) {
cp2 = QPointF(half_x, end.y());
} else {
cp2 = QPointF(end.x(), half_y);
}
path.cubicTo(cp1, cp2, end);
if (!qFuzzyCompare(start.x(), end.x())) {
double continue_x = end.x() - qCos(angle)*arrow_size_;
double x1, x2, x3, x4, y1, y2, y3, y4;
if (start.x() < end.x()) {
x1 = start.x();
x2 = cp1.x();
x3 = cp2.x();
x4 = end.x();
y1 = start.y();
y2 = cp1.y();
y3 = cp2.y();
y4 = end.y();
} else {
x1 = end.x();
x2 = cp2.x();
x3 = cp1.x();
x4 = start.x();
y1 = end.y();
y2 = cp2.y();
y3 = cp1.y();
y4 = start.y();
}
double t = Bezier::CubicXtoT(continue_x, x1, x2, x3, x4);
double y = Bezier::CubicTtoY(y1, y2, y3, y4, t);
angle = qAtan2(end.y() - y, end.x() - continue_x);
}
} else {
path.lineTo(end);
}
setPath(path);
const double arrow_angle = 150.0 * 3.141592 / 180.0;
QVector<QPointF> arrow_points(4);
arrow_points[0] = end;
arrow_points[1] = end + QPointF(qCos(angle + arrow_angle) * arrow_size_, qSin(angle + arrow_angle) * arrow_size_);
arrow_points[2] = end + QPointF(qCos(angle - arrow_angle) * arrow_size_, qSin(angle - arrow_angle) * arrow_size_);
arrow_points[3] = end;
arrow_ = QPolygonF(arrow_points);
}
void NodeViewEdge::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
flow_dir_ = dir;
Adjust();
}
void NodeViewEdge::SetCurved(bool e)
{
curved_ = e;
update();
}
void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
QPalette::ColorGroup group;
QPalette::ColorRole role;
if (connected_) {
group = QPalette::Active;
} else {
group = QPalette::Disabled;
}
if (highlighted_ != bool(option->state & QStyle::State_Selected)) {
role = QPalette::Highlight;
} else {
role = QPalette::Text;
}
// Draw main path
QColor edge_color = qApp->palette().color(group, role);
painter->setPen(QPen(edge_color, edge_width_));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path());
// Draw arrow
painter->setPen(Qt::NoPen);
painter->setBrush(edge_color);
painter->drawPolygon(arrow_);
}
}
-121
View File
@@ -1,121 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEEDGEITEM_H
#define NODEEDGEITEM_H
#include <QGraphicsPathItem>
#include <QPalette>
#include "node/edge.h"
#include "nodeviewcommon.h"
namespace olive {
/**
* @brief A graphical representation of a NodeEdge to be used in NodeView
*
* A fairly simple line widget use to visualize a connection between two node parameters (a NodeEdge).
*/
class NodeViewEdge : public QGraphicsPathItem
{
public:
NodeViewEdge(QGraphicsItem* parent = nullptr);
/**
* @brief Set the edge that this item corresponds to
*
* This can be changed at any time (but under most circumstances won't be). Calling this will automatically call
* Adjust() to move this item into the correct position.
*/
void SetEdge(NodeEdgePtr edge);
NodeEdgePtr edge();
/**
* @brief Moves/updates this line to visually connect between the two corresponding NodeViewItems
*
* Using the attached edge (see SetEdge()), this function retrieves the NodeViewItems representing the two nodes
* that this edge connects. It uses their positions to determine where the line should visually connect and sets
* it accordingly.
*
* This should be set any time the NodeEdge changes (see SetEdge()), and any time the nodes move in the NodeGraph
* (see NodeView::ItemsChanged()). This will keep the nodes visually connected at all times.
*/
void Adjust();
/**
* @brief Set the connected state of this line
*
* When the edge is not connected, it visually depicts this by coloring the line grey. When an edge is connected or
* a potential connection is valid, the line is colored white. This function sets whether the line should be grey
* (false) or white (true).
*
* Using SetEdge() automatically sets this to true. Under most circumstances this should be left alone, and only
* be set when an edge is being created/dragged.
*/
void SetConnected(bool c);
/**
* @brief Set highlighted state
*
* Changes color of edge.
*/
void SetHighlighted(bool e);
/**
* @brief Set points to create curve from
*/
void SetPoints(const QPointF& start, const QPointF& end, bool input_is_expanded);
/**
* @brief Sets the direction nodes are flowing
*/
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
/**
* @brief Set whether edges should be drawn as curved or as straight lines
*/
void SetCurved(bool e);
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
NodeEdgePtr edge_;
int edge_width_;
bool connected_;
bool highlighted_;
NodeViewCommon::FlowDirection flow_dir_;
bool curved_;
QPolygonF arrow_;
int arrow_size_;
};
}
#endif // NODEEDGEITEM_H
-702
View File
@@ -1,702 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "nodeviewitem.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include "common/flipmodifiers.h"
#include "common/qtutils.h"
#include "config/config.h"
#include "core.h"
#include "nodeview.h"
#include "nodeviewscene.h"
#include "nodeviewundo.h"
#include "ui/icons/icons.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
QGraphicsRectItem(parent),
node_(nullptr),
dragging_edge_(nullptr),
cached_drop_item_(nullptr),
cached_drop_item_expanded_(false),
expanded_(false),
hide_titlebar_(false),
standard_click_(false),
highlighted_index_(-1),
node_edge_change_command_(nullptr),
flow_dir_(NodeViewCommon::kLeftToRight)
{
// Set flags for this widget
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
//
// We use font metrics to set all the UI measurements for DPI-awareness
//
// Set border width
node_border_width_ = DefaultItemBorder();
int widget_width = DefaultItemWidth();
int widget_height = DefaultItemHeight();
title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height);
setRect(title_bar_rect_);
}
QPointF NodeViewItem::GetNodePosition() const
{
QPointF node_pos;
qreal adjusted_x = pos().x() / DefaultItemHorizontalPadding();
qreal adjusted_y = pos().y() / DefaultItemVerticalPadding();
switch (flow_dir_) {
case NodeViewCommon::kLeftToRight:
node_pos.setX(adjusted_x);
node_pos.setY(adjusted_y);
break;
case NodeViewCommon::kRightToLeft:
node_pos.setX(-adjusted_x);
node_pos.setY(adjusted_y);
break;
case NodeViewCommon::kTopToBottom:
node_pos.setX(adjusted_y);
node_pos.setY(adjusted_x);
break;
case NodeViewCommon::kBottomToTop:
node_pos.setX(-adjusted_y);
node_pos.setY(adjusted_x);
break;
}
return node_pos;
}
void NodeViewItem::SetNodePosition(const QPointF &pos)
{
switch (flow_dir_) {
case NodeViewCommon::kLeftToRight:
setPos(pos.x() * DefaultItemHorizontalPadding(),
pos.y() * DefaultItemVerticalPadding());
break;
case NodeViewCommon::kRightToLeft:
setPos(-pos.x() * DefaultItemHorizontalPadding(),
pos.y() * DefaultItemVerticalPadding());
break;
case NodeViewCommon::kTopToBottom:
setPos(pos.y() * DefaultItemHorizontalPadding(),
pos.x() * DefaultItemVerticalPadding());
break;
case NodeViewCommon::kBottomToTop:
setPos(pos.y() * DefaultItemHorizontalPadding(),
-pos.x() * DefaultItemVerticalPadding());
break;
}
}
int NodeViewItem::DefaultTextPadding()
{
return QFontMetrics(QFont()).height() / 4;
}
int NodeViewItem::DefaultItemHeight()
{
return QFontMetrics(QFont()).height() + DefaultTextPadding() * 2;
}
int NodeViewItem::DefaultItemWidth()
{
return QtUtils::QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHHHHHH");;
}
int NodeViewItem::DefaultItemBorder()
{
return QFontMetrics(QFont()).height() / 12;
}
qreal NodeViewItem::DefaultItemHorizontalPadding() const
{
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
return DefaultItemWidth() * 1.5;
} else {
return DefaultItemWidth() * 1.25;
}
}
qreal NodeViewItem::DefaultItemVerticalPadding() const
{
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
return DefaultItemHeight() * 1.5;
} else {
return DefaultItemHeight() * 2.0;
}
}
void NodeViewItem::SetNode(Node *n)
{
node_ = n;
node_inputs_.clear();
if (node_) {
node_->Retranslate();
foreach (NodeParam* p, node_->parameters()) {
if (p->type() == NodeParam::kInput) {
NodeInput* input = static_cast<NodeInput*>(p);
if (input->is_connectable()) {
node_inputs_.append(input);
}
}
}
SetNodePosition(node_->GetPosition());
}
update();
}
Node *NodeViewItem::GetNode() const
{
return node_;
}
bool NodeViewItem::IsExpanded() const
{
return expanded_;
}
void NodeViewItem::SetExpanded(bool e, bool hide_titlebar)
{
if (node_inputs_.isEmpty()
|| (expanded_ == e && hide_titlebar_ == hide_titlebar)) {
return;
}
expanded_ = e;
hide_titlebar_ = hide_titlebar;
if (expanded_ && !node_inputs_.isEmpty()) {
// Create new rect
QRectF new_rect = title_bar_rect_;
if (hide_titlebar_) {
new_rect.setHeight(new_rect.height() * node_inputs_.size());
} else {
new_rect.setHeight(new_rect.height() * (node_inputs_.size() + 1));
}
setRect(new_rect);
} else {
setRect(title_bar_rect_);
}
update();
}
void NodeViewItem::ToggleExpanded()
{
SetExpanded(!IsExpanded());
}
void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
// HACK for getting the main QWidget palette color (the `widget`'s palette uses the NodeView color instead which we
// don't want here)
QPalette app_pal = Core::instance()->main_window()->palette();
// Draw background rect if expanded
if (IsExpanded()) {
painter->setPen(Qt::NoPen);
painter->setBrush(app_pal.color(QPalette::Window));
painter->drawRect(rect());
painter->setPen(app_pal.color(QPalette::Text));
for (int i=0;i<node_inputs_.size();i++) {
QRectF input_rect = GetInputRect(i);
if (highlighted_index_ == i) {
QColor highlight_col = app_pal.color(QPalette::Text);
highlight_col.setAlpha(64);
painter->fillRect(input_rect, highlight_col);
}
painter->drawText(input_rect, Qt::AlignCenter, node_inputs_.at(i)->name());
}
}
// Draw the titlebar
if (!hide_titlebar_ && node_) {
Color node_color = Config::Current()[QStringLiteral("NodeCatColor%1")
.arg(node_->Category().first())].value<Color>();
QLinearGradient grad;
grad.setStart(0, rect().top());
grad.setFinalStop(0, rect().bottom());
QColor node_color_as_qcolor = node_color.toQColor();
{
// Generate lighter color for gradient
qreal hue, sat, lightness;
node_color_as_qcolor.getHslF(&hue, &sat, &lightness);
lightness = qMin(1.0, lightness + 0.2);
grad.setColorAt(0.0, QColor::fromHslF(hue, sat, lightness));
}
grad.setColorAt(1.0, node_color_as_qcolor);
painter->setPen(Qt::black);
painter->setBrush(grad);
painter->drawRect(title_bar_rect_);
painter->setPen(app_pal.color(QPalette::Text));
QString node_label;
if (!node_->GetLabel().isEmpty()) {
// Use label directly if node has one
node_label = node_->GetLabel();
} else if (node_->IsTrack()) {
// If node is a track, use a special track name to help users identify better
// Exception for tracks
TrackOutput* track = static_cast<TrackOutput*>(node_);
node_label = TrackOutput::GetDefaultTrackName(track->track_type(), track->Index());
} else {
// Otherwise, just use the node's short name
node_label = node_->ShortName();
}
QFont f;
QFontMetrics fm(f);
// Draw right or down arrow based on expanded state
int icon_size = fm.height() / 2;
int icon_padding = title_bar_rect_.height() / 2 - icon_size / 2;
int icon_full_size = icon_size + icon_padding * 2;
const QIcon& expand_icon = IsExpanded() ? icon::TriDown : icon::TriRight;
expand_icon.paint(painter, QRect(title_bar_rect_.x() + icon_padding,
title_bar_rect_.y() + icon_padding,
icon_size,
icon_size));
// Calculate how much space we have for text
int item_width = title_bar_rect_.width();
int max_text_width = item_width - DefaultTextPadding() * 2 - icon_full_size;
int label_width = QtUtils::QFontMetricsWidth(fm, node_label);
// Concatenate text if necessary (adds a "..." to the end and removes characters until the
// string fits in the bounds)
if (label_width > max_text_width) {
QString concatenated;
do {
node_label.chop(1);
concatenated = QCoreApplication::translate("NodeViewItem", "%1...").arg(node_label);
} while ((label_width = QtUtils::QFontMetricsWidth(fm, concatenated)) > max_text_width);
node_label = concatenated;
}
// Determine the text color (automatically calculate from node background color)
if (node_color.GetRoughLuminance() > 0.5) {
painter->setPen(Qt::black);
} else {
painter->setPen(Qt::white);
}
// Determine X position (favors horizontal centering unless it'll overrun the arrow)
QRectF text_rect = title_bar_rect_;
Qt::Alignment text_align = Qt::AlignCenter;
int likely_x = item_width / 2 - label_width / 2;
if (likely_x < icon_full_size) {
text_rect.adjust(icon_full_size, 0, 0, 0);
text_align = Qt::AlignLeft | Qt::AlignVCenter;
}
// Draw the text in a rect (the rect is sized around text already in the constructor)
painter->drawText(text_rect,
text_align,
node_label);
}
// Draw final border
QPen border_pen;
border_pen.setWidth(node_border_width_);
if (option->state & QStyle::State_Selected) {
border_pen.setColor(app_pal.color(QPalette::Highlight));
} else {
border_pen.setColor(Qt::black);
}
painter->setPen(border_pen);
painter->setBrush(Qt::NoBrush);
painter->drawRect(rect());
}
void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// We override standard mouse behavior in some cases. In these cases, we don't want the standard "move" and "release"
// events to trigger if we haven't already triggered the "press" event. We use this variable to determine whether
// base class behavior is valid here.
standard_click_ = false;
// If CTRL is held, we start a new edge
if (node_ && event->modifiers() & Qt::ControlModifier) {
NodeParam* param = node_->output();
// Create draggable object
dragging_edge_ = new NodeViewEdge();
dragging_edge_->SetFlowDirection(flow_dir_);
// Set up a QUndoCommand to make this action undoable
node_edge_change_command_ = new QUndoCommand();
if (param->type() == NodeParam::kOutput || param->edges().isEmpty()) {
// For an output param (or an input param with no connections), we default to creating a new edge
drag_source_ = this;
drag_src_param_ = param;
// Set the starting position to the current param's connector
dragging_edge_start_ = GetParamPoint(param, QPointF());
} else if (param->type() == NodeParam::kInput) {
// For an input param, we default to moving an existing edge
// (here we use the last one, which will usually also be the first)
NodeEdgePtr edge = param->edges().last();
// The starting position will be the OPPOSING parameter's rectangle
// Get the opposing parameter
drag_src_param_ = edge->output();
// Get its Node UI object
drag_source_ = static_cast<NodeViewScene*>(scene())->NodeToUIObject(drag_src_param_->parentNode());
// Get the opposing parameter's rect center using the line's current coordinates
// (we use the current coordinates because a complex formula is used for the line's coords if
// the opposing node is collapsed, therefore it's easier to just retrieve it from line itself)
NodeViewEdge* existing_edge_ui = static_cast<NodeViewScene*>(scene())->EdgeToUIObject(edge);
QPainterPath existing_edge_line = existing_edge_ui->path();
QPointF edge_start = existing_edge_line.pointAtPercent(0);
QPointF edge_end = existing_edge_line.pointAtPercent(1);
if (existing_edge_ui->contains(edge_start)) {
dragging_edge_start_ = edge_start;
} else {
dragging_edge_start_ = edge_end;
}
// Remove old edge
NodeEdgeRemoveCommand* remove_command = new NodeEdgeRemoveCommand(edge->output(),
edge->input(),
node_edge_change_command_);
remove_command->redo();
}
// Add it to the scene
scene()->addItem(dragging_edge_);
// Trigger initial line setting
mouseMoveEvent(event);
return;
} else {
// We aren't using any override behaviors, switch back to standard click behavior
standard_click_ = true;
event->setModifiers(FlipControlAndShiftModifiers(event->modifiers()));
QGraphicsRectItem::mousePressEvent(event);
}
}
void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// Check if an edge drag was initiated
if (dragging_edge_ != nullptr) {
QPointF end_point = event->scenePos();
drag_dest_param_ = nullptr;
if (!cached_drop_item_
|| !cached_drop_item_->contains(cached_drop_item_->mapFromScene(event->scenePos()))) {
// Cursor has left last entered item, we need to find a new one
if (cached_drop_item_) {
// If we expanded an item below but are no longer dragging over it, re-collapse it
if (cached_drop_item_expanded_) {
cached_drop_item_->SetExpanded(false);
}
cached_drop_item_->SetHighlightedIndex(-1);
cached_drop_item_->setZValue(0);
cached_drop_item_ = nullptr;
}
NodeViewItem* cursor_item = dynamic_cast<NodeViewItem*>(scene()->itemAt(event->scenePos(), sceneTransform()));
if (cursor_item
&& cursor_item != drag_source_
&& !cursor_item->node_inputs_.isEmpty()) {
cached_drop_item_ = cursor_item;
// If the item we're dragging over is collapsed, expand it
cached_drop_item_expanded_ = !cached_drop_item_->IsExpanded();
if (cached_drop_item_expanded_) {
cached_drop_item_->SetExpanded(true, true);
}
cached_drop_item_->setZValue(1);
} else {
cached_drop_item_ = nullptr;
}
}
if (cached_drop_item_) {
int highlight_their_index = -1;
// See if the mouse is currently inside a connector rect
for (int i=0;i<cached_drop_item_->node_inputs_.size();i++) {
// Get the parameter we're dragging into
NodeParam* comp_param = cached_drop_item_->node_inputs_.at(i);
// See if cursor is inside its UI
if (cached_drop_item_->GetInputRect(i).contains(cached_drop_item_->mapFromScene(event->scenePos()))) { // See if we're dragging inside the hitbox
// Attempt to prevent circular dependency - ensure the receiving node doesn't output to the outputting node
if (!cached_drop_item_->GetNode()->OutputsTo(node_, true)) {
drag_dest_param_ = comp_param;
highlight_their_index = i;
QPointF end_point_local = cached_drop_item_->GetInputPoint(i, pos());
end_point = cached_drop_item_->mapToScene(end_point_local);
}
break;
}
}
cached_drop_item_->SetHighlightedIndex(highlight_their_index);
}
dragging_edge_->SetConnected(drag_dest_param_);
dragging_edge_->SetPoints(dragging_edge_start_,
end_point,
cached_drop_item_ ? cached_drop_item_->IsExpanded() : false);
return;
}
if (standard_click_) {
event->setModifiers(FlipControlAndShiftModifiers(event->modifiers()));
QGraphicsRectItem::mouseMoveEvent(event);
}
}
void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
// Check if an edge drag was initiated
if (dragging_edge_ != nullptr) {
// Remove the drag object
scene()->removeItem(dragging_edge_);
// If we expanded an item in the drag, re-collapse it now
if (cached_drop_item_) {
if (cached_drop_item_expanded_) {
cached_drop_item_->SetExpanded(false);
}
cached_drop_item_->SetHighlightedIndex(-1);
cached_drop_item_->setZValue(0);
cached_drop_item_ = nullptr;
}
if (drag_dest_param_ != nullptr) {
// We dragged to somewhere, so we'll make a new connection
NodeEdgePtr new_edge;
NodeOutput* output;
NodeInput* input;
// Connecting will automatically add an edge UI object through the signal/slot system
if (drag_dest_param_->type() == NodeParam::kOutput) {
output = static_cast<NodeOutput*>(drag_dest_param_);
input = static_cast<NodeInput*>(drag_src_param_);
} else {
output = static_cast<NodeOutput*>(drag_src_param_);
input = static_cast<NodeInput*>(drag_dest_param_);
}
// Use a command to make Node connecting undoable
new NodeEdgeAddCommand(output,
input,
node_edge_change_command_);
}
dragging_edge_ = nullptr;
Core::instance()->undo_stack()->pushIfHasChildren(node_edge_change_command_);
node_edge_change_command_ = nullptr;
return;
}
if (standard_click_) {
event->setModifiers(FlipControlAndShiftModifiers(event->modifiers()));
QGraphicsRectItem::mouseReleaseEvent(event);
}
}
void NodeViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsRectItem::mouseDoubleClickEvent(event);
if (!(event->modifiers() & Qt::ControlModifier)) {
SetExpanded(!IsExpanded());
}
}
QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionHasChanged && node_) {
node_->blockSignals(true);
node_->SetPosition(GetNodePosition());
node_->blockSignals(false);
}
return QGraphicsItem::itemChange(change, value);
}
void NodeViewItem::SetHighlightedIndex(int index)
{
if (highlighted_index_ == index) {
return;
}
highlighted_index_ = index;
update();
}
QRectF NodeViewItem::GetInputRect(int index) const
{
QRectF r = title_bar_rect_;
if (!hide_titlebar_) {
index++;
}
if (IsExpanded()) {
r.translate(0, r.height() * index);
}
return r;
}
QPointF NodeViewItem::GetParamPoint(NodeParam *param, const QPointF& source_pos) const
{
if (param->type() == NodeParam::kOutput) {
switch (flow_dir_) {
case NodeViewCommon::kLeftToRight:
default:
return pos() + QPointF(rect().right(), rect().center().y());
case NodeViewCommon::kRightToLeft:
return pos() + QPointF(rect().left(), rect().center().y());
case NodeViewCommon::kTopToBottom:
return pos() + QPointF(rect().center().x(), rect().bottom());
case NodeViewCommon::kBottomToTop:
return pos() + QPointF(rect().center().x(), rect().top());
}
} else {
NodeInput* input = static_cast<NodeInput*>(param);
// Resolve NodeInputArray elements
while (input->parentNode() != input->parent()) {
input = static_cast<NodeInput*>(input->parent());
}
return pos() + GetInputPoint(node_inputs_.indexOf(input), source_pos);
}
}
void NodeViewItem::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
flow_dir_ = dir;
}
QPointF NodeViewItem::GetInputPoint(int index, const QPointF& source_pos) const
{
QRectF input_rect = GetInputRect(index);
Qt::Orientation flow_orientation = NodeViewCommon::GetFlowOrientation(flow_dir_);
if (flow_orientation == Qt::Horizontal || IsExpanded()) {
if (flow_dir_ == NodeViewCommon::kLeftToRight
|| (flow_orientation == Qt::Vertical && source_pos.x() < pos().x())) {
return QPointF(input_rect.left(), input_rect.center().y());
} else {
return QPointF(input_rect.right(), input_rect.center().y());
}
} else {
if (flow_dir_ == NodeViewCommon::kTopToBottom) {
return QPointF(input_rect.center().x(), input_rect.top());
} else {
return QPointF(input_rect.center().x(), input_rect.bottom());
}
}
}
}
-179
View File
@@ -1,179 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEVIEWITEM_H
#define NODEVIEWITEM_H
#include <QFontMetrics>
#include <QGraphicsRectItem>
#include <QLinearGradient>
#include <QUndoCommand>
#include <QWidget>
#include "node/node.h"
#include "nodeviewcommon.h"
#include "nodeviewedge.h"
#include "nodeviewitemwidgetproxy.h"
namespace olive {
/**
* @brief A visual widget representation of a Node object to be used in a NodeView
*
* This widget can be collapsed or expanded to show/hide the node's various parameters.
*
* To retrieve the NodeViewItem for a certain Node, use NodeView::NodeToUIObject().
*/
class NodeViewItem : public QGraphicsRectItem
{
public:
NodeViewItem(QGraphicsItem* parent = nullptr);
QPointF GetNodePosition() const;
void SetNodePosition(const QPointF& pos);
/**
* @brief Set the Node to correspond to this widget
*/
void SetNode(Node* n);
/**
* @brief Get currently attached node
*/
Node* GetNode() const;
/**
* @brief Get expanded state
*/
bool IsExpanded() const;
/**
* @brief Set expanded state
*/
void SetExpanded(bool e, bool hide_titlebar = false);
void ToggleExpanded();
/**
* @brief Returns GLOBAL point that edges should connect to for any NodeParam member of this object
*/
QPointF GetParamPoint(NodeParam* param, const QPointF &source_pos) const;
/**
* @brief Sets the direction nodes are flowing
*/
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
static int DefaultTextPadding();
static int DefaultItemHeight();
static int DefaultItemWidth();
static int DefaultItemBorder();
qreal DefaultItemHorizontalPadding() const;
qreal DefaultItemVerticalPadding() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
private:
/**
* @brief Highlight an input (for instance when the user is dragging over it)
*/
void SetHighlightedIndex(int index);
/**
* @brief Returns local rect of a NodeInput in array node_inputs_[index]
*/
QRectF GetInputRect(int index) const;
/**
* @brief Returns local point that edges should connect to for a NodeInput in array node_inputs_[index]
*/
QPointF GetInputPoint(int index, const QPointF &source_pos) const;
/**
* @brief Reference to attached Node
*/
Node* node_;
/**
* @brief Cached list of node inputs
*/
QList<NodeInput*> node_inputs_;
/**
* @brief Rectangle of the Node's title bar (equal to rect() when collapsed)
*/
QRectF title_bar_rect_;
/// Edge dragging variables
NodeViewEdge* dragging_edge_;
QPointF dragging_edge_start_;
NodeParam* drag_src_param_;
NodeParam* drag_dest_param_;
NodeViewItem* drag_source_;
NodeViewItem* cached_drop_item_;
bool cached_drop_item_expanded_;
/// Sizing variables to use when drawing
int node_border_width_;
/**
* @brief Expanded state
*/
bool expanded_;
bool hide_titlebar_;
/**
* @brief Current click mode
*
* \see mousePressEvent()
*/
bool standard_click_;
int highlighted_index_;
/**
* @brief QUndoCommand for creating and deleting edges by dragging
*
* \see mousePressEvent()
* \see mouseReleaseEvent()
*/
QUndoCommand* node_edge_change_command_;
NodeViewCommon::FlowDirection flow_dir_;
};
}
#endif // NODEVIEWITEM_H
@@ -1,41 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "nodeviewitemwidgetproxy.h"
QColor NodeViewItemWidget::TitleBarColor()
{
return title_bar_color_;
}
void NodeViewItemWidget::SetTitleBarColor(QColor color)
{
title_bar_color_ = color;
}
QColor NodeViewItemWidget::BorderColor()
{
return border_color_;
}
void NodeViewItemWidget::SetBorderColor(QColor color)
{
border_color_ = color;
}
@@ -1,49 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEVIEWITEMWIDGETPROXY_H
#define NODEVIEWITEMWIDGETPROXY_H
#include <QWidget>
/**
* @brief A proxy object to allow NodeViewItem access to CSS functions
*
* QGraphicsItems can't take Q_PROPERTYs for CSS stylesheet input, but QWidgets can. This is a hack to allow CSS
* properties to be set from CSS and then read by NodeViewItem.
*/
class NodeViewItemWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(QColor titlebarColor READ TitleBarColor WRITE SetTitleBarColor DESIGNABLE true)
Q_PROPERTY(QColor borderColor READ BorderColor WRITE SetBorderColor DESIGNABLE true)
public:
NodeViewItemWidget() = default;
QColor TitleBarColor();
void SetTitleBarColor(QColor color);
QColor BorderColor();
void SetBorderColor(QColor color);
private:
QColor title_bar_color_;
QColor border_color_;
};
#endif // NODEVIEWITEMWIDGETPROXY_H
-313
View File
@@ -1,313 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "nodeviewscene.h"
#include "common/functiontimer.h"
#include "nodeviewedge.h"
#include "nodeviewitem.h"
#include "project/item/sequence/sequence.h"
namespace olive {
NodeViewScene::NodeViewScene(QObject *parent) :
QGraphicsScene(parent),
graph_(nullptr),
direction_(NodeViewCommon::kLeftToRight),
curved_edges_(true)
{
}
void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction)
{
direction_ = direction;
{
// Iterate over node items setting direction
QHash<Node*, NodeViewItem*>::const_iterator i;
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
i.value()->SetFlowDirection(direction_);
// Update position too
i.value()->SetNodePosition(i.key()->GetPosition());
}
}
{
// Iterate over edge items setting direction
QHash<NodeEdge*, NodeViewEdge*>::const_iterator i;
for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) {
i.value()->SetFlowDirection(direction_);
}
}
}
void NodeViewScene::clear()
{
// Deselect everything (prevents signals that a selection has changed after deleting an object)
DeselectAll();
// HACK: QGraphicsScene contains some sort of internal caching of the selected items which doesn't update unless
// we call a function like this. That means even though we deselect all items above, QGraphicsScene will
// continue to incorrectly signal selectionChanged() when items that were selected (but are now not) get
// deleted. Calling this function appears to update the internal cache and prevent this.
selectedItems();
{
QHash<Node*, NodeViewItem*>::const_iterator i;
for (i=item_map_.begin();i!=item_map_.end();i++) {
delete i.value();
}
item_map_.clear();
}
{
QHash<NodeEdge*, NodeViewEdge*>::const_iterator i;
for (i=edge_map_.begin();i!=edge_map_.end();i++) {
delete i.value();
}
edge_map_.clear();
}
}
void NodeViewScene::SelectAll()
{
QList<QGraphicsItem *> all_items = this->items();
foreach (QGraphicsItem* i, all_items) {
i->setSelected(true);
}
}
void NodeViewScene::DeselectAll()
{
QList<QGraphicsItem *> selected_items = this->selectedItems();
foreach (QGraphicsItem* i, selected_items) {
i->setSelected(false);
}
}
NodeViewItem *NodeViewScene::NodeToUIObject(Node *n)
{
return item_map_.value(n);
}
NodeViewEdge *NodeViewScene::EdgeToUIObject(NodeEdgePtr n)
{
return edge_map_.value(n.get());
}
void NodeViewScene::SetGraph(NodeGraph *graph)
{
graph_ = graph;
}
QVector<Node *> NodeViewScene::GetSelectedNodes() const
{
QHash<Node*, NodeViewItem*>::const_iterator iterator;
QVector<Node *> selected;
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
if (iterator.value()->isSelected()) {
selected.append(iterator.key());
}
}
return selected;
}
QVector<NodeViewItem *> NodeViewScene::GetSelectedItems() const
{
QHash<Node*, NodeViewItem*>::const_iterator iterator;
QVector<NodeViewItem *> selected;
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
if (iterator.value()->isSelected()) {
selected.append(iterator.value());
}
}
return selected;
}
QVector<NodeEdge*> NodeViewScene::GetSelectedEdges() const
{
QVector<NodeEdge*> edges;
QHash<NodeEdge*, NodeViewEdge*>::const_iterator i;
for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) {
if (i.value()->isSelected()) {
edges.append(i.key());
}
}
return edges;
}
const QHash<Node *, NodeViewItem *> &NodeViewScene::item_map() const
{
return item_map_;
}
const QHash<NodeEdge *, NodeViewEdge *> &NodeViewScene::edge_map() const
{
return edge_map_;
}
void NodeViewScene::AddNode(Node* node)
{
NodeViewItem* item = new NodeViewItem();
item->SetFlowDirection(direction_);
item->SetNode(node);
addItem(item);
item_map_.insert(node, item);
// Add a NodeViewEdge for each connection
foreach (NodeParam* param, node->parameters()) {
// We only bother working with outputs since eventually this will cover all inputs too
// (covering both would lead to duplicates since every edge connects to one input and one output)
if (param->type() == NodeParam::kOutput) {
const QVector<NodeEdgePtr>& edges = param->edges();
foreach(NodeEdgePtr edge, edges) {
AddEdge(edge);
}
}
}
connect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged);
connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged);
}
void NodeViewScene::RemoveNode(Node *node)
{
disconnect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged);
disconnect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged);
delete item_map_.take(node);
}
void NodeViewScene::AddEdge(NodeEdgePtr edge)
{
NodeViewEdge* edge_ui = new NodeViewEdge();
edge_ui->SetEdge(edge);
edge_ui->SetFlowDirection(direction_);
edge_ui->SetCurved(curved_edges_);
addItem(edge_ui);
edge_map_.insert(edge.get(), edge_ui);
}
void NodeViewScene::RemoveEdge(NodeEdgePtr edge)
{
delete edge_map_.take(edge.get());
}
int NodeViewScene::DetermineWeight(Node *n)
{
QVector<Node*> inputs = n->GetImmediateDependencies();
int weight = 0;
foreach (Node* i, inputs) {
if (i->GetRoutesTo(n) == 1) {
weight += DetermineWeight(i);
}
}
return qMax(1, weight);
}
Qt::Orientation NodeViewScene::GetFlowOrientation() const
{
return NodeViewCommon::GetFlowOrientation(direction_);
}
NodeViewCommon::FlowDirection NodeViewScene::GetFlowDirection() const
{
return direction_;
}
void NodeViewScene::ReorganizeFrom(Node* n)
{
QVector<Node*> immediates = n->GetImmediateDependencies();
if (immediates.isEmpty()) {
// Nothing to do
return;
}
QPointF parent_pos = n->GetPosition();
int weight_count = DetermineWeight(n);
qreal child_x = parent_pos.x() - 1.0;
qreal children_height = weight_count-1;
qreal children_y = parent_pos.y() - children_height * 0.5;
int weight_counter = 0;
foreach (Node* i, immediates) {
if (i->GetRoutesTo(n) == 1) {
int weight = DetermineWeight(i);
i->SetPosition(QPointF(child_x,
children_y + weight_counter + (weight - 1) * 0.5));
weight_counter += weight;
ReorganizeFrom(i);
}
}
}
bool NodeViewScene::GetEdgesAreCurved() const
{
return curved_edges_;
}
void NodeViewScene::SetEdgesAreCurved(bool curved)
{
if (curved_edges_ != curved) {
curved_edges_ = curved;
foreach (NodeViewEdge* e, edge_map_) {
e->SetCurved(curved_edges_);
}
}
}
void NodeViewScene::NodePositionChanged(const QPointF &pos)
{
item_map_.value(static_cast<Node*>(sender()))->SetNodePosition(pos);
}
void NodeViewScene::NodeLabelChanged()
{
item_map_.value(static_cast<Node*>(sender()))->update();
}
}
-151
View File
@@ -1,151 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NODEVIEWSCENE_H
#define NODEVIEWSCENE_H
#include <QGraphicsScene>
#include <QTimer>
#include "node/graph.h"
#include "nodeviewedge.h"
#include "nodeviewitem.h"
namespace olive {
class NodeViewScene : public QGraphicsScene
{
Q_OBJECT
public:
NodeViewScene(QObject *parent = nullptr);
void clear();
void SelectAll();
void DeselectAll();
/**
* @brief Retrieve the graphical widget corresponding to a specific Node
*
* In situations where you know what Node you're working with but need the UI object (e.g. for positioning), this
* static function will retrieve the NodeViewItem (Node UI representation) connected to this Node in a certain
* QGraphicsScene. This can be called from any other UI object, since it'll have a reference to the QGraphicsScene
* through QGraphicsItem::scene().
*
* If the scene does not contain a widget for this node (usually meaning the node's graph is not the active graph
* in this view/scene), this function returns nullptr.
*/
NodeViewItem* NodeToUIObject(Node* n);
/**
* @brief Retrieve the graphical widget corresponding to a specific NodeEdge
*
* Same as NodeToUIObject() but returns a NodeViewEdge corresponding to a NodeEdgePtr instead.
*/
NodeViewEdge* EdgeToUIObject(NodeEdgePtr n);
void SetGraph(NodeGraph* graph);
QVector<Node *> GetSelectedNodes() const;
QVector<NodeViewItem*> GetSelectedItems() const;
QVector<NodeEdge *> GetSelectedEdges() const;
const QHash<Node*, NodeViewItem*>& item_map() const;
const QHash<NodeEdge*, NodeViewEdge*>& edge_map() const;
Qt::Orientation GetFlowOrientation() const;
NodeViewCommon::FlowDirection GetFlowDirection() const;
void SetFlowDirection(NodeViewCommon::FlowDirection direction);
/**
* @brief Automatically reposition the nodes based on their connections
*/
void ReorganizeFrom(Node* n);
bool GetEdgesAreCurved() const;
public slots:
/**
* @brief Slot when a Node is added to a graph (SetGraph() connects this)
*
* This should NEVER be called directly, only connected to a NodeGraph. To add a Node to the NodeGraph
* use NodeGraph::AddNode().
*/
void AddNode(Node* node);
/**
* @brief Slot when a Node is removed from a graph (SetGraph() connects this)
*
* This should NEVER be called directly, only connected to a NodeGraph. To remove a Node from the NodeGraph
* use NodeGraph::RemoveNode().
*/
void RemoveNode(Node* node);
/**
* @brief Slot when an edge is added to a graph (SetGraph() connects this)
*
* This should NEVER be called directly, only connected to a NodeGraph. To add an edge (i.e. connect two node
* parameters together), use NodeParam::ConnectEdge().
*/
void AddEdge(NodeEdgePtr edge);
/**
* @brief Slot when an edge is removed from a graph (SetGraph() connects this)
*
* This should NEVER be called directly, only connected to a NodeGraph. To remove an edge (i.e. disconnect two node
* parameters), use NodeParam::DisconnectEdge().
*/
void RemoveEdge(NodeEdgePtr edge);
/**
* @brief Set whether edges in this scene should be curved or not
*/
void SetEdgesAreCurved(bool curved);
private:
static int DetermineWeight(Node* n);
QHash<Node*, NodeViewItem*> item_map_;
QHash<NodeEdge*, NodeViewEdge*> edge_map_;
NodeGraph* graph_;
NodeViewCommon::FlowDirection direction_;
bool curved_edges_;
private slots:
/**
* @brief Receiver for whenever a node position changes
*/
void NodePositionChanged(const QPointF& pos);
/**
* @brief Receiver for when a node's label has changed
*/
void NodeLabelChanged();
};
}
#endif // NODEVIEWSCENE_H
+18 -119
View File
@@ -24,87 +24,50 @@
namespace olive {
NodeEdgeAddCommand::NodeEdgeAddCommand(NodeOutput *output, NodeInput *input, QUndoCommand *parent) :
NodeEdgeAddCommand::NodeEdgeAddCommand(Node *output, NodeInput *input, int element, QUndoCommand *parent) :
UndoCommand(parent),
output_(output),
input_(input),
old_edge_(nullptr),
done_(false)
element_(element)
{
}
void NodeEdgeAddCommand::redo_internal()
{
if (done_) {
return;
}
old_edge_ = NodeParam::DisconnectForNewOutput(input_);
NodeParam::ConnectEdge(output_, input_);
done_ = true;
Node::ConnectEdge(output_, input_, element_);
}
void NodeEdgeAddCommand::undo_internal()
{
if (!done_) {
return;
}
NodeParam::DisconnectEdge(output_, input_);
if (old_edge_ != nullptr) {
NodeParam::ConnectEdge(old_edge_->output(), old_edge_->input());
}
done_ = false;
Node::DisconnectEdge(output_, input_, element_);
}
Project *NodeEdgeAddCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(output_->parentNode()->parent())->project();
return output_->parent()->project();
}
NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeOutput *output, NodeInput *input, QUndoCommand *parent) :
NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(Node *output, NodeInput *input, int element, QUndoCommand *parent) :
UndoCommand(parent),
output_(output),
input_(input),
done_(false)
{
}
NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand *parent) :
UndoCommand(parent),
output_(edge->output()),
input_(edge->input()),
done_(false)
element_(element)
{
}
void NodeEdgeRemoveCommand::redo_internal()
{
if (done_) {
return;
}
NodeParam::DisconnectEdge(output_, input_);
done_ = true;
Node::DisconnectEdge(output_, input_, element_);
}
void NodeEdgeRemoveCommand::undo_internal()
{
if (!done_) {
return;
}
NodeParam::ConnectEdge(output_, input_);
done_ = false;
Node::ConnectEdge(output_, input_, element_);
}
Project *NodeEdgeRemoveCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(output_->parentNode()->parent())->project();
return output_->parent()->project();
}
NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node, QUndoCommand *parent) :
@@ -118,75 +81,34 @@ NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node, QUndoCommand *paren
void NodeAddCommand::redo_internal()
{
graph_->AddNode(node_);
node_->setParent(graph_);
}
void NodeAddCommand::undo_internal()
{
graph_->TakeNode(node_, &memory_manager_);
node_->setParent(&memory_manager_);
}
Project *NodeAddCommand::GetRelevantProject() const
{
return static_cast<Sequence*>(graph_)->project();
return graph_->project();
}
NodeRemoveCommand::NodeRemoveCommand(NodeGraph *graph, const QVector<Node *> &nodes, QUndoCommand *parent) :
NodeRemoveCommand::NodeRemoveCommand(Node *node, QUndoCommand *parent) :
UndoCommand(parent),
graph_(graph),
nodes_(nodes)
graph_(node->parent()),
node_(node)
{
}
void NodeRemoveCommand::redo_internal()
{
// Cache edges for undoing
foreach (Node* n, nodes_) {
foreach (NodeParam* param, n->parameters()) {
foreach (NodeEdgePtr edge, param->edges()) {
// Ensures the same edge isn't added twice (prevents double connecting when undoing)
if (!edges_.contains(edge)) {
edges_.append(edge);
}
}
}
}
// Take nodes from graph (TakeNode() will automatically disconnect edges)
foreach (Node* n, nodes_) {
// If the node is a block, unlink any linked blocks before removing
if (n->IsBlock()) {
Block *b = static_cast<Block *>(n);
if (b->HasLinks()) {
BlockUnlinkAllCommand *unlink_command = new BlockUnlinkAllCommand(b);
unlink_command->redo();
block_unlink_commands_.append(unlink_command);
}
}
graph_->TakeNode(n, &memory_manager_);
}
node_->setParent(&memory_manager_);
}
void NodeRemoveCommand::undo_internal()
{
// Re-add nodes to graph
foreach (Node* n, nodes_) {
graph_->AddNode(n);
}
// Relink any blocks that were unlinked
foreach(BlockUnlinkAllCommand* command, block_unlink_commands_) {
command->undo();
delete command;
}
// Re-connect edges
foreach (NodeEdgePtr edge, edges_) {
NodeParam::ConnectEdge(edge->output(), edge->input());
}
edges_.clear();
block_unlink_commands_.clear();
node_->setParent(graph_);
}
Project *NodeRemoveCommand::GetRelevantProject() const
@@ -194,21 +116,6 @@ Project *NodeRemoveCommand::GetRelevantProject() const
return static_cast<Sequence*>(graph_)->project();
}
NodeRemoveWithExclusiveDeps::NodeRemoveWithExclusiveDeps(NodeGraph *graph, Node *node, QUndoCommand *parent) :
UndoCommand(parent)
{
QVector<Node*> node_and_its_deps;
node_and_its_deps.append(node);
node_and_its_deps.append(node->GetExclusiveDependencies());
remove_command_ = new NodeRemoveCommand(graph, node_and_its_deps, this);
}
Project *NodeRemoveWithExclusiveDeps::GetRelevantProject() const
{
return remove_command_->GetRelevantProject();
}
NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, bool include_connections, QUndoCommand *parent) :
QUndoCommand(parent),
src_(src),
@@ -217,14 +124,6 @@ NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, bool include
{
}
NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, QUndoCommand *parent) :
QUndoCommand(parent),
src_(src),
dest_(dest),
include_connections_(true)
{
}
void NodeCopyInputsCommand::redo()
{
Node::CopyInputs(src_, dest_, include_connections_);
+9 -89
View File
@@ -25,7 +25,6 @@
#include "node/graph.h"
#include "node/node.h"
#include "nodeviewitem.h"
#include "undo/undocommand.h"
#include "widget/timelinewidget/undo/undo.h"
@@ -38,7 +37,7 @@ namespace olive {
*/
class NodeEdgeAddCommand : public UndoCommand {
public:
NodeEdgeAddCommand(NodeOutput* output, NodeInput* input, QUndoCommand* parent = nullptr);
NodeEdgeAddCommand(Node* output, NodeInput* input, int element, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -47,12 +46,10 @@ protected:
virtual void undo_internal() override;
private:
NodeOutput* output_;
Node* output_;
NodeInput* input_;
int element_;
NodeEdgePtr old_edge_;
bool done_;
};
/**
@@ -62,8 +59,7 @@ private:
*/
class NodeEdgeRemoveCommand : public UndoCommand {
public:
NodeEdgeRemoveCommand(NodeOutput* output, NodeInput* input, QUndoCommand* parent = nullptr);
NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand* parent = nullptr);
NodeEdgeRemoveCommand(Node* output, NodeInput* input, int element, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -72,10 +68,10 @@ protected:
virtual void undo_internal() override;
private:
NodeOutput* output_;
Node* output_;
NodeInput* input_;
int element_;
bool done_;
};
class NodeAddCommand : public UndoCommand {
@@ -97,8 +93,7 @@ private:
class NodeRemoveCommand : public UndoCommand {
public:
NodeRemoveCommand(NodeGraph* graph,
const QVector<Node*>& nodes,
NodeRemoveCommand(Node* node,
QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
@@ -111,32 +106,15 @@ private:
QObject memory_manager_;
NodeGraph* graph_;
QVector<Node*> nodes_;
QVector<NodeEdgePtr> edges_;
QVector<BlockUnlinkAllCommand*> block_unlink_commands_;
};
Node* node_;
class NodeRemoveWithExclusiveDeps : public UndoCommand {
public:
NodeRemoveWithExclusiveDeps(NodeGraph* graph,
Node* node,
QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
private:
NodeRemoveCommand* remove_command_;
};
class NodeCopyInputsCommand : public QUndoCommand {
public:
NodeCopyInputsCommand(Node* src,
Node* dest,
bool include_connections = true,
QUndoCommand* parent = nullptr);
NodeCopyInputsCommand(Node* src,
Node* dest,
bool include_connections,
QUndoCommand* parent = nullptr);
protected:
@@ -151,64 +129,6 @@ private:
};
class NodeGraphBeginOperationCommand : public UndoCommand {
public:
NodeGraphBeginOperationCommand(NodeGraph* graph, QUndoCommand* parent = nullptr) :
UndoCommand(parent),
graph_(graph)
{
}
virtual Project* GetRelevantProject() const override
{
return static_cast<Sequence*>(graph_)->project();
}
protected:
virtual void redo_internal() override
{
graph_->BeginOperation();
}
virtual void undo_internal() override
{
graph_->EndOperation();
}
private:
NodeGraph* graph_;
};
class NodeGraphEndOperationCommand : public UndoCommand {
public:
NodeGraphEndOperationCommand(NodeGraph* graph, QUndoCommand* parent = nullptr) :
UndoCommand(parent),
graph_(graph)
{
}
virtual Project* GetRelevantProject() const override
{
return static_cast<Sequence*>(graph_)->project();
}
protected:
virtual void redo_internal() override
{
graph_->EndOperation();
}
virtual void undo_internal() override
{
graph_->BeginOperation();
}
private:
NodeGraph* graph_;
};
}
#endif // NODEVIEWUNDO_H
@@ -541,9 +541,9 @@ void ProjectExplorer::DeselectAll()
CurrentView()->selectionModel()->clearSelection();
}
QList<MediaInput *> ProjectExplorer::GetMediaNodesUsingFootage(Footage *item)
QVector<MediaInput *> ProjectExplorer::GetMediaNodesUsingFootage(Footage *item)
{
QList<MediaInput *> list;
QVector<MediaInput *> list;
// Get all sequences.
QVector<Item*> sequences = model_.project()->get_items_of_type(Item::kSequence);
@@ -552,12 +552,10 @@ QList<MediaInput *> ProjectExplorer::GetMediaNodesUsingFootage(Footage *item)
foreach (Item* s, sequences) {
const QList<Node*>& nodes = static_cast<Sequence*>(s)->nodes();
foreach (Node* n, nodes) {
if (n->IsMedia()) {
MediaInput* media_node = static_cast<MediaInput*>(n);
MediaInput* media_node = dynamic_cast<MediaInput*>(n);
if (media_node->stream()->footage() == item) {
list.append(media_node);
}
if (media_node && media_node->stream()->footage() == item) {
list.append(media_node);
}
}
}
@@ -593,7 +591,7 @@ void ProjectExplorer::DeleteSelected()
// If this is footage, check if it's used anywhere in any sequence
Footage* footage = static_cast<Footage*>(item);
QList<MediaInput*> footage_nodes = GetMediaNodesUsingFootage(footage);
QVector<MediaInput*> footage_nodes = GetMediaNodesUsingFootage(footage);
if (!footage_nodes.isEmpty()) {
// Footage is in use, show messagebox asking what to do about it
+2 -2
View File
@@ -105,11 +105,11 @@ private:
/**
* @brief Check if an item is in use anywhere and return any relevant input nodes
*/
QList<MediaInput*> GetMediaNodesUsingFootage(Footage* item);
QVector<MediaInput*> GetMediaNodesUsingFootage(Footage* item);
/**
* @brief Get all the blocks that solely rely on an input node
*
*
* Ignores blocks that depend on multiple inputs
*/
QList<Block*> GetFootageBlocks(QList<Node*> nodes);
@@ -22,7 +22,7 @@
namespace olive {
OfflineFootageCommand::OfflineFootageCommand(const QList<MediaInput *> &media, QUndoCommand* parent) :
OfflineFootageCommand::OfflineFootageCommand(const QVector<MediaInput *> &media, QUndoCommand* parent) :
UndoCommand(parent)
{
foreach (MediaInput* i, media) {
@@ -31,7 +31,7 @@ namespace olive {
*/
class OfflineFootageCommand : public UndoCommand {
public:
OfflineFootageCommand(const QList<MediaInput*>& media, QUndoCommand* parent = nullptr);
OfflineFootageCommand(const QVector<MediaInput*>& media, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
+5 -5
View File
@@ -73,9 +73,9 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
ShaderJob shader_job;
shader_job.InsertValue(QStringLiteral("viewport"), ShaderValue(QVector2D(width(), height()), NodeParam::kVec2));
shader_job.InsertValue(QStringLiteral("histogram_scale"), ShaderValue(histogram_scale, NodeParam::kFloat));
shader_job.InsertValue(QStringLiteral("histogram_power"), ShaderValue(histogram_power, NodeParam::kFloat));
shader_job.InsertValue(QStringLiteral("viewport"), NodeValue(NodeValue::kVec2, QVector2D(width(), height())));
shader_job.InsertValue(QStringLiteral("histogram_scale"), NodeValue(NodeValue::kFloat, histogram_scale));
shader_job.InsertValue(QStringLiteral("histogram_power"), NodeValue(NodeValue::kFloat, histogram_power));
if (!texture_row_sums_
|| texture_row_sums_->width() != this->width()
@@ -86,11 +86,11 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
}
// Draw managed texture to a sums texture
shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
shader_job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex)));
renderer()->BlitToTexture(pipeline, shader_job, texture_row_sums_.get());
// Draw sums into a histogram
shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_row_sums_), NodeParam::kTexture));
shader_job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_row_sums_)));
renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params());
// Draw line overlays
+1 -1
View File
@@ -54,7 +54,7 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
{
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex)));
renderer()->Blit(pipeline, job, VideoParams(width(), height(),
static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt()),
+4 -4
View File
@@ -58,22 +58,22 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
// Set viewport size
job.InsertValue(QStringLiteral("viewport"),
ShaderValue(QVector2D(width(), height()), NodeParam::kVec2));
NodeValue(NodeValue::kVec2, QVector2D(width(), height())));
// Set luma coefficients
double luma_coeffs[3] = {0.0f, 0.0f, 0.0f};
color_manager()->GetDefaultLumaCoefs(luma_coeffs);
job.InsertValue(QStringLiteral("luma_coeffs"),
ShaderValue(QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3));
NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2])));
// Scale of the waveform relative to the viewport surface.
job.InsertValue(QStringLiteral("waveform_scale"),
ShaderValue(waveform_scale, NodeParam::kFloat));
NodeValue(NodeValue::kFloat, waveform_scale));
// Insert source texture
job.InsertValue(QStringLiteral("ove_maintex"),
ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex)));
renderer()->Blit(pipeline, job, VideoParams(width(), height(),
static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt()),
+22 -31
View File
@@ -469,7 +469,7 @@ void TimelineWidget::ReplaceBlocksWithGaps(const QVector<Block *> &blocks,
new TrackReplaceBlockWithGapCommand(original_track, b, command);
if (remove_from_graph) {
new NodeRemoveWithExclusiveDeps(static_cast<NodeGraph*>(b->parent()), b, command);
Node::RemoveNodesAndExclusiveDependencies(b, command);
}
}
}
@@ -509,9 +509,7 @@ void TimelineWidget::DeleteSelected(bool ripple)
transition,
command);
new NodeRemoveWithExclusiveDeps(static_cast<NodeGraph*>(GetConnectedNode()->parent()),
transition,
command);
Node::RemoveNodesAndExclusiveDependencies(transition, command);
}
// Replace clips with gaps (effectively deleting them)
@@ -910,37 +908,28 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track)
}
}
void TimelineWidget::RemoveBlock(const QList<Block *> &blocks)
void TimelineWidget::RemoveBlock(Block *b)
{
QVector<Block*> deselect_blocks;
// Disconnect all signals
disconnect(b, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed);
disconnect(b, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated);
disconnect(b, &Block::LabelChanged, this, &TimelineWidget::BlockUpdated);
disconnect(b, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated);
foreach (Block* b, blocks) {
// Disconnect all signals
disconnect(b, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed);
disconnect(b, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated);
disconnect(b, &Block::LabelChanged, this, &TimelineWidget::BlockUpdated);
disconnect(b, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated);
// Take item from map
TimelineViewBlockItem* item = block_items_.take(b);
// Take item from map
TimelineViewBlockItem* item = block_items_.take(b);
// If selected, deselect it
int select_index = selected_blocks_.indexOf(b);
if (select_index > -1) {
selected_blocks_.removeAt(select_index);
deselect_blocks.append(b);
RemoveSelection(item);
}
// Finally, delete item
delete item;
// If selected, deselect it
int select_index = selected_blocks_.indexOf(b);
if (select_index > -1) {
selected_blocks_.removeAt(select_index);
RemoveSelection(item);
}
if (!deselect_blocks.isEmpty()) {
// We already removed the blocks from selected_blocks_, so we can signal directly rather than
// through
emit BlocksDeselected(deselect_blocks);
}
// Finally, delete item
delete item;
emit BlocksDeselected({b});
}
void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type)
@@ -958,7 +947,9 @@ void TimelineWidget::RemoveTrack(TrackOutput *track)
disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
disconnect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated);
RemoveBlock(track->Blocks());
foreach (Block* b, track->Blocks()) {
RemoveBlock(b);
}
}
void TimelineWidget::TrackIndexChanged()
+1 -1
View File
@@ -281,7 +281,7 @@ private slots:
void ViewDragDropped(TimelineViewMouseEvent* event);
void AddBlock(Block* block, TrackReference track);
void RemoveBlock(const QList<Block*>& blocks);
void RemoveBlock(Block *blocks);
void AddTrack(TrackOutput* track, Timeline::TrackType type);
void RemoveTrack(TrackOutput* track);
+2 -2
View File
@@ -123,7 +123,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
solid,
command);
new NodeEdgeAddCommand(solid->output(), clip->texture_input(), command);
new NodeEdgeAddCommand(solid, clip->texture_input(), -1, command);
break;
}
case olive::Tool::kAddableTitle:
@@ -134,7 +134,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
text,
command);
new NodeEdgeAddCommand(text->output(), clip->texture_input(), command);
new NodeEdgeAddCommand(text, clip->texture_input(), -1, command);
break;
}
case olive::Tool::kAddableBars:
+4 -4
View File
@@ -435,8 +435,8 @@ void ImportTool::DropGhosts(bool insert)
TransformDistortNode* transform = new TransformDistortNode();
new NodeAddCommand(dst_graph, transform, command);
new NodeEdgeAddCommand(video_input->output(), transform->texture_input(), command);
new NodeEdgeAddCommand(transform->output(), clip->texture_input(), command);
new NodeEdgeAddCommand(video_input, transform->texture_input(), -1, command);
new NodeEdgeAddCommand(transform, clip->texture_input(), -1, command);
/*
MatrixGenerator* matrix = new MatrixGenerator();
@@ -461,8 +461,8 @@ void ImportTool::DropGhosts(bool insert)
VolumeNode* volume_node = new VolumeNode();
new NodeAddCommand(dst_graph, volume_node, command);
new NodeEdgeAddCommand(audio_input->output(), volume_node->samples_input(), command);
new NodeEdgeAddCommand(volume_node->output(), clip->texture_input(), command);
new NodeEdgeAddCommand(audio_input, volume_node->samples_input(), -1, command);
new NodeEdgeAddCommand(volume_node, clip->texture_input(), -1, command);
break;
}
default:
@@ -572,8 +572,6 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
QUndoCommand* command = new QUndoCommand();
new NodeGraphBeginOperationCommand(static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent()), command);
if (!blocks_trimming.isEmpty()) {
foreach (const GhostBlockPair& p, blocks_trimming) {
TimelineViewGhostItem* ghost = p.ghost;
@@ -730,8 +728,6 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
}
}
new NodeGraphEndOperationCommand(static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent()), command);
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
@@ -147,12 +147,14 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
Block* in_block = (ghost_->GetMode() == Timeline::kTrimIn) ? active_block : friend_block;
// Connect block to transition
new NodeEdgeAddCommand(out_block->output(),
new NodeEdgeAddCommand(out_block,
transition->out_block_input(),
-1,
command);
new NodeEdgeAddCommand(in_block->output(),
new NodeEdgeAddCommand(in_block,
transition->in_block_input(),
-1,
command);
} else {
Block* block_to_transition = Node::ValueToPtr<Block>(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock));
@@ -167,8 +169,9 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
}
// Connect block to transition
new NodeEdgeAddCommand(block_to_transition->output(),
new NodeEdgeAddCommand(block_to_transition,
transition_input_to_connect,
-1,
command);
}
+72 -63
View File
@@ -30,13 +30,6 @@
namespace olive {
Node* TakeNodeFromParentGraph(Node* n, QObject* new_parent = nullptr)
{
static_cast<NodeGraph*>(n->parent())->TakeNode(n, new_parent);
return n;
}
BlockResizeCommand::BlockResizeCommand(Block *block, rational new_length, QUndoCommand* parent) :
UndoCommand(parent),
block_(block),
@@ -266,7 +259,8 @@ void TrackRippleRemoveAreaCommand::redo_internal()
foreach (Block* remove_block, removed_blocks_) {
track_->RippleRemoveBlock(remove_block);
NodeRemoveWithExclusiveDeps* remove_command = new NodeRemoveWithExclusiveDeps(static_cast<NodeGraph*>(remove_block->parent()), remove_block);
QUndoCommand* remove_command = new QUndoCommand();
Node::RemoveNodesAndExclusiveDependencies(remove_block, remove_command);
remove_command->redo();
remove_block_commands_.append(remove_command);
}
@@ -295,7 +289,6 @@ void TrackRippleRemoveAreaCommand::redo_internal()
track_->EndOperation();
track_->Node::InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX),
track_->block_input(),
track_->block_input());
}
@@ -334,7 +327,7 @@ void TrackRippleRemoveAreaCommand::undo_internal()
// Restore blocks that were removed
for (int i=remove_block_commands_.size()-1;i>=0;i--) {
UndoCommand* command = remove_block_commands_.at(i);
QUndoCommand* command = remove_block_commands_.at(i);
command->undo();
delete command;
}
@@ -361,7 +354,7 @@ void TrackRippleRemoveAreaCommand::undo_internal()
track_->EndOperation();
track_->Node::InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX),
track_->block_input(), track_->block_input());
track_->block_input());
if (splice_split_command_) {
delete splice_split_command_;
@@ -385,13 +378,24 @@ Project *TrackPlaceBlockCommand::GetRelevantProject() const
void TrackPlaceBlockCommand::redo_internal()
{
added_track_count_ = 0;
// Determine if we need to add tracks
if (track_index_ >= timeline_->GetTracks().size()) {
if (added_tracks_.isEmpty()) {
// First redo, create tracks now
added_tracks_.resize(track_index_ - timeline_->GetTracks().size() + 1);
// Get track (or make it if necessary)
while (track_index_ >= timeline_->GetTracks().size()) {
timeline_->AddTrack();
for (int i=0; i<added_tracks_.size(); i++) {
added_tracks_[i] = new TrackOutput();
}
}
added_track_count_++;
for (int i=0; i<added_tracks_.size(); i++) {
TrackOutput* track = added_tracks_.at(i);
track->setParent(timeline_->GetParentGraph());
timeline_->track_input()->ArrayAppend();
Node::ConnectEdge(track, timeline_->track_input(), timeline_->track_input()->ArraySize() - 1);
}
}
track_ = timeline_->GetTrackAt(track_index_);
@@ -404,7 +408,7 @@ void TrackPlaceBlockCommand::redo_internal()
// If so, insert a gap here
gap_ = new GapBlock();
gap_->set_length_and_media_out(in_ - track_->track_length());
static_cast<NodeGraph*>(track_->parent())->AddNode(gap_);
gap_->setParent(track_->parent());
track_->AppendBlock(gap_);
}
@@ -424,14 +428,17 @@ void TrackPlaceBlockCommand::undo_internal()
if (gap_ != nullptr) {
track_->RippleRemoveBlock(gap_);
TakeNodeFromParentGraph(gap_, &memory_manager_);
gap_->setParent(&memory_manager_);
}
} else {
TrackRippleRemoveAreaCommand::undo_internal();
}
for (;added_track_count_>0;added_track_count_--) {
timeline_->RemoveTrack(&memory_manager_);
for (int i=added_tracks_.size()-1; i>=0; i--) {
TrackOutput* track = added_tracks_.at(i);
Node::DisconnectEdge(track, timeline_->track_input(), timeline_->track_input()->ArraySize() - 1);
track->setParent(&memory_manager_);
timeline_->track_input()->ArrayRemoveLast();
}
}
@@ -465,13 +472,16 @@ void BlockSplitCommand::redo_internal()
{
track_->BeginOperation();
NodeGraph* graph = static_cast<NodeGraph*>(block_->parent());
NodeGraph* graph = block_->parent();
add_command_ = new QUndoCommand();
new NodeAddCommand(graph, new_block_, add_command_);
new NodeCopyInputsCommand(block_, new_block_, true, add_command_);
if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) {
bool copy_dependencies_too = Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool();
new NodeCopyInputsCommand(block_, new_block_, !copy_dependencies_too, add_command_);
if (copy_dependencies_too) {
QVector<Node*> src_nodes;
QVector<Node*> dst_nodes;
@@ -502,8 +512,8 @@ void BlockSplitCommand::redo_internal()
track_->InsertBlockAfter(new_block_, block_);
foreach (NodeInput* transition, transitions_to_move_) {
NodeParam::DisconnectEdge(block_->output(), transition);
NodeParam::ConnectEdge(new_block_->output(), transition);
Node::DisconnectEdge(block_, transition);
Node::ConnectEdge(new_block_, transition);
}
track_->EndOperation();
@@ -514,8 +524,8 @@ void BlockSplitCommand::undo_internal()
track_->BeginOperation();
foreach (NodeInput* transition, transitions_to_move_) {
NodeParam::DisconnectEdge(new_block_->output(), transition);
NodeParam::ConnectEdge(block_->output(), transition);
Node::DisconnectEdge(new_block_, transition);
Node::ConnectEdge(block_, transition);
}
block_->set_length_and_media_out(old_length_);
@@ -929,7 +939,7 @@ void BlockTrimCommand::redo_internal()
adjacent_ = new GapBlock();
adjacent_->set_length_and_media_out(trim_diff);
static_cast<NodeGraph*>(track_->parent())->AddNode(adjacent_);
adjacent_->setParent(track_->parent());
if (mode_ == Timeline::kTrimIn) {
track_->InsertBlockBefore(adjacent_, block_);
@@ -948,7 +958,7 @@ void BlockTrimCommand::redo_internal()
if (adjacent_length.isNull()) {
// Ripple remove block
track_->RippleRemoveBlock(adjacent_);
TakeNodeFromParentGraph(adjacent_, &memory_manager_);
adjacent_->setParent(&memory_manager_);
we_deleted_adjacent_ = true;
} else if (mode_ == Timeline::kTrimIn) {
adjacent_->set_length_and_media_out(adjacent_length);
@@ -965,7 +975,7 @@ void BlockTrimCommand::redo_internal()
invalidate_range = TimeRange(block_->in(), block_->out());
}
track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(invalidate_range, track_->block_input());
}
void BlockTrimCommand::undo_internal()
@@ -987,7 +997,7 @@ void BlockTrimCommand::undo_internal()
if (we_created_adjacent_) {
// If we created a gap, just remove it straight up
track_->RippleRemoveBlock(adjacent_);
TakeNodeFromParentGraph(adjacent_, &memory_manager_);
adjacent_->setParent(&memory_manager_);
adjacent_ = nullptr;
we_created_adjacent_ = false;
} else if (adjacent_) {
@@ -999,7 +1009,7 @@ void BlockTrimCommand::undo_internal()
// If trimmed LONGER, we adjusted an existing block
// (assume if there's no adjacent, we're at the end of the timeline and do nothing)
if (we_deleted_adjacent_) {
static_cast<NodeGraph*>(track_->parent())->AddNode(adjacent_);
adjacent_->setParent(track_->parent());
if (mode_ == Timeline::kTrimIn) {
track_->InsertBlockBefore(adjacent_, block_);
@@ -1032,7 +1042,7 @@ void BlockTrimCommand::undo_internal()
track_->EndOperation();
track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(invalidate_range, track_->block_input());
}
TrackReplaceBlockWithGapCommand::TrackReplaceBlockWithGapCommand(TrackOutput *track, Block *block, QUndoCommand *command) :
@@ -1074,7 +1084,7 @@ void TrackReplaceBlockWithGapCommand::redo_internal()
existing_merged_gap_ = static_cast<GapBlock*>(next);
new_gap_length += existing_merged_gap_->length();
track_->RippleRemoveBlock(existing_merged_gap_);
TakeNodeFromParentGraph(existing_merged_gap_, &memory_manager_);
existing_merged_gap_->setParent(&memory_manager_);
} else if (previous_is_a_gap) {
// Extend this gap to fill space left by block
existing_gap_ = static_cast<GapBlock*>(previous);
@@ -1094,7 +1104,7 @@ void TrackReplaceBlockWithGapCommand::redo_internal()
// No gap exists to fill this space, create a new one and swap it in
our_gap_ = new GapBlock();
our_gap_->set_length_and_media_out(new_gap_length);
static_cast<NodeGraph*>(track_->parent())->AddNode(our_gap_);
our_gap_->setParent(track_->parent());
track_->ReplaceBlock(block_, our_gap_);
}
@@ -1105,7 +1115,7 @@ void TrackReplaceBlockWithGapCommand::redo_internal()
Block* preceding = block_->previous();
if (preceding && preceding->type() == Block::kGap) {
track_->RippleRemoveBlock(preceding);
TakeNodeFromParentGraph(preceding, &memory_manager_);
preceding->setParent(&memory_manager_);
existing_merged_gap_ = static_cast<GapBlock*>(preceding);
}
@@ -1116,7 +1126,7 @@ void TrackReplaceBlockWithGapCommand::redo_internal()
track_->EndOperation();
track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(invalidate_range, track_->block_input());
}
void TrackReplaceBlockWithGapCommand::undo_internal()
@@ -1127,7 +1137,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
// We made this gap, simply swap our gap back
track_->ReplaceBlock(our_gap_, block_);
TakeNodeFromParentGraph(our_gap_, &memory_manager_);
our_gap_->setParent(&memory_manager_);
our_gap_ = nullptr;
} else if (existing_gap_) {
@@ -1138,7 +1148,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
// If we merged two gaps together, restore the second one now
if (existing_merged_gap_) {
original_gap_length -= existing_merged_gap_->length();
static_cast<NodeGraph*>(track_->parent())->AddNode(existing_merged_gap_);
existing_merged_gap_->setParent(track_->parent());
track_->InsertBlockAfter(existing_merged_gap_, existing_gap_);
existing_merged_gap_ = nullptr;
}
@@ -1162,7 +1172,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
// However, we may have removed an unnecessary gap that preceded it
if (existing_merged_gap_) {
static_cast<NodeGraph*>(track_->parent())->AddNode(existing_merged_gap_);
existing_merged_gap_->setParent(track_->parent());
track_->AppendBlock(existing_merged_gap_);
existing_merged_gap_ = nullptr;
}
@@ -1174,7 +1184,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
track_->EndOperation();
track_->Node::InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input());
}
TrackSlideCommand::TrackSlideCommand(TrackOutput* track, const QList<Block*>& moving_blocks, Block *in_adjacent, Block *out_adjacent, const rational& movement, QUndoCommand* parent) :
@@ -1218,12 +1228,12 @@ void TrackSlideCommand::slide_internal(bool undo)
if (we_created_in_adjacent_) {
// This is a gap we made, we can just delete it entirely
track_->RippleRemoveBlock(in_adjacent_);
TakeNodeFromParentGraph(in_adjacent_, &memory_manager_);
in_adjacent_->setParent(&memory_manager_);
we_created_in_adjacent_ = false;
in_adjacent_ = nullptr;
} else if (in_adjacent_->parent() == &memory_manager_) {
// This is a gap we removed, we can re-insert it now
static_cast<NodeGraph*>(track_->parent())->AddNode(in_adjacent_);
in_adjacent_->setParent(track_->parent());
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
} else {
// We must have just resized this block
@@ -1233,7 +1243,7 @@ void TrackSlideCommand::slide_internal(bool undo)
if (we_created_out_adjacent_) {
// This is a gap we made, we can just delete it entirely
track_->RippleRemoveBlock(out_adjacent_);
TakeNodeFromParentGraph(out_adjacent_, &memory_manager_);
out_adjacent_->setParent(&memory_manager_);
we_created_out_adjacent_ = false;
out_adjacent_ = nullptr;
} else if (out_adjacent_) {
@@ -1241,7 +1251,7 @@ void TrackSlideCommand::slide_internal(bool undo)
// to check here
if (out_adjacent_->parent() == &memory_manager_) {
// This is a gap we removed, we can re-insert it now
static_cast<NodeGraph*>(track_->parent())->AddNode(out_adjacent_);
out_adjacent_->setParent(track_->parent());
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
} else {
// We must have just resized this block
@@ -1257,14 +1267,14 @@ void TrackSlideCommand::slide_internal(bool undo)
// be created
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(movement_);
static_cast<NodeGraph*>(track_->parent())->AddNode(gap);
gap->setParent(track_->parent());
track_->InsertBlockBefore(gap, blocks_.first());
we_created_in_adjacent_ = true;
in_adjacent_ = gap;
} else if (-movement_ == in_adjacent_->length()) {
// Remove in adjacent entirely
track_->RippleRemoveBlock(in_adjacent_);
TakeNodeFromParentGraph(in_adjacent_, &memory_manager_);
in_adjacent_->setParent(&memory_manager_);
} else {
// Resize in adjacent
in_adjacent_->set_length_and_media_out(in_adjacent_->length() + movement_);
@@ -1276,7 +1286,7 @@ void TrackSlideCommand::slide_internal(bool undo)
if (blocks_.last()->next()) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(-movement_);
static_cast<NodeGraph*>(track_->parent())->AddNode(gap);
gap->setParent(track_->parent());
track_->InsertBlockAfter(gap, blocks_.last());
we_created_out_adjacent_ = true;
out_adjacent_ = gap;
@@ -1284,7 +1294,7 @@ void TrackSlideCommand::slide_internal(bool undo)
} else if (movement_ == out_adjacent_->length()) {
// Remove out adjacent entirely
track_->RippleRemoveBlock(out_adjacent_);
TakeNodeFromParentGraph(out_adjacent_, &memory_manager_);
out_adjacent_->setParent(&memory_manager_);
} else {
// Resize out adjacent
out_adjacent_->set_length_and_media_in(out_adjacent_->length() - movement_);
@@ -1298,7 +1308,7 @@ void TrackSlideCommand::slide_internal(bool undo)
invalidate_range.set_range(qMin(invalidate_range.in(), blocks_.first()->in()),
qMax(invalidate_range.out(), blocks_.last()->out()));
track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(invalidate_range, track_->block_input());
}
TrackListRippleRemoveAreaCommand::TrackListRippleRemoveAreaCommand(TrackList *list, rational in, rational out, QUndoCommand *parent) :
@@ -1465,13 +1475,13 @@ void TrackListRippleToolCommand::redo_internal()
// Assume the Block was a Gap and it was reduced to zero length, remove it here
working_data_[i].removed_gap_after = b->previous();
info.track->RippleRemoveBlock(b);
TakeNodeFromParentGraph(b, &memory_manager_);
b->setParent(&memory_manager_);
}
} else if (info.new_length > 0) {
// This is a gap we are creating
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(info.new_length);
static_cast<NodeGraph*>(info.ref_block->parent())->AddNode(gap);
gap->setParent(info.ref_block->parent());
working_data_[i].created_gap = gap;
info.track->InsertBlockAfter(gap, info.ref_block);
@@ -1508,7 +1518,6 @@ void TrackListRippleToolCommand::redo_internal()
// FIXME: Untested, is this desirable behavior?
if (earliest_pt < new_latest_pt) {
info.track->InvalidateCache(TimeRange(earliest_pt, new_latest_pt),
info.track->block_input(),
info.track->block_input());
}
}
@@ -1538,7 +1547,7 @@ void TrackListRippleToolCommand::undo_internal()
// Assume the Block was a Gap and it was reduced to zero length, remove it here
Block* previous_block = working_data_[i].removed_gap_after;
static_cast<NodeGraph*>(info.track->parent())->AddNode(b);
b->setParent(info.track->parent());
if (previous_block) {
info.track->InsertBlockAfter(b, previous_block);
@@ -1551,7 +1560,7 @@ void TrackListRippleToolCommand::undo_internal()
GapBlock* gap = working_data_.at(i).created_gap;
info.track->RippleRemoveBlock(gap);
TakeNodeFromParentGraph(gap, &memory_manager_);
gap->setParent(&memory_manager_);
}
}
}
@@ -1627,7 +1636,7 @@ void TrackListInsertGaps::redo_internal()
foreach (Block* block, blocks_to_append_gap_to) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(length_);
static_cast<NodeGraph*>(block->parent())->AddNode(gap);
gap->setParent(block->parent());
TrackOutput::TrackFromBlock(block)->InsertBlockAfter(gap, block);
gaps_added_.append(gap);
}
@@ -1657,7 +1666,7 @@ void TrackListInsertGaps::undo_internal()
// Remove added gaps
foreach (GapBlock* gap, gaps_added_) {
TrackOutput::TrackFromBlock(gap)->RippleRemoveBlock(gap);
TakeNodeFromParentGraph(gap, &memory_manager_);
gap->setParent(&memory_manager_);
}
gaps_added_.clear();
@@ -1712,18 +1721,18 @@ void TransitionRemoveCommand::redo_internal()
}
if (in_block_) {
NodeParam::DisconnectEdge(in_block_->output(), block_->in_block_input());
Node::DisconnectEdge(in_block_, block_->in_block_input());
}
if (out_block_) {
NodeParam::DisconnectEdge(out_block_->output(), block_->out_block_input());
Node::DisconnectEdge(out_block_, block_->out_block_input());
}
track_->RippleRemoveBlock(block_);
track_->EndOperation();
track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(invalidate_range, track_->block_input());
}
void TransitionRemoveCommand::undo_internal()
@@ -1737,11 +1746,11 @@ void TransitionRemoveCommand::undo_internal()
}
if (in_block_) {
NodeParam::ConnectEdge(in_block_->output(), block_->in_block_input());
Node::ConnectEdge(in_block_, block_->in_block_input());
}
if (out_block_) {
NodeParam::ConnectEdge(out_block_->output(), block_->out_block_input());
Node::ConnectEdge(out_block_, block_->out_block_input());
}
// These if statements must be separated because in_offset and out_offset report different things
@@ -1757,7 +1766,7 @@ void TransitionRemoveCommand::undo_internal()
track_->EndOperation();
track_->InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input(), track_->block_input());
track_->Node::InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input());
}
TimelineSetSelectionsCommand::TimelineSetSelectionsCommand(TimelineWidget *timeline, const TimelineWidgetSelections &now, const TimelineWidgetSelections &old, QUndoCommand *parent) :
+3 -2
View File
@@ -208,7 +208,7 @@ protected:
QObject memory_manager_;
QList<UndoCommand*> remove_block_commands_;
QVector<QUndoCommand*> remove_block_commands_;
};
@@ -312,7 +312,8 @@ private:
int track_index_;
bool append_;
GapBlock* gap_;
int added_track_count_;
QVector<TrackOutput*> added_tracks_;
};
class BlockSplitCommand : public UndoCommand {
+4 -4
View File
@@ -45,22 +45,22 @@ void TimeTargetObject::SetPathIndex(int index)
path_index_ = index;
}
rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, NodeParam::Type direction) const
rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, bool input_direction) const
{
if (!from || !to) {
return r;
}
return GetAdjustedTime(from, to, TimeRange(r, r), direction).in();
return GetAdjustedTime(from, to, TimeRange(r, r), input_direction).in();
}
TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, NodeParam::Type direction) const
TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, bool input_direction) const
{
if (!from || !to) {
return r;
}
QVector<TimeRange> adjusted = from->TransformTimeTo(r, to, direction);
QVector<TimeRange> adjusted = from->TransformTimeTo(r, to, input_direction);
if (adjusted.isEmpty()) {
return r;
+2 -2
View File
@@ -35,8 +35,8 @@ public:
void SetPathIndex(int index);
rational GetAdjustedTime(Node* from, Node* to, const rational& r, NodeParam::Type direction) const;
TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, NodeParam::Type direction) const;
rational GetAdjustedTime(Node* from, Node* to, const rational& r, bool input_direction) const;
TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, bool input_direction) const;
//int GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const;
+6 -6
View File
@@ -33,10 +33,10 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
footage_(nullptr)
{
video_node_ = new MediaInput();
sequence_.AddNode(video_node_);
video_node_->setParent(&sequence_);
audio_node_ = new MediaInput();
sequence_.AddNode(audio_node_);
audio_node_->setParent(&sequence_);
connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
@@ -60,8 +60,8 @@ void FootageViewerWidget::SetFootage(Footage *footage)
video_node_->SetStream(nullptr);
audio_node_->SetStream(nullptr);
NodeParam::DisconnectEdge(video_node_->output(), sequence_.viewer_output()->texture_input());
NodeParam::DisconnectEdge(audio_node_->output(), sequence_.viewer_output()->samples_input());
Node::DisconnectEdge(video_node_, sequence_.viewer_output()->texture_input());
Node::DisconnectEdge(audio_node_, sequence_.viewer_output()->samples_input());
}
footage_ = footage;
@@ -98,12 +98,12 @@ void FootageViewerWidget::SetFootage(Footage *footage)
if (video_stream) {
video_node_->SetStream(video_stream);
NodeParam::ConnectEdge(video_node_->output(), sequence_.viewer_output()->texture_input());
Node::ConnectEdge(video_node_, sequence_.viewer_output()->texture_input());
}
if (audio_stream) {
audio_node_->SetStream(audio_stream);
NodeParam::ConnectEdge(audio_node_->output(), sequence_.viewer_output()->samples_input());
Node::ConnectEdge(audio_node_, sequence_.viewer_output()->samples_input());
}
ConnectViewerNode(sequence_.viewer_output(), footage_->project()->color_manager());
+6 -4
View File
@@ -178,7 +178,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
connect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
connect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange);
connect(n->video_frame_cache(), &FrameHashCache::Shifted, this, &ViewerWidget::ViewerShiftedRange);
connect(n, &ViewerOutput::GraphChangedFrom, this, &ViewerWidget::UpdateStack);
connect(n->texture_input(), &NodeInput::InputConnected, this, &ViewerWidget::UpdateStack);
connect(n->texture_input(), &NodeInput::InputDisconnected, this, &ViewerWidget::UpdateStack);
InterlacingChangedSlot(n->video_params().interlacing());
@@ -232,7 +233,8 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
disconnect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
disconnect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange);
disconnect(n->video_frame_cache(), &FrameHashCache::Shifted, this, &ViewerWidget::ViewerShiftedRange);
disconnect(n, &ViewerOutput::GraphChangedFrom, this, &ViewerWidget::UpdateStack);
disconnect(n->texture_input(), &NodeInput::InputConnected, this, &ViewerWidget::UpdateStack);
disconnect(n->texture_input(), &NodeInput::InputDisconnected, this, &ViewerWidget::UpdateStack);
ruler()->SetPlaybackCache(nullptr);
@@ -396,8 +398,8 @@ void ViewerWidget::DecodeCachedImage(RenderTicketPtr ticket, const QString &fn,
bool ViewerWidget::ShouldForceWaveform() const
{
return GetConnectedNode()
&& !GetConnectedNode()->texture_input()->is_connected()
&& GetConnectedNode()->samples_input()->is_connected();
&& !GetConnectedNode()->texture_input()->IsConnected()
&& GetConnectedNode()->samples_input()->IsConnected();
}
void ViewerWidget::UpdateTextureFromNode(const rational& time)
+3 -3
View File
@@ -280,8 +280,8 @@ void ViewerDisplayWidget::OnPaint()
}
ShaderJob job;
job.InsertValue(QStringLiteral("resolution_in"), ShaderValue(QVector2D(texture_to_draw->width(), texture_to_draw->height()), NodeParam::kVec2));
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_to_draw), NodeParam::kTexture));
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
@@ -375,7 +375,7 @@ QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y
rational ViewerDisplayWidget::GetGizmoTime()
{
return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput);
return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, true);
}
bool ViewerDisplayWidget::IsHandDrag(QMouseEvent *event) const