implemented base UI keyframe functionality
This commit implements much of the base functionality for creating and destroying keyframes in the UI. Not complete yet, but getting there.
This commit is contained in:
@@ -10,6 +10,23 @@ KeyframeView::KeyframeView(QWidget *parent) :
|
||||
setDragMode(QGraphicsView::RubberBandDrag);
|
||||
}
|
||||
|
||||
void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
|
||||
{
|
||||
QPoint global_pt(0, y);
|
||||
QPoint local_pt = mapFromGlobal(global_pt);
|
||||
QPointF scene_pt = mapToScene(local_pt);
|
||||
|
||||
KeyframeViewItem* item = new KeyframeViewItem(key, scene_pt.y());
|
||||
item->SetScale(scale_);
|
||||
item_map_.insert(key.get(), item);
|
||||
scene()->addItem(item);
|
||||
}
|
||||
|
||||
void KeyframeView::RemoveKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
delete item_map_.value(key.get());
|
||||
}
|
||||
|
||||
void KeyframeView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadPress(event)) {
|
||||
@@ -36,3 +53,12 @@ void KeyframeView::mouseReleaseEvent(QMouseEvent *event)
|
||||
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void KeyframeView::ScaleChangedEvent(double scale)
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
|
||||
|
||||
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
|
||||
iterator.value()->SetScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,24 @@
|
||||
|
||||
class KeyframeView : public TimelineViewBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyframeView(QWidget* parent = nullptr);
|
||||
|
||||
void AddKeyframe(const rational& time, int y);
|
||||
public slots:
|
||||
void AddKeyframe(NodeKeyframePtr key, int y);
|
||||
|
||||
void RemoveKeyframe(NodeKeyframePtr key);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
virtual void ScaleChangedEvent(double scale) override;
|
||||
|
||||
private:
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*> item_map_;
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEW_H
|
||||
|
||||
@@ -7,25 +7,18 @@
|
||||
|
||||
#include "common/qtversionabstraction.h"
|
||||
|
||||
KeyframeViewItem::KeyframeViewItem(QGraphicsItem *parent) :
|
||||
KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphicsItem *parent) :
|
||||
QGraphicsRectItem(parent),
|
||||
key_(nullptr),
|
||||
scale_(1.0)
|
||||
key_(key),
|
||||
scale_(1.0),
|
||||
middle_(vcenter)
|
||||
{
|
||||
keyframe_size_ = QFontMetricsWidth(qApp->fontMetrics(), "Oi");
|
||||
setFlag(QGraphicsItem::ItemIsSelectable);
|
||||
setFlag(QGraphicsItem::ItemIsMovable);
|
||||
}
|
||||
|
||||
void KeyframeViewItem::SetKeyframe(NodeKeyframe *key)
|
||||
{
|
||||
key_ = key;
|
||||
UpdateRect();
|
||||
}
|
||||
connect(key.get(), SIGNAL(TimeChanged(const rational&)), this, SLOT(UpdateRect()));
|
||||
|
||||
void KeyframeViewItem::SetVerticalCenter(int middle)
|
||||
{
|
||||
middle_ = middle;
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
@@ -37,10 +30,6 @@ void KeyframeViewItem::SetScale(double scale)
|
||||
|
||||
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
if (!key_) {
|
||||
return;
|
||||
}
|
||||
|
||||
painter->setPen(Qt::black);
|
||||
|
||||
if (option->state & QStyle::State_Selected) {
|
||||
@@ -73,10 +62,6 @@ void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
|
||||
|
||||
void KeyframeViewItem::UpdateRect()
|
||||
{
|
||||
if (!key_) {
|
||||
return;
|
||||
}
|
||||
|
||||
double x_center = key_->time().toDouble() * scale_;
|
||||
|
||||
setRect(x_center - keyframe_size_/2, middle_ - keyframe_size_/2, keyframe_size_, keyframe_size_);
|
||||
|
||||
@@ -5,14 +5,11 @@
|
||||
|
||||
#include "node/keyframe.h"
|
||||
|
||||
class KeyframeViewItem : public QGraphicsRectItem
|
||||
class KeyframeViewItem : public QObject, public QGraphicsRectItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyframeViewItem(QGraphicsItem *parent = nullptr);
|
||||
|
||||
void SetKeyframe(NodeKeyframe* key);
|
||||
|
||||
void SetVerticalCenter(int middle);
|
||||
KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphicsItem *parent = nullptr);
|
||||
|
||||
void SetScale(double scale);
|
||||
|
||||
@@ -20,15 +17,17 @@ protected:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
|
||||
private:
|
||||
void UpdateRect();
|
||||
|
||||
NodeKeyframe* key_;
|
||||
NodeKeyframePtr key_;
|
||||
|
||||
double scale_;
|
||||
|
||||
int middle_;
|
||||
qreal middle_;
|
||||
|
||||
int keyframe_size_;
|
||||
|
||||
private slots:
|
||||
void UpdateRect();
|
||||
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEWITEM_H
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QScrollArea>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
|
||||
NodeParamView::NodeParamView(QWidget *parent) :
|
||||
@@ -70,6 +71,8 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
// Connect ruler and keyframe view together
|
||||
connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), keyframe_view_, SLOT(SetTime(const int64_t&)));
|
||||
connect(keyframe_view_, SIGNAL(TimeChanged(const int64_t&)), ruler_, SLOT(SetTime(const int64_t&)));
|
||||
connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), this, SLOT(RulerTimeChanged(const int64_t&)));
|
||||
connect(keyframe_view_, SIGNAL(TimeChanged(const int64_t&)), this, SLOT(RulerTimeChanged(const int64_t&)));
|
||||
|
||||
splitter->addWidget(keyframe_area);
|
||||
|
||||
@@ -93,30 +96,16 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
|
||||
// For each node, create a widget
|
||||
foreach (Node* node, nodes_) {
|
||||
NodeParamViewItem* item = new NodeParamViewItem(node);
|
||||
|
||||
// See if we already have an item for this node type
|
||||
// Insert the widget before the stretch
|
||||
param_layout_->insertWidget(param_layout_->count() - 1, item);
|
||||
|
||||
bool merged_node = false;
|
||||
connect(item, SIGNAL(KeyframeAdded(NodeKeyframePtr, int)), keyframe_view_, SLOT(AddKeyframe(NodeKeyframePtr, int)));
|
||||
connect(item, SIGNAL(KeyframeRemoved(NodeKeyframePtr)), keyframe_view_, SLOT(RemoveKeyframe(NodeKeyframePtr)));
|
||||
connect(item, SIGNAL(RequestSetTime(const rational&)), this, SLOT(SetTime(const rational&)));
|
||||
|
||||
foreach (NodeParamViewItem* existing_item, items_) {
|
||||
if (existing_item->CanAddNode(node)) {
|
||||
existing_item->AttachNode(node);
|
||||
merged_node = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't merge this node into the existing item, create a new one
|
||||
if (!merged_node) {
|
||||
NodeParamViewItem* item = new NodeParamViewItem(this);
|
||||
|
||||
item->AttachNode(node);
|
||||
|
||||
// Insert the widget before the stretch
|
||||
param_layout_->insertWidget(param_layout_->count() - 1, item);
|
||||
|
||||
items_.append(item);
|
||||
}
|
||||
items_.append(item);
|
||||
}
|
||||
|
||||
if (!nodes_.isEmpty()) {
|
||||
@@ -126,6 +115,8 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
SetTimebase(viewer->video_params().time_base());
|
||||
}
|
||||
}
|
||||
|
||||
SetTime(0);
|
||||
}
|
||||
|
||||
const QList<Node *> &NodeParamView::nodes()
|
||||
@@ -144,8 +135,32 @@ void NodeParamView::SetScale(const double& scale)
|
||||
keyframe_view_->SetScale(scale);
|
||||
}
|
||||
|
||||
void NodeParamView::SetTime(const rational &time)
|
||||
{
|
||||
int64_t timestamp = olive::time_to_timestamp(time, keyframe_view_->timebase());
|
||||
|
||||
ruler_->SetTime(timestamp);
|
||||
keyframe_view_->SetTime(timestamp);
|
||||
|
||||
UpdateItemTime(time);
|
||||
}
|
||||
|
||||
void NodeParamView::SetTimebase(const rational &timebase)
|
||||
{
|
||||
ruler_->SetTimebase(timebase);
|
||||
keyframe_view_->SetTimebase(timebase);
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateItemTime(const rational &time)
|
||||
{
|
||||
foreach (NodeParamViewItem* item, items_) {
|
||||
item->SetTime(time);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::RulerTimeChanged(const int64_t ×tamp)
|
||||
{
|
||||
rational time = olive::timestamp_to_time(timestamp, keyframe_view_->timebase());
|
||||
|
||||
UpdateItemTime(time);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
class NodeParamView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamView(QWidget* parent);
|
||||
|
||||
@@ -40,9 +41,14 @@ public:
|
||||
const double& GetScale() const;
|
||||
void SetScale(const double &scale);
|
||||
|
||||
public slots:
|
||||
void SetTime(const rational& time);
|
||||
|
||||
private:
|
||||
void SetTimebase(const rational& timebase);
|
||||
|
||||
void UpdateItemTime(const rational& time);
|
||||
|
||||
QVBoxLayout* param_layout_;
|
||||
|
||||
KeyframeView* keyframe_view_;
|
||||
@@ -52,6 +58,10 @@ private:
|
||||
QList<Node*> nodes_;
|
||||
|
||||
QList<NodeParamViewItem*> items_;
|
||||
|
||||
private slots:
|
||||
void RulerTimeChanged(const int64_t& timestamp);
|
||||
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEW_H
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
|
||||
#include "nodeparamviewkeyframecontrol.h"
|
||||
#include "nodeparamviewundo.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "ui/icons/icons.h"
|
||||
#include "undo/undostack.h"
|
||||
|
||||
NodeParamViewItem::NodeParamViewItem(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
node_(node)
|
||||
{
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setSpacing(0);
|
||||
@@ -70,48 +70,52 @@ NodeParamViewItem::NodeParamViewItem(QWidget *parent) :
|
||||
|
||||
// Set correct widget state
|
||||
SetExpanded(title_bar_collapse_btn_->isChecked());
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
void NodeParamViewItem::AttachNode(Node *n)
|
||||
void NodeParamViewItem::SetTime(const rational &time)
|
||||
{
|
||||
// Make sure we can attach this node (CanAddNode() should be run by the caller to make sure this node is valid)
|
||||
Q_ASSERT(CanAddNode(n));
|
||||
time_ = time;
|
||||
|
||||
// Add node to the list
|
||||
nodes_.append(n);
|
||||
|
||||
// If the added node was the first node, set up the UI
|
||||
if (nodes_.size() == 1) {
|
||||
SetupUI();
|
||||
} else {
|
||||
AddAdditionalNode(n);
|
||||
foreach (NodeParamViewWidgetBridge* bridge, bridges_) {
|
||||
// Updates the UI widgets from the time
|
||||
bridge->SetTime(time_);
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeParamViewItem::CanAddNode(Node* n)
|
||||
{
|
||||
// Ensures that all Nodes have the same ID
|
||||
return (nodes_.isEmpty() || nodes_.first()->id() == n->id());
|
||||
foreach (NodeParamViewKeyframeControl* key_control, key_control_list_) {
|
||||
UpdateKeyframeControl(key_control);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange && !nodes_.isEmpty()) {
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
|
||||
void NodeParamViewItem::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframePtr keyframe)
|
||||
{
|
||||
// Find its row in the parameters
|
||||
QLabel* lbl = label_map_.value(input);
|
||||
|
||||
// Find label's Y position
|
||||
QPoint lbl_center = lbl->rect().center();
|
||||
|
||||
// Find global position
|
||||
lbl_center = lbl->mapToGlobal(lbl_center);
|
||||
|
||||
emit KeyframeAdded(keyframe, lbl_center.y());
|
||||
}
|
||||
|
||||
void NodeParamViewItem::SetupUI()
|
||||
{
|
||||
Q_ASSERT(!nodes_.isEmpty());
|
||||
|
||||
Node* first_node = nodes_.first();
|
||||
|
||||
int row_count = 0;
|
||||
|
||||
foreach (NodeParam* param, first_node->parameters()) {
|
||||
foreach (NodeParam* param, node_->parameters()) {
|
||||
// This widget only needs to show input parameters
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
@@ -120,11 +124,12 @@ void NodeParamViewItem::SetupUI()
|
||||
QLabel* param_label = new QLabel();
|
||||
param_lbls_.append(param_label);
|
||||
|
||||
label_map_.insert(input, param_label);
|
||||
|
||||
content_layout_->addWidget(param_label, row_count, 0);
|
||||
|
||||
// Create a widget/input bridge for this input
|
||||
NodeParamViewWidgetBridge* bridge = new NodeParamViewWidgetBridge(this);
|
||||
bridge->AddInput(input);
|
||||
NodeParamViewWidgetBridge* bridge = new NodeParamViewWidgetBridge(input, this);
|
||||
bridges_.append(bridge);
|
||||
|
||||
// Add widgets for this parameter ot the layout
|
||||
@@ -140,6 +145,15 @@ void NodeParamViewItem::SetupUI()
|
||||
|
||||
NodeParamViewKeyframeControl* key_control = new NodeParamViewKeyframeControl(input);
|
||||
content_layout_->addWidget(key_control, row_count, control_column);
|
||||
connect(key_control, &NodeParamViewKeyframeControl::KeyframeEnableChanged, this, &NodeParamViewItem::UserChangedKeyframeEnable);
|
||||
connect(key_control, &NodeParamViewKeyframeControl::GoToPreviousKey, this, &NodeParamViewItem::GoToPreviousKey);
|
||||
connect(key_control, &NodeParamViewKeyframeControl::GoToNextKey, this, &NodeParamViewItem::GoToNextKey);
|
||||
connect(key_control, &NodeParamViewKeyframeControl::KeyframeToggled, this, &NodeParamViewItem::UserToggledKeyframe);
|
||||
key_control_list_.append(key_control);
|
||||
|
||||
connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItem::InputKeyframeEnableChanged);
|
||||
connect(input, &NodeInput::KeyframeAdded, this, &NodeParamViewItem::InputAddedKeyframe);
|
||||
connect(input, &NodeInput::KeyframeRemoved, this, &NodeParamViewItem::KeyframeRemoved);
|
||||
}
|
||||
|
||||
row_count++;
|
||||
@@ -149,30 +163,15 @@ void NodeParamViewItem::SetupUI()
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
void NodeParamViewItem::AddAdditionalNode(Node *n)
|
||||
{
|
||||
int bridge_count = 0;
|
||||
|
||||
foreach (NodeParam* param, n->parameters()) {
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
bridges_.at(bridge_count)->AddInput(static_cast<NodeInput*>(param));
|
||||
|
||||
bridge_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::Retranslate()
|
||||
{
|
||||
Node* first_node = nodes_.first();
|
||||
node_->Retranslate();
|
||||
|
||||
first_node->Retranslate();
|
||||
|
||||
title_bar_lbl_->setText(first_node->Name());
|
||||
title_bar_lbl_->setText(node_->Name());
|
||||
|
||||
int row_count = 0;
|
||||
|
||||
foreach (NodeParam* param, first_node->parameters()) {
|
||||
foreach (NodeParam* param, node_->parameters()) {
|
||||
// This widget only needs to show input parameters
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
param_lbls_.at(row_count)->setText(tr("%1:").arg(param->name()));
|
||||
@@ -182,6 +181,27 @@ void NodeParamViewItem::Retranslate()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::UpdateKeyframeControl(NodeParamViewKeyframeControl *key_control)
|
||||
{
|
||||
NodeInput* input = key_control->GetConnectedInput();
|
||||
|
||||
// Update UI based on time
|
||||
key_control->SetPreviousButtonEnabled(time_ > input->keyframes().first()->time());
|
||||
key_control->SetNextButtonEnabled(time_ < input->keyframes().last()->time());
|
||||
key_control->SetToggleButtonChecked(input->has_keyframe_at_time(time_));
|
||||
}
|
||||
|
||||
NodeParamViewKeyframeControl *NodeParamViewItem::KeyframeControlFromInput(NodeInput *input) const
|
||||
{
|
||||
foreach (NodeParamViewKeyframeControl* key_control, key_control_list_) {
|
||||
if (key_control->GetConnectedInput() == input) {
|
||||
return key_control;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NodeParamViewItem::SetExpanded(bool e)
|
||||
{
|
||||
expanded_ = e;
|
||||
@@ -195,7 +215,7 @@ void NodeParamViewItem::SetExpanded(bool e)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::KeyframeEnableChanged(bool e)
|
||||
void NodeParamViewItem::UserChangedKeyframeEnable(bool e)
|
||||
{
|
||||
NodeParamViewKeyframeControl* control = static_cast<NodeParamViewKeyframeControl*>(sender());
|
||||
NodeInput* input = control->GetConnectedInput();
|
||||
@@ -205,15 +225,14 @@ void NodeParamViewItem::KeyframeEnableChanged(bool e)
|
||||
return;
|
||||
}
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
if (e) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Enable keyframing
|
||||
new NodeParamSetKeyframing(input, true, command);
|
||||
new NodeParamSetKeyframingCommand(input, true, command);
|
||||
|
||||
// FIXME: Create a keyframe at this time
|
||||
|
||||
olive::undo_stack.push(command);
|
||||
// NodeInputs already have one keyframe by default, we move it to the current time here
|
||||
new NodeParamSetKeyframeTimeCommand(input->keyframes().first(), time_, command);
|
||||
} else {
|
||||
// Confirm the user wants to clear all keyframes
|
||||
if (QMessageBox::warning(this,
|
||||
@@ -221,21 +240,107 @@ void NodeParamViewItem::KeyframeEnableChanged(bool e)
|
||||
tr("Are you sure you want to disable keyframing on this value? This will clear all existing keyframes."),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
// Disable keyframing
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
// Store value at this time, we'll set this as the persistent value later
|
||||
QVariant stored_val = input->get_value_at_time(time_);
|
||||
|
||||
// FIXME: Delete all keyframes
|
||||
// Delete all keyframes EXCEPT ONE
|
||||
for (int i=input->keyframes().size()-1;i>0;i--) {
|
||||
new NodeParamRemoveKeyframeCommand(input, input->keyframes().at(i), command);
|
||||
}
|
||||
|
||||
// Update value with this one
|
||||
new NodeParamSetKeyframeValueCommand(input->keyframes().first(), stored_val, command);
|
||||
|
||||
// Disable keyframing
|
||||
new NodeParamSetKeyframing(input, false, command);
|
||||
|
||||
olive::undo_stack.push(command);
|
||||
new NodeParamSetKeyframingCommand(input, false, command);
|
||||
|
||||
} else {
|
||||
// Disable action has effectively been ignored
|
||||
control->SetKeyframeEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
olive::undo_stack.pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void NodeParamViewItem::UserToggledKeyframe(bool e)
|
||||
{
|
||||
NodeParamViewKeyframeControl* control = static_cast<NodeParamViewKeyframeControl*>(sender());
|
||||
NodeInput* input = control->GetConnectedInput();
|
||||
NodeKeyframePtr key = input->get_keyframe_at_time(time_);
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
if (e && !key) {
|
||||
// Add a keyframe here
|
||||
NodeKeyframePtr closest_key = input->get_closest_keyframe_to_time(time_);
|
||||
|
||||
key = std::make_shared<NodeKeyframe>(time_, input->get_value_at_time(time_), closest_key->type());
|
||||
|
||||
new NodeParamInsertKeyframeCommand(input, key, command);
|
||||
} else if (!e && key) {
|
||||
// Remove a keyframe here
|
||||
new NodeParamRemoveKeyframeCommand(input, key, command);
|
||||
}
|
||||
|
||||
olive::undo_stack.pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void NodeParamViewItem::InputKeyframeEnableChanged(bool e)
|
||||
{
|
||||
NodeInput* input = static_cast<NodeInput*>(sender());
|
||||
|
||||
foreach (NodeKeyframePtr key, input->keyframes()) {
|
||||
if (e) {
|
||||
// Add a keyframe item for each keyframe
|
||||
InputAddedKeyframeInternal(input, key);
|
||||
} else {
|
||||
// Remove each keyframe item
|
||||
emit KeyframeRemoved(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::InputAddedKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
// Get NodeInput that emitted this signal
|
||||
NodeInput* input = static_cast<NodeInput*>(sender());
|
||||
|
||||
InputAddedKeyframeInternal(input, key);
|
||||
|
||||
UpdateKeyframeControl(KeyframeControlFromInput(input));
|
||||
}
|
||||
|
||||
void NodeParamViewItem::GoToPreviousKey()
|
||||
{
|
||||
NodeParamViewKeyframeControl* key_control = static_cast<NodeParamViewKeyframeControl*>(sender());
|
||||
NodeInput* input = key_control->GetConnectedInput();
|
||||
|
||||
for (int i=input->keyframes().size()-1;i>=0;i--) {
|
||||
// Find closest keyframe that is before this time
|
||||
const rational& this_key_time = input->keyframes().at(i)->time();
|
||||
|
||||
if (this_key_time < time_) {
|
||||
emit RequestSetTime(this_key_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::GoToNextKey()
|
||||
{
|
||||
NodeParamViewKeyframeControl* key_control = static_cast<NodeParamViewKeyframeControl*>(sender());
|
||||
NodeInput* input = key_control->GetConnectedInput();
|
||||
|
||||
for (int i=0;i<input->keyframes().size();i++) {
|
||||
// Find closest keyframe that is before this time
|
||||
const rational& this_key_time = input->keyframes().at(i)->time();
|
||||
|
||||
if (this_key_time > time_) {
|
||||
emit RequestSetTime(this_key_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) :
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "node/node.h"
|
||||
#include "nodeparamviewkeyframecontrol.h"
|
||||
#include "nodeparamviewwidgetbridge.h"
|
||||
|
||||
class NodeParamViewItemTitleBar : public QWidget {
|
||||
@@ -42,22 +43,31 @@ class NodeParamViewItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamViewItem(QWidget* parent);
|
||||
NodeParamViewItem(Node* node, QWidget* parent = nullptr);
|
||||
|
||||
void AttachNode(Node* n);
|
||||
void SetTime(const rational& time);
|
||||
|
||||
bool CanAddNode(Node *n);
|
||||
signals:
|
||||
void KeyframeAdded(NodeKeyframePtr key, int y);
|
||||
|
||||
void KeyframeRemoved(NodeKeyframePtr key);
|
||||
|
||||
void RequestSetTime(const rational& time);
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e) override;
|
||||
virtual void changeEvent(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void InputAddedKeyframeInternal(NodeInput* input, NodeKeyframePtr keyframe);
|
||||
|
||||
void SetupUI();
|
||||
|
||||
void AddAdditionalNode(Node* n);
|
||||
|
||||
void Retranslate();
|
||||
|
||||
void UpdateKeyframeControl(NodeParamViewKeyframeControl* key_control);
|
||||
|
||||
NodeParamViewKeyframeControl* KeyframeControlFromInput(NodeInput* input) const;
|
||||
|
||||
bool expanded_;
|
||||
|
||||
NodeParamViewItemTitleBar* title_bar_;
|
||||
@@ -72,14 +82,31 @@ private:
|
||||
|
||||
QGridLayout* content_layout_;
|
||||
|
||||
QList<Node*> nodes_;
|
||||
Node* node_;
|
||||
|
||||
QList<NodeParamViewWidgetBridge*> bridges_;
|
||||
|
||||
rational time_;
|
||||
|
||||
QMap<NodeInput*, QLabel*> label_map_;
|
||||
|
||||
QList<NodeParamViewKeyframeControl*> key_control_list_;
|
||||
|
||||
private slots:
|
||||
void SetExpanded(bool e);
|
||||
|
||||
void KeyframeEnableChanged(bool e);
|
||||
void UserChangedKeyframeEnable(bool e);
|
||||
|
||||
void UserToggledKeyframe(bool e);
|
||||
|
||||
void InputKeyframeEnableChanged(bool e);
|
||||
|
||||
void InputAddedKeyframe(NodeKeyframePtr key);
|
||||
|
||||
void GoToPreviousKey();
|
||||
|
||||
void GoToNextKey();
|
||||
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEWITEM_H
|
||||
|
||||
@@ -33,8 +33,12 @@ NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(NodeInput* input, QWi
|
||||
enable_key_btn_->setIconSize(enable_key_btn_->iconSize() / 4 * 3);
|
||||
layout->addWidget(enable_key_btn_);
|
||||
|
||||
connect(enable_key_btn_, SIGNAL(toggled(bool)), this, SLOT(ShowButtonsFromKeyframeEnable(bool)));
|
||||
connect(enable_key_btn_, SIGNAL(toggled(bool)), this, SIGNAL(KeyframeEnableChanged(bool)));
|
||||
connect(prev_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToPreviousKey);
|
||||
connect(next_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToNextKey);
|
||||
connect(toggle_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeToggled);
|
||||
connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable);
|
||||
connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged);
|
||||
connect(input_, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewKeyframeControl::SetKeyframeEnabled);
|
||||
|
||||
// Pick up keyframing value
|
||||
ShowButtonsFromKeyframeEnable(input_->is_keyframing());
|
||||
@@ -45,6 +49,26 @@ NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const
|
||||
return input_;
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::SetPreviousButtonEnabled(bool enabled)
|
||||
{
|
||||
prev_key_btn_->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::SetNextButtonEnabled(bool enabled)
|
||||
{
|
||||
next_key_btn_->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::SetToggleButtonChecked(bool checked)
|
||||
{
|
||||
// Suppress KeyframeToggled() signal from this object
|
||||
blockSignals(true);
|
||||
|
||||
toggle_key_btn_->setChecked(checked);
|
||||
|
||||
blockSignals(false);
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::SetKeyframeEnabled(bool e)
|
||||
{
|
||||
// Suppress KeyframeEnableChanged() signal from this object
|
||||
|
||||
@@ -14,12 +14,21 @@ public:
|
||||
|
||||
NodeInput* GetConnectedInput() const;
|
||||
|
||||
void SetPreviousButtonEnabled(bool enabled);
|
||||
void SetNextButtonEnabled(bool enabled);
|
||||
void SetToggleButtonChecked(bool checked);
|
||||
|
||||
public slots:
|
||||
void SetKeyframeEnabled(bool e);
|
||||
|
||||
signals:
|
||||
void KeyframeEnableChanged(bool);
|
||||
|
||||
void GoToPreviousKey();
|
||||
void GoToNextKey();
|
||||
|
||||
void KeyframeToggled(bool);
|
||||
|
||||
private:
|
||||
QPushButton* CreateNewToolButton(const QIcon &icon) const;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "nodeparamviewundo.h"
|
||||
|
||||
NodeParamSetKeyframing::NodeParamSetKeyframing(NodeInput *input, bool setting, QUndoCommand *parent) :
|
||||
NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(NodeInput *input, bool setting, QUndoCommand *parent) :
|
||||
QUndoCommand(parent),
|
||||
input_(input),
|
||||
setting_(setting)
|
||||
@@ -8,12 +8,82 @@ NodeParamSetKeyframing::NodeParamSetKeyframing(NodeInput *input, bool setting, Q
|
||||
Q_ASSERT(setting != input_->is_keyframing());
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframing::redo()
|
||||
void NodeParamSetKeyframingCommand::redo()
|
||||
{
|
||||
input_->set_is_keyframing(setting_);
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframing::undo()
|
||||
void NodeParamSetKeyframingCommand::undo()
|
||||
{
|
||||
input_->set_is_keyframing(!setting_);
|
||||
}
|
||||
|
||||
NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent) :
|
||||
QUndoCommand(parent),
|
||||
key_(key),
|
||||
old_value_(key_->value()),
|
||||
new_value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframeValueCommand::redo()
|
||||
{
|
||||
key_->set_value(new_value_);
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframeValueCommand::undo()
|
||||
{
|
||||
key_->set_value(old_value_);
|
||||
}
|
||||
|
||||
NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand* parent) :
|
||||
QUndoCommand(parent),
|
||||
input_(input),
|
||||
keyframe_(keyframe)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeParamInsertKeyframeCommand::redo()
|
||||
{
|
||||
input_->insert_keyframe(keyframe_);
|
||||
}
|
||||
|
||||
void NodeParamInsertKeyframeCommand::undo()
|
||||
{
|
||||
input_->remove_keyframe(keyframe_);
|
||||
}
|
||||
|
||||
NodeParamRemoveKeyframeCommand::NodeParamRemoveKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand *parent) :
|
||||
QUndoCommand(parent),
|
||||
input_(input),
|
||||
keyframe_(keyframe)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeParamRemoveKeyframeCommand::redo()
|
||||
{
|
||||
input_->remove_keyframe(keyframe_);
|
||||
}
|
||||
|
||||
void NodeParamRemoveKeyframeCommand::undo()
|
||||
{
|
||||
input_->insert_keyframe(keyframe_);
|
||||
}
|
||||
|
||||
NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational &time, QUndoCommand *parent) :
|
||||
QUndoCommand(parent),
|
||||
key_(key),
|
||||
old_time_(key->time()),
|
||||
new_time_(time)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframeTimeCommand::redo()
|
||||
{
|
||||
key_->set_time(new_time_);
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframeTimeCommand::undo()
|
||||
{
|
||||
key_->set_time(old_time_);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include "node/input.h"
|
||||
|
||||
class NodeParamSetKeyframing : public QUndoCommand {
|
||||
class NodeParamSetKeyframingCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeParamSetKeyframing(NodeInput* input, bool setting, QUndoCommand* parent = nullptr);
|
||||
NodeParamSetKeyframingCommand(NodeInput* input, bool setting, QUndoCommand* parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
@@ -17,4 +17,62 @@ private:
|
||||
bool setting_;
|
||||
};
|
||||
|
||||
class NodeParamInsertKeyframeCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeInput* input_;
|
||||
|
||||
NodeKeyframePtr keyframe_;
|
||||
|
||||
};
|
||||
|
||||
class NodeParamRemoveKeyframeCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeParamRemoveKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeInput* input_;
|
||||
|
||||
NodeKeyframePtr keyframe_;
|
||||
|
||||
};
|
||||
|
||||
class NodeParamSetKeyframeTimeCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational& time, QUndoCommand* parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeKeyframePtr key_;
|
||||
|
||||
rational old_time_;
|
||||
rational new_time_;
|
||||
|
||||
};
|
||||
|
||||
class NodeParamSetKeyframeValueCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeKeyframePtr key_;
|
||||
|
||||
QVariant old_value_;
|
||||
QVariant new_value_;
|
||||
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEWUNDO_H
|
||||
|
||||
@@ -8,27 +8,95 @@
|
||||
#include <QVector4D>
|
||||
|
||||
#include "node/node.h"
|
||||
#include "nodeparamviewundo.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "undo/undostack.h"
|
||||
#include "widget/footagecombobox/footagecombobox.h"
|
||||
#include "widget/slider/floatslider.h"
|
||||
#include "widget/slider/integerslider.h"
|
||||
|
||||
// FIXME: Test code only
|
||||
#include "panel/panelmanager.h"
|
||||
#include "panel/project/project.h"
|
||||
// End test code
|
||||
|
||||
NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(QObject* parent) :
|
||||
QObject(parent)
|
||||
NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) :
|
||||
QObject(parent),
|
||||
input_(input)
|
||||
{
|
||||
CreateWidgets();
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::AddInput(NodeInput *input)
|
||||
void NodeParamViewWidgetBridge::SetTime(const rational &time)
|
||||
{
|
||||
inputs_.append(input);
|
||||
time_ = time;
|
||||
|
||||
// If this was the first input, create the widgets
|
||||
if (inputs_.size() == 1) {
|
||||
CreateWidgets();
|
||||
// We assume the first data type is the "primary" type
|
||||
switch (input_->data_type()) {
|
||||
// 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::kWholeNumber:
|
||||
case NodeParam::kNumber:
|
||||
case NodeParam::kString:
|
||||
case NodeParam::kBuffer:
|
||||
case NodeParam::kVector:
|
||||
break;
|
||||
case NodeParam::kInt:
|
||||
static_cast<IntegerSlider*>(widgets_.first())->SetValue(input_->get_value_at_time(time).toLongLong());
|
||||
break;
|
||||
case NodeParam::kFloat:
|
||||
static_cast<FloatSlider*>(widgets_.first())->SetValue(input_->get_value_at_time(time).toDouble());
|
||||
break;
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
QVector2D vec2 = input_->get_value_at_time(time).value<QVector2D>();
|
||||
|
||||
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec2.x()));
|
||||
static_cast<FloatSlider*>(widgets_.at(1))->SetValue(static_cast<double>(vec2.y()));
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec3:
|
||||
{
|
||||
QVector3D vec3 = input_->get_value_at_time(time).value<QVector3D>();
|
||||
|
||||
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec3.x()));
|
||||
static_cast<FloatSlider*>(widgets_.at(1))->SetValue(static_cast<double>(vec3.y()));
|
||||
static_cast<FloatSlider*>(widgets_.at(2))->SetValue(static_cast<double>(vec3.z()));
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec4:
|
||||
{
|
||||
QVector4D vec4 = input_->get_value_at_time(time).value<QVector4D>();
|
||||
|
||||
static_cast<FloatSlider*>(widgets_.at(0))->SetValue(static_cast<double>(vec4.x()));
|
||||
static_cast<FloatSlider*>(widgets_.at(1))->SetValue(static_cast<double>(vec4.y()));
|
||||
static_cast<FloatSlider*>(widgets_.at(2))->SetValue(static_cast<double>(vec4.z()));
|
||||
static_cast<FloatSlider*>(widgets_.at(3))->SetValue(static_cast<double>(vec4.w()));
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFile:
|
||||
// FIXME: File selector
|
||||
break;
|
||||
case NodeParam::kColor:
|
||||
// FIXME: Color selector
|
||||
break;
|
||||
case NodeParam::kText:
|
||||
{
|
||||
static_cast<QLineEdit*>(widgets_.first())->setText(input_->get_value_at_time(time).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kBoolean:
|
||||
static_cast<QCheckBox*>(widgets_.first())->setChecked(input_->get_value_at_time(time).toBool());
|
||||
break;
|
||||
case NodeParam::kFont:
|
||||
{
|
||||
// FIXME: Implement this
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFootage:
|
||||
static_cast<FootageComboBox*>(widgets_.first())->SetFootage(input_->get_value_at_time(time).value<StreamPtr>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +107,8 @@ const QList<QWidget *> &NodeParamViewWidgetBridge::widgets()
|
||||
|
||||
void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
{
|
||||
NodeInput* base_input = inputs_.first();
|
||||
|
||||
// We assume the first data type is the "primary" type
|
||||
switch (base_input->data_type()) {
|
||||
switch (input_->data_type()) {
|
||||
// None of these inputs have applicable UI widgets
|
||||
case NodeParam::kNone:
|
||||
case NodeParam::kAny:
|
||||
@@ -61,14 +127,12 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
{
|
||||
IntegerSlider* slider = new IntegerSlider();
|
||||
|
||||
slider->SetValue(base_input->get_value_at_time(0).toLongLong());
|
||||
|
||||
if (base_input->has_minimum()) {
|
||||
slider->SetMinimum(base_input->minimum().toLongLong());
|
||||
if (input_->has_minimum()) {
|
||||
slider->SetMinimum(input_->minimum().toLongLong());
|
||||
}
|
||||
|
||||
if (base_input->has_maximum()) {
|
||||
slider->SetMaximum(base_input->maximum().toLongLong());
|
||||
if (input_->has_maximum()) {
|
||||
slider->SetMaximum(input_->maximum().toLongLong());
|
||||
}
|
||||
|
||||
connect(slider, SIGNAL(ValueChanged(int64_t)), this, SLOT(WidgetCallback()));
|
||||
@@ -80,14 +144,12 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
{
|
||||
FloatSlider* slider = new FloatSlider();
|
||||
|
||||
slider->SetValue(base_input->get_value_at_time(0).toDouble());
|
||||
|
||||
if (base_input->has_minimum()) {
|
||||
slider->SetMinimum(base_input->minimum().toDouble());
|
||||
if (input_->has_minimum()) {
|
||||
slider->SetMinimum(input_->minimum().toDouble());
|
||||
}
|
||||
|
||||
if (base_input->has_maximum()) {
|
||||
slider->SetMaximum(base_input->maximum().toDouble());
|
||||
if (input_->has_maximum()) {
|
||||
slider->SetMaximum(input_->maximum().toDouble());
|
||||
}
|
||||
|
||||
connect(slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
@@ -97,60 +159,45 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
}
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
QVector2D vec2 = base_input->get_value_at_time(0).value<QVector2D>();
|
||||
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
x_slider->SetValue(static_cast<double>(vec2.x()));
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
y_slider->SetValue(static_cast<double>(vec2.y()));
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec3:
|
||||
{
|
||||
QVector3D vec3 = base_input->get_value_at_time(0).value<QVector3D>();
|
||||
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
x_slider->SetValue(static_cast<double>(vec3.x()));
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
y_slider->SetValue(static_cast<double>(vec3.y()));
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* z_slider = new FloatSlider();
|
||||
z_slider->SetValue(static_cast<double>(vec3.z()));
|
||||
widgets_.append(z_slider);
|
||||
connect(z_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec4:
|
||||
{
|
||||
QVector4D vec4 = base_input->get_value_at_time(0).value<QVector4D>();
|
||||
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
x_slider->SetValue(static_cast<double>(vec4.x()));
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
y_slider->SetValue(static_cast<double>(vec4.y()));
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* z_slider = new FloatSlider();
|
||||
z_slider->SetValue(static_cast<double>(vec4.z()));
|
||||
widgets_.append(z_slider);
|
||||
connect(z_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
|
||||
FloatSlider* w_slider = new FloatSlider();
|
||||
w_slider->SetValue(static_cast<double>(vec4.w()));
|
||||
widgets_.append(w_slider);
|
||||
connect(w_slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback()));
|
||||
break;
|
||||
@@ -171,7 +218,6 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
case NodeParam::kBoolean:
|
||||
{
|
||||
QCheckBox* check_box = new QCheckBox();
|
||||
check_box->setChecked(base_input->get_value_at_time(0).toBool());
|
||||
widgets_.append(check_box);
|
||||
connect(check_box, SIGNAL(toggled(bool)), this, SLOT(WidgetCallback()));
|
||||
break;
|
||||
@@ -185,17 +231,9 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
case NodeParam::kFootage:
|
||||
{
|
||||
FootageComboBox* footage_combobox = new FootageComboBox();
|
||||
|
||||
// FIXME: Test code
|
||||
// Pretty hacky way of getting the root folder for this node's sequence
|
||||
ProjectPanel* pp = olive::panel_manager->MostRecentlyFocused<ProjectPanel>();
|
||||
footage_combobox->SetRoot(pp->project()->root());
|
||||
|
||||
// Use multiple values
|
||||
footage_combobox->SetFootage(base_input->get_value_at_time(0).value<StreamPtr>());
|
||||
footage_combobox->SetRoot(static_cast<Sequence*>(input_->parentNode()->parent())->project()->root());
|
||||
|
||||
connect(footage_combobox, SIGNAL(FootageChanged(StreamPtr)), this, SLOT(WidgetCallback()));
|
||||
// End test code
|
||||
|
||||
widgets_.append(footage_combobox);
|
||||
|
||||
@@ -204,135 +242,156 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::SetInputValue(NodeInput *input, const QVariant &value)
|
||||
{
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
if (input->is_keyframing()) {
|
||||
NodeKeyframePtr existing_key = input->get_keyframe_at_time(time_);
|
||||
|
||||
if (existing_key) {
|
||||
new NodeParamSetKeyframeValueCommand(existing_key, value, command);
|
||||
} else {
|
||||
// No existing key, create a new one
|
||||
NodeKeyframePtr closest_key = input->get_closest_keyframe_to_time(time_);
|
||||
NodeKeyframePtr new_key = std::make_shared<NodeKeyframe>(time_, value, closest_key->type());
|
||||
|
||||
new NodeParamInsertKeyframeCommand(input, new_key, command);
|
||||
}
|
||||
} else {
|
||||
new NodeParamSetKeyframeValueCommand(input->keyframes().first(), value, command);
|
||||
}
|
||||
|
||||
olive::undo_stack.pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::WidgetCallback()
|
||||
{
|
||||
foreach (NodeInput* input, inputs_) {
|
||||
switch (input->data_type()) {
|
||||
// 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::kWholeNumber:
|
||||
case NodeParam::kNumber:
|
||||
case NodeParam::kString:
|
||||
case NodeParam::kVector:
|
||||
case NodeParam::kBuffer:
|
||||
break;
|
||||
case NodeParam::kInt:
|
||||
{
|
||||
// Widget is a IntegerSlider
|
||||
IntegerSlider* int_slider = static_cast<IntegerSlider*>(sender());
|
||||
input->set_value_at_time(0, int_slider->GetValue());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFloat:
|
||||
{
|
||||
// Widget is a FloatSlider
|
||||
FloatSlider* float_slider = static_cast<FloatSlider*>(sender());
|
||||
input->set_value_at_time(0, float_slider->GetValue());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
// Widgets are two FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
switch (input_->data_type()) {
|
||||
// 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::kWholeNumber:
|
||||
case NodeParam::kNumber:
|
||||
case NodeParam::kString:
|
||||
case NodeParam::kVector:
|
||||
case NodeParam::kBuffer:
|
||||
break;
|
||||
case NodeParam::kInt:
|
||||
{
|
||||
// Widget is a IntegerSlider
|
||||
// IntegerSlider* int_slider = static_cast<IntegerSlider*>(sender());
|
||||
// input->set_default_value(time_, int_slider->GetValue());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFloat:
|
||||
{
|
||||
// Widget is a FloatSlider
|
||||
FloatSlider* float_slider = static_cast<FloatSlider*>(sender());
|
||||
SetInputValue(input_, float_slider->GetValue());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
// Widgets are two FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
|
||||
QVector2D val = input->get_value_at_time(0).value<QVector2D>();
|
||||
QVector2D val = input_->get_value_at_time(0).value<QVector2D>();
|
||||
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
|
||||
input->set_value_at_time(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec3:
|
||||
{
|
||||
// Widgets are three FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
// input->set_default_value(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec3:
|
||||
{
|
||||
// Widgets are three FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
|
||||
QVector3D val = input->get_value_at_time(0).value<QVector3D>();
|
||||
QVector3D val = input_->get_value_at_time(0).value<QVector3D>();
|
||||
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(1)) {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is Z slider
|
||||
val.setZ(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(1)) {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is Z slider
|
||||
val.setZ(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
|
||||
input->set_value_at_time(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec4:
|
||||
{
|
||||
// Widgets are three FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
// input->set_default_value(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec4:
|
||||
{
|
||||
// Widgets are three FloatSliders
|
||||
FloatSlider* slider = static_cast<FloatSlider*>(sender());
|
||||
|
||||
QVector4D val = input->get_value_at_time(0).value<QVector4D>();
|
||||
QVector4D val = input_->get_value_at_time(0).value<QVector4D>();
|
||||
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(1)) {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(2)) {
|
||||
// Slider is Z slider
|
||||
val.setZ(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is W slider
|
||||
val.setW(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
if (slider == widgets_.at(0)) {
|
||||
// Slider is X slider
|
||||
val.setX(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(1)) {
|
||||
// Slider is Y slider
|
||||
val.setY(static_cast<float>(slider->GetValue()));
|
||||
} else if (slider == widgets_.at(2)) {
|
||||
// Slider is Z slider
|
||||
val.setZ(static_cast<float>(slider->GetValue()));
|
||||
} else {
|
||||
// Slider is W slider
|
||||
val.setW(static_cast<float>(slider->GetValue()));
|
||||
}
|
||||
|
||||
input->set_value_at_time(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFile:
|
||||
// FIXME: File selector
|
||||
break;
|
||||
case NodeParam::kColor:
|
||||
// FIXME: Color selector
|
||||
break;
|
||||
case NodeParam::kText:
|
||||
{
|
||||
// Sender is a QLineEdit
|
||||
QLineEdit* line_edit = static_cast<QLineEdit*>(sender());
|
||||
input->set_value_at_time(0, line_edit->text());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kBoolean:
|
||||
{
|
||||
// Widget is a QCheckBox
|
||||
QCheckBox* check_box = static_cast<QCheckBox*>(sender());
|
||||
input->set_value_at_time(0, check_box->isChecked());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFont:
|
||||
{
|
||||
// Widget is a QFontComboBox
|
||||
QFontComboBox* font_combobox = static_cast<QFontComboBox*>(sender());
|
||||
input->set_value_at_time(0, font_combobox->currentFont());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFootage:
|
||||
{
|
||||
// Widget is a FootageComboBox
|
||||
FootageComboBox* footage_combobox = static_cast<FootageComboBox*>(sender());
|
||||
input->set_value_at_time(0, QVariant::fromValue(footage_combobox->SelectedFootage()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// input->set_default_value(0, val);
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFile:
|
||||
// FIXME: File selector
|
||||
break;
|
||||
case NodeParam::kColor:
|
||||
// FIXME: Color selector
|
||||
break;
|
||||
case NodeParam::kText:
|
||||
{
|
||||
// Sender is a QLineEdit
|
||||
// QLineEdit* line_edit = static_cast<QLineEdit*>(sender());
|
||||
// input->set_default_value(time_, line_edit->text());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kBoolean:
|
||||
{
|
||||
// Widget is a QCheckBox
|
||||
// QCheckBox* check_box = static_cast<QCheckBox*>(sender());
|
||||
// input->set_default_value(0, check_box->isChecked());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFont:
|
||||
{
|
||||
// Widget is a QFontComboBox
|
||||
// QFontComboBox* font_combobox = static_cast<QFontComboBox*>(sender());
|
||||
// input->set_default_value(time_, font_combobox->currentFont());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFootage:
|
||||
{
|
||||
// Widget is a FootageComboBox
|
||||
// FootageComboBox* footage_combobox = static_cast<FootageComboBox*>(sender());
|
||||
// input->set_default_value(time_, QVariant::fromValue(footage_combobox->SelectedFootage()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,22 @@ class NodeParamViewWidgetBridge : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamViewWidgetBridge(QObject* parent);
|
||||
NodeParamViewWidgetBridge(NodeInput* input, QObject* parent);
|
||||
|
||||
void AddInput(NodeInput* input);
|
||||
void SetTime(const rational& time);
|
||||
|
||||
const QList<QWidget*>& widgets();
|
||||
|
||||
private:
|
||||
QList<NodeInput*> inputs_;
|
||||
void CreateWidgets();
|
||||
|
||||
void SetInputValue(NodeInput* input, const QVariant& value);
|
||||
|
||||
NodeInput* input_;
|
||||
|
||||
QList<QWidget*> widgets_;
|
||||
|
||||
void CreateWidgets();
|
||||
rational time_;
|
||||
|
||||
private slots:
|
||||
void WidgetCallback();
|
||||
|
||||
@@ -32,6 +32,8 @@ void TimelineViewBase::SetScale(const double &scale)
|
||||
viewport()->update();
|
||||
|
||||
end_item_->SetScale(scale_);
|
||||
|
||||
ScaleChangedEvent(scale_);
|
||||
}
|
||||
|
||||
void TimelineViewBase::SetTimebase(const rational &timebase)
|
||||
@@ -146,3 +148,8 @@ void TimelineViewBase::resizeEvent(QResizeEvent *event)
|
||||
|
||||
UpdateSceneRect();
|
||||
}
|
||||
|
||||
void TimelineViewBase::ScaleChangedEvent(double scale)
|
||||
{
|
||||
Q_UNUSED(scale)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ protected:
|
||||
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
virtual void ScaleChangedEvent(double scale);
|
||||
|
||||
rational GetPlayheadTime();
|
||||
|
||||
bool PlayheadPress(QMouseEvent* event);
|
||||
|
||||
Reference in New Issue
Block a user