implement keyframe track separation in curve view
This commit is contained in:
@@ -834,4 +834,9 @@ QVariant NodeInput::StringToValue(const QString &string, QList<XMLNodeData::Foot
|
||||
return NodeValue::StringToValue(data_type_, string, true);
|
||||
}
|
||||
|
||||
uint qHash(const NodeInput::KeyframeTrackReference &ref, uint seed)
|
||||
{
|
||||
return qHash(ref.input, seed) ^ qHash(ref.element, seed) ^ qHash(ref.track, seed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -338,6 +338,17 @@ public:
|
||||
return GetImmediate(element)->get_closest_keyframe_after_time(time);
|
||||
}
|
||||
|
||||
struct KeyframeTrackReference {
|
||||
NodeInput* input;
|
||||
int element;
|
||||
int track;
|
||||
|
||||
bool operator==(const KeyframeTrackReference& rhs) const
|
||||
{
|
||||
return input == rhs.input && element == rhs.element && track == rhs.track;
|
||||
}
|
||||
};
|
||||
|
||||
signals:
|
||||
void NameChanged(const QString& name);
|
||||
|
||||
@@ -471,6 +482,8 @@ private slots:
|
||||
|
||||
};
|
||||
|
||||
uint qHash(const NodeInput::KeyframeTrackReference& ref, uint seed = 0);
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEINPUT_H
|
||||
|
||||
@@ -61,49 +61,45 @@ void CurveView::Clear()
|
||||
lines_.clear();
|
||||
}
|
||||
|
||||
void CurveView::ConnectInput(NodeInput *input)
|
||||
void CurveView::ConnectInput(NodeInput *input, int element, int track)
|
||||
{
|
||||
if (connected_inputs_.contains(input)) {
|
||||
NodeInput::KeyframeTrackReference ref = {input, element, track};
|
||||
|
||||
if (connected_inputs_.contains(ref)) {
|
||||
// Input wasn't connected, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Add keyframes from each subelement including primary (-1)
|
||||
for (int i=-1; i<input->ArraySize(); i++) {
|
||||
ConnectInputElement(input, i);
|
||||
// Add keyframes from track
|
||||
foreach (NodeKeyframe* key, input->GetKeyframeTracks(element).at(track)) {
|
||||
this->AddKeyframe(key);
|
||||
}
|
||||
|
||||
if (!keyframe_colors_.contains(ref)) {
|
||||
// Generate a random color for this input
|
||||
keyframe_colors_.insert(ref, QColor::fromHsv(std::rand()%360, std::rand()%255, 255));
|
||||
}
|
||||
|
||||
// Append to the list
|
||||
connected_inputs_.append(input);
|
||||
|
||||
// Connect add/remove signals
|
||||
connect(input, &NodeInput::KeyframeAdded, this, &CurveView::AddKeyframe);
|
||||
connect(input, &NodeInput::KeyframeRemoved, this, &CurveView::RemoveKeyframe);
|
||||
connected_inputs_.append(ref);
|
||||
}
|
||||
|
||||
void CurveView::DisconnectNode(Node *node)
|
||||
void CurveView::DisconnectInput(NodeInput *input, int element, int track)
|
||||
{
|
||||
foreach (NodeInput* i, node->parameters()) {
|
||||
DisconnectInput(i);
|
||||
}
|
||||
}
|
||||
NodeInput::KeyframeTrackReference ref = {input, element, track};
|
||||
|
||||
void CurveView::DisconnectInput(NodeInput *input)
|
||||
{
|
||||
if (!connected_inputs_.contains(input)) {
|
||||
if (!connected_inputs_.contains(ref)) {
|
||||
// Input wasn't connected, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove keyframes belonging to this input
|
||||
RemoveKeyframesOfInput(input);
|
||||
// Remove keyframes belonging to this element and track
|
||||
foreach (NodeKeyframe* key, input->GetKeyframeTracks(element).at(track)) {
|
||||
RemoveKeyframe(key);
|
||||
}
|
||||
|
||||
// Remove from the list
|
||||
connected_inputs_.removeOne(input);
|
||||
|
||||
// Disconnect add/remove signals
|
||||
disconnect(input, &NodeInput::KeyframeAdded, this, &CurveView::AddKeyframe);
|
||||
disconnect(input, &NodeInput::KeyframeRemoved, this, &CurveView::RemoveKeyframe);
|
||||
connected_inputs_.removeOne(ref);
|
||||
}
|
||||
|
||||
void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
@@ -157,91 +153,89 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
painter->drawLines(lines);
|
||||
|
||||
// Draw keyframe lines
|
||||
foreach (NodeInput* input, connected_inputs_) {
|
||||
for (int j=-1; j<input->ArraySize(); j++) {
|
||||
if (input->IsKeyframing(j)) {
|
||||
const QVector<NodeKeyframeTrack>& tracks = input->GetKeyframeTracks(j);
|
||||
foreach (const NodeInput::KeyframeTrackReference& ref, connected_inputs_) {
|
||||
NodeInput* input = ref.input;
|
||||
|
||||
for (int k=0; k<tracks.size(); k++) {
|
||||
const NodeKeyframeTrack& track = tracks.at(k);
|
||||
if (input->IsKeyframing(ref.element)) {
|
||||
const QVector<NodeKeyframeTrack>& tracks = input->GetKeyframeTracks(ref.element);
|
||||
|
||||
if (!track.isEmpty()) {
|
||||
painter->setPen(QPen(keyframe_colors_.value(GetKeyframeTrackUniqueID(input, j, k)),
|
||||
qMax(1, fontMetrics().height() / 4)));
|
||||
const NodeKeyframeTrack& track = tracks.at(ref.track);
|
||||
|
||||
QVector<QLineF> keyframe_lines;
|
||||
if (!track.isEmpty()) {
|
||||
painter->setPen(QPen(keyframe_colors_.value(ref),
|
||||
qMax(1, fontMetrics().height() / 4)));
|
||||
|
||||
// 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));
|
||||
QVector<QLineF> keyframe_lines;
|
||||
|
||||
// Draw lines between each keyframe
|
||||
for (int i=1;i<track.size();i++) {
|
||||
NodeKeyframe* before = track.at(i-1);
|
||||
NodeKeyframe* after = track.at(i);
|
||||
// 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));
|
||||
|
||||
KeyframeViewItem* before_item = item_map().value(before);
|
||||
KeyframeViewItem* after_item = item_map().value(after);
|
||||
// Draw lines between each keyframe
|
||||
for (int i=1;i<track.size();i++) {
|
||||
NodeKeyframe* before = track.at(i-1);
|
||||
NodeKeyframe* after = track.at(i);
|
||||
|
||||
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
|
||||
KeyframeViewItem* before_item = item_map().value(before);
|
||||
KeyframeViewItem* after_item = item_map().value(after);
|
||||
|
||||
// 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());
|
||||
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
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo(before_item->pos());
|
||||
path.cubicTo(before_control_point, after_control_point, after_item->pos());
|
||||
painter->drawPath(path);
|
||||
// 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());
|
||||
|
||||
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
|
||||
// Draw a quadratic bezier
|
||||
QPainterPath path;
|
||||
path.moveTo(before_item->pos());
|
||||
path.cubicTo(before_control_point, after_control_point, after_item->pos());
|
||||
painter->drawPath(path);
|
||||
|
||||
// Quadratic beziers have a single control point, we just have to determine which it is
|
||||
QPointF key_anchor;
|
||||
QPointF control_point;
|
||||
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
|
||||
// Draw a quadratic bezier
|
||||
|
||||
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();
|
||||
}
|
||||
// Quadratic beziers have a single control point, we just have to determine which it is
|
||||
QPointF key_anchor;
|
||||
QPointF control_point;
|
||||
|
||||
// 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()));
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
// 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())));
|
||||
// Scale control point
|
||||
control_point = key_anchor + ScalePoint(control_point);
|
||||
|
||||
painter->drawLines(keyframe_lines);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,26 +299,6 @@ 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());
|
||||
@@ -359,11 +333,6 @@ 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());
|
||||
@@ -449,7 +418,7 @@ void CurveView::AddKeyframe(NodeKeyframe* key)
|
||||
{
|
||||
KeyframeViewItem* item = AddKeyframeInternal(key);
|
||||
SetItemYFromKeyframeValue(key, item);
|
||||
item->SetOverrideBrush(keyframe_colors_.value(GetKeyframeTrackUniqueID(key->parent(), key->element(), key->track())));
|
||||
item->SetOverrideBrush(keyframe_colors_.value({key->parent(), key->element(), key->track()}));
|
||||
|
||||
connect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
|
||||
connect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged);
|
||||
|
||||
@@ -38,11 +38,9 @@ public:
|
||||
|
||||
virtual void Clear() override;
|
||||
|
||||
void ConnectInput(NodeInput* input);
|
||||
void ConnectInput(NodeInput* input, int element, int track);
|
||||
|
||||
void DisconnectNode(Node* node);
|
||||
|
||||
void DisconnectInput(NodeInput* input);
|
||||
void DisconnectInput(NodeInput* input, int element, int track);
|
||||
|
||||
public slots:
|
||||
void AddKeyframe(NodeKeyframe* key);
|
||||
@@ -63,8 +61,6 @@ protected:
|
||||
virtual void ContextMenuEvent(Menu &m) override;
|
||||
|
||||
private:
|
||||
void ConnectInputElement(NodeInput* input, int element);
|
||||
|
||||
qreal GetItemYFromKeyframeValue(NodeKeyframe* key);
|
||||
qreal GetItemYFromKeyframeValue(double value);
|
||||
|
||||
@@ -76,19 +72,17 @@ private:
|
||||
|
||||
void CreateBezierControlPoints(KeyframeViewItem *item);
|
||||
|
||||
uint GetKeyframeTrackUniqueID(NodeInput* input, int element, int track);
|
||||
|
||||
QMap<uint, QColor> keyframe_colors_;
|
||||
QHash<NodeInput::KeyframeTrackReference, QColor> keyframe_colors_;
|
||||
|
||||
int text_padding_;
|
||||
|
||||
int minimum_grid_space_;
|
||||
|
||||
QList<QGraphicsLineItem*> lines_;
|
||||
QVector<QGraphicsLineItem*> lines_;
|
||||
|
||||
QList<BezierControlPointItem*> bezier_control_points_;
|
||||
QVector<BezierControlPointItem*> bezier_control_points_;
|
||||
|
||||
QList<NodeInput*> connected_inputs_;
|
||||
QVector<NodeInput::KeyframeTrackReference> connected_inputs_;
|
||||
|
||||
private slots:
|
||||
void KeyframeValueChanged();
|
||||
|
||||
@@ -44,8 +44,10 @@ CurveWidget::CurveWidget(QWidget *parent) :
|
||||
|
||||
tree_view_ = new NodeTreeView();
|
||||
tree_view_->SetOnlyShowKeyframable(true);
|
||||
tree_view_->SetShowKeyframeTracksAsRows(true);
|
||||
connect(tree_view_, &NodeTreeView::NodeEnableChanged, this, &CurveWidget::NodeEnabledChanged);
|
||||
connect(tree_view_, &NodeTreeView::InputEnableChanged, this, &CurveWidget::InputEnabledChanged);
|
||||
connect(tree_view_, &NodeTreeView::InputSelectionChanged, this, &CurveWidget::InputSelectionChanged);
|
||||
splitter->addWidget(tree_view_);
|
||||
|
||||
QWidget* workarea = new QWidget();
|
||||
@@ -137,14 +139,14 @@ void CurveWidget::SetNodes(const QVector<Node *> &nodes)
|
||||
// Detect removed nodes
|
||||
foreach (Node* n, nodes_) {
|
||||
if (!nodes.contains(n)) {
|
||||
view_->DisconnectNode(n);
|
||||
ConnectNode(n, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect added nodes
|
||||
foreach (Node* n, nodes) {
|
||||
if (tree_view_->IsNodeEnabled(n) && !nodes_.contains(n)) {
|
||||
ConnectNode(n);
|
||||
ConnectNode(n, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,18 +215,48 @@ void CurveWidget::UpdateBridgeTime(const int64_t ×tamp)
|
||||
key_control_->SetTime(time);
|
||||
}
|
||||
|
||||
void CurveWidget::ConnectNode(Node *n)
|
||||
void CurveWidget::ConnectNode(Node *node, bool connect)
|
||||
{
|
||||
foreach (NodeInput* i, n->parameters()) {
|
||||
if (tree_view_->IsInputEnabled(i)) {
|
||||
view_->ConnectInput(i);
|
||||
}
|
||||
foreach (NodeInput* input, node->parameters()) {
|
||||
ConnectInput(input, connect);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveWidget::DisconnectNode(Node *n)
|
||||
void CurveWidget::ConnectInput(NodeInput *input, bool connect)
|
||||
{
|
||||
view_->DisconnectNode(n);
|
||||
int track_count = NodeValue::get_number_of_keyframe_tracks(input->GetDataType());
|
||||
bool multiple_tracks = track_count > 1;
|
||||
|
||||
for (int i=-1; i<input->ArraySize(); i++) {
|
||||
if (tree_view_->IsInputEnabled(input, i, multiple_tracks ? -1 : 0)) {
|
||||
if (multiple_tracks) {
|
||||
for (int j=0; j<track_count; j++) {
|
||||
if (tree_view_->IsInputEnabled(input, i, j)) {
|
||||
if (connect) {
|
||||
view_->ConnectInput(input, i, j);
|
||||
} else {
|
||||
view_->DisconnectInput(input, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (connect) {
|
||||
view_->ConnectInput(input, i, 0);
|
||||
} else {
|
||||
view_->DisconnectInput(input, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect add/remove signals
|
||||
if (connect) {
|
||||
QObject::connect(input, &NodeInput::KeyframeAdded, this, &CurveWidget::AddKeyframe);
|
||||
QObject::connect(input, &NodeInput::KeyframeRemoved, this, &CurveWidget::RemoveKeyframe);
|
||||
} else {
|
||||
QObject::disconnect(input, &NodeInput::KeyframeAdded, this, &CurveWidget::AddKeyframe);
|
||||
QObject::disconnect(input, &NodeInput::KeyframeRemoved, this, &CurveWidget::RemoveKeyframe);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveWidget::SelectionChanged()
|
||||
@@ -303,20 +335,33 @@ void CurveWidget::KeyControlRequestedTimeChanged(const rational &time)
|
||||
|
||||
void CurveWidget::NodeEnabledChanged(Node* n, bool e)
|
||||
{
|
||||
if (e) {
|
||||
ConnectNode(n);
|
||||
} else {
|
||||
DisconnectNode(n);
|
||||
}
|
||||
ConnectNode(n, e);
|
||||
}
|
||||
|
||||
void CurveWidget::InputEnabledChanged(NodeInput *i, bool e)
|
||||
void CurveWidget::InputEnabledChanged(NodeInput *i, int element, int track, bool e)
|
||||
{
|
||||
if (e) {
|
||||
view_->ConnectInput(i);
|
||||
view_->ConnectInput(i, element, track);
|
||||
} else {
|
||||
view_->DisconnectInput(i);
|
||||
view_->DisconnectInput(i, element, track);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveWidget::AddKeyframe(NodeKeyframe *key)
|
||||
{
|
||||
view_->AddKeyframe(key);
|
||||
}
|
||||
|
||||
void CurveWidget::RemoveKeyframe(NodeKeyframe *key)
|
||||
{
|
||||
view_->RemoveKeyframe(key);
|
||||
}
|
||||
|
||||
void CurveWidget::InputSelectionChanged(NodeInput *input, int element, int track)
|
||||
{
|
||||
Q_UNUSED(track)
|
||||
|
||||
key_control_->SetInput(input, element);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,9 +69,9 @@ private:
|
||||
|
||||
void UpdateBridgeTime(const int64_t& timestamp);
|
||||
|
||||
void ConnectNode(Node* n);
|
||||
void ConnectNode(Node* node, bool connect);
|
||||
|
||||
void DisconnectNode(Node* n);
|
||||
void ConnectInput(NodeInput* input, bool connect);
|
||||
|
||||
NodeTreeView* tree_view_;
|
||||
|
||||
@@ -96,7 +96,13 @@ private slots:
|
||||
|
||||
void NodeEnabledChanged(Node* n, bool e);
|
||||
|
||||
void InputEnabledChanged(NodeInput* i, bool e);
|
||||
void InputEnabledChanged(NodeInput* i, int element, int track, bool e);
|
||||
|
||||
void AddKeyframe(NodeKeyframe* key);
|
||||
|
||||
void RemoveKeyframe(NodeKeyframe* key);
|
||||
|
||||
void InputSelectionChanged(NodeInput* input, int element, int track);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ namespace olive {
|
||||
|
||||
NodeTreeView::NodeTreeView(QWidget *parent) :
|
||||
QTreeWidget(parent),
|
||||
only_show_keyframable_(false)
|
||||
only_show_keyframable_(false),
|
||||
show_keyframe_tracks_as_rows_(false)
|
||||
{
|
||||
connect(this, &NodeTreeView::itemChanged, this, &NodeTreeView::ItemCheckStateChanged);
|
||||
connect(this, &NodeTreeView::itemSelectionChanged, this, &NodeTreeView::SelectionChanged);
|
||||
|
||||
Retranslate();
|
||||
}
|
||||
@@ -16,9 +18,9 @@ bool NodeTreeView::IsNodeEnabled(Node *n) const
|
||||
return !disabled_nodes_.contains(n);
|
||||
}
|
||||
|
||||
bool NodeTreeView::IsInputEnabled(NodeInput *i) const
|
||||
bool NodeTreeView::IsInputEnabled(NodeInput *i, int element, int track) const
|
||||
{
|
||||
return !disabled_inputs_.contains(i);
|
||||
return !disabled_inputs_.contains({i, element, track});
|
||||
}
|
||||
|
||||
void NodeTreeView::SetNodes(const QVector<Node *> &nodes)
|
||||
@@ -34,16 +36,32 @@ void NodeTreeView::SetNodes(const QVector<Node *> &nodes)
|
||||
node_item->setData(0, kItemType, kItemTypeNode);
|
||||
node_item->setData(0, kItemPointer, reinterpret_cast<quintptr>(n));
|
||||
|
||||
foreach (NodeInput* i, n->inputs()) {
|
||||
if (only_show_keyframable_ && !i->IsKeyframable()) {
|
||||
foreach (NodeInput* input, n->inputs()) {
|
||||
if (only_show_keyframable_ && !input->IsKeyframable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* input_item = new QTreeWidgetItem(node_item);
|
||||
input_item->setText(0, i->name());
|
||||
input_item->setCheckState(0, disabled_inputs_.contains(i) ? Qt::Unchecked : Qt::Checked);
|
||||
input_item->setData(0, kItemType, kItemTypeInput);
|
||||
input_item->setData(0, kItemPointer, reinterpret_cast<quintptr>(i));
|
||||
int type_track_count = NodeValue::get_number_of_keyframe_tracks(input->GetDataType());
|
||||
bool type_has_multiple_tracks = (type_track_count > 1);
|
||||
|
||||
QTreeWidgetItem* input_item = CreateItem(node_item, input, -1, type_has_multiple_tracks ? -1 : 0);
|
||||
|
||||
if (input->IsArray()) {
|
||||
for (int i=0; i<input->ArraySize(); i++) {
|
||||
QTreeWidgetItem* element_item = CreateItem(input_item, input, i, type_has_multiple_tracks ? -1 : 0);
|
||||
|
||||
if (type_has_multiple_tracks && show_keyframe_tracks_as_rows_) {
|
||||
for (int j=0; j<type_track_count; j++) {
|
||||
CreateItem(element_item, input, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type_has_multiple_tracks && show_keyframe_tracks_as_rows_) {
|
||||
for (int j=0; j<type_track_count; j++) {
|
||||
CreateItem(input_item, input, -1, j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add at the end to prevent unnecessary signalling while we're setting these objects up
|
||||
@@ -69,6 +87,42 @@ void NodeTreeView::Retranslate()
|
||||
setHeaderLabel(tr("Nodes"));
|
||||
}
|
||||
|
||||
QTreeWidgetItem* NodeTreeView::CreateItem(QTreeWidgetItem *parent, NodeInput *input, int element, int track)
|
||||
{
|
||||
QTreeWidgetItem* input_item = new QTreeWidgetItem(parent);
|
||||
|
||||
QString item_name;
|
||||
if (track == -1 || NodeValue::get_number_of_keyframe_tracks(input->GetDataType()) == 1) {
|
||||
item_name = input->name();
|
||||
} else {
|
||||
switch (track) {
|
||||
case 0:
|
||||
item_name = tr("X");
|
||||
break;
|
||||
case 1:
|
||||
item_name = tr("Y");
|
||||
break;
|
||||
case 2:
|
||||
item_name = tr("Z");
|
||||
break;
|
||||
case 3:
|
||||
item_name = tr("W");
|
||||
break;
|
||||
default:
|
||||
item_name = QString::number(track);
|
||||
}
|
||||
}
|
||||
input_item->setText(0, item_name);
|
||||
|
||||
input_item->setCheckState(0, disabled_inputs_.contains({input, element, track}) ? Qt::Unchecked : Qt::Checked);
|
||||
input_item->setData(0, kItemType, kItemTypeInput);
|
||||
input_item->setData(0, kItemPointer, reinterpret_cast<quintptr>(input));
|
||||
input_item->setData(0, kItemElement, element);
|
||||
input_item->setData(0, kItemTrack, track);
|
||||
|
||||
return input_item;
|
||||
}
|
||||
|
||||
void NodeTreeView::ItemCheckStateChanged(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
Q_UNUSED(column)
|
||||
@@ -91,20 +145,44 @@ void NodeTreeView::ItemCheckStateChanged(QTreeWidgetItem *item, int column)
|
||||
}
|
||||
case kItemTypeInput:
|
||||
{
|
||||
NodeInput* i = reinterpret_cast<NodeInput*>(item->data(0, kItemPointer).value<quintptr>());
|
||||
NodeInput* input = reinterpret_cast<NodeInput*>(item->data(0, kItemPointer).value<quintptr>());
|
||||
int element = item->data(0, kItemElement).toInt();
|
||||
int track = item->data(0, kItemTrack).toInt();
|
||||
NodeInput::KeyframeTrackReference i = {input, element, track};
|
||||
|
||||
if (item->checkState(0) == Qt::Checked) {
|
||||
if (disabled_inputs_.contains(i)) {
|
||||
disabled_inputs_.removeOne(i);
|
||||
emit InputEnableChanged(i, true);
|
||||
emit InputEnableChanged(input, element, track, true);
|
||||
}
|
||||
} else if (!disabled_inputs_.contains(i)) {
|
||||
disabled_inputs_.append(i);
|
||||
emit InputEnableChanged(i, false);
|
||||
emit InputEnableChanged(input, element, track, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeTreeView::SelectionChanged()
|
||||
{
|
||||
QList<QTreeWidgetItem*> sel = selectedItems();
|
||||
|
||||
NodeInput* selected_input = nullptr;
|
||||
int selected_element = -1;
|
||||
int selected_track = -1;
|
||||
|
||||
if (!sel.isEmpty()) {
|
||||
QTreeWidgetItem* item = sel.first();
|
||||
|
||||
if (item->data(0, kItemType).toInt() == kItemTypeInput) {
|
||||
selected_input = reinterpret_cast<NodeInput*>(item->data(0, kItemPointer).value<quintptr>());
|
||||
selected_element = item->data(0, kItemElement).toInt();
|
||||
selected_track = item->data(0, kItemTrack).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
emit InputSelectionChanged(selected_input, selected_element, selected_track);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,20 +15,27 @@ public:
|
||||
|
||||
bool IsNodeEnabled(Node* n) const;
|
||||
|
||||
bool IsInputEnabled(NodeInput* i) const;
|
||||
bool IsInputEnabled(NodeInput* i, int element, int track) const;
|
||||
|
||||
void SetOnlyShowKeyframable(bool e)
|
||||
{
|
||||
only_show_keyframable_ = e;
|
||||
}
|
||||
|
||||
void SetShowKeyframeTracksAsRows(bool e)
|
||||
{
|
||||
show_keyframe_tracks_as_rows_ = e;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void SetNodes(const QVector<Node *> &nodes);
|
||||
|
||||
signals:
|
||||
void NodeEnableChanged(Node* n, bool e);
|
||||
|
||||
void InputEnableChanged(NodeInput* i, bool e);
|
||||
void InputEnableChanged(NodeInput* i, int element, int track, bool e);
|
||||
|
||||
void InputSelectionChanged(NodeInput* input, int element, int track);
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent* e) override;
|
||||
@@ -36,6 +43,8 @@ protected:
|
||||
private:
|
||||
void Retranslate();
|
||||
|
||||
QTreeWidgetItem *CreateItem(QTreeWidgetItem* parent, NodeInput* input, int element, int track);
|
||||
|
||||
enum ItemType {
|
||||
kItemTypeNode,
|
||||
kItemTypeInput
|
||||
@@ -43,18 +52,24 @@ private:
|
||||
|
||||
static const int kItemType = Qt::UserRole;
|
||||
static const int kItemPointer = Qt::UserRole + 1;
|
||||
static const int kItemElement = Qt::UserRole + 2;
|
||||
static const int kItemTrack = Qt::UserRole + 3;
|
||||
|
||||
QVector<Node*> nodes_;
|
||||
|
||||
QVector<Node*> disabled_nodes_;
|
||||
|
||||
QVector<NodeInput*> disabled_inputs_;
|
||||
QVector<NodeInput::KeyframeTrackReference> disabled_inputs_;
|
||||
|
||||
bool only_show_keyframable_;
|
||||
|
||||
bool show_keyframe_tracks_as_rows_;
|
||||
|
||||
private slots:
|
||||
void ItemCheckStateChanged(QTreeWidgetItem* item, int column);
|
||||
|
||||
void SelectionChanged();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user