keyframeview: implemented transforming keyframe times to and from sequence time
Since the node graph can have transform cross nodes, input keyframes may occur at a different times requiring transforming between sequence time and media time. This commit implements such a mechanism in all UI classes that need it.
This commit is contained in:
+4
-3
@@ -540,15 +540,16 @@ QList<TimeRange> Node::TransformTimeTo(const TimeRange &time, Node *target, Node
|
||||
foreach (NodeInput* input, inputs) {
|
||||
if (input->IsConnected()) {
|
||||
TimeRange input_adjustment = InputTimeAdjustment(input, time);
|
||||
Node* connected = input->get_connected_node();
|
||||
|
||||
if (input->get_connected_node() == target) {
|
||||
if (connected == target) {
|
||||
// We found the target, no need to keep traversing
|
||||
if (!paths_found.contains(input_adjustment)) {
|
||||
paths_found.append(input_adjustment);
|
||||
}
|
||||
} else {
|
||||
// We did NOT find the target, traverse this
|
||||
paths_found.append(TransformTimeTo(input_adjustment, target, direction));
|
||||
paths_found.append(connected->TransformTimeTo(input_adjustment, target, direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -567,7 +568,7 @@ QList<TimeRange> Node::TransformTimeTo(const TimeRange &time, Node *target, Node
|
||||
if (input_node == target) {
|
||||
paths_found.append(output_adjustment);
|
||||
} else {
|
||||
paths_found.append(TransformTimeTo(output_adjustment, target, direction));
|
||||
paths_found.append(input_node->TransformTimeTo(output_adjustment, target, direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -221,7 +221,7 @@ public:
|
||||
/**
|
||||
* @brief Find a node of a certain type that this Node outputs to
|
||||
*/
|
||||
const T* FindOutputNode() const;
|
||||
T* FindOutputNode();
|
||||
|
||||
/**
|
||||
* @brief Convert a pointer to a value that can be sent between NodeParams
|
||||
@@ -416,7 +416,7 @@ T* Node::ValueToPtr(const QVariant &ptr)
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const Node* FindOutputNodeInternal(const Node* n) {
|
||||
Node* FindOutputNodeInternal(Node* n) {
|
||||
foreach (NodeEdgePtr edge, n->output()->edges()) {
|
||||
Node* connected = edge->input()->parentNode();
|
||||
T* cast_test = dynamic_cast<T*>(connected);
|
||||
@@ -424,7 +424,7 @@ const Node* FindOutputNodeInternal(const Node* n) {
|
||||
if (cast_test) {
|
||||
return cast_test;
|
||||
} else {
|
||||
const Node* drill_test = FindOutputNodeInternal<T>(connected);
|
||||
Node* drill_test = FindOutputNodeInternal<T>(connected);
|
||||
if (drill_test) {
|
||||
return drill_test;
|
||||
}
|
||||
@@ -435,9 +435,9 @@ const Node* FindOutputNodeInternal(const Node* n) {
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* Node::FindOutputNode() const
|
||||
T* Node::FindOutputNode()
|
||||
{
|
||||
return static_cast<const T*>(FindOutputNodeInternal<T>(this));
|
||||
return static_cast<T*>(FindOutputNodeInternal<T>(this));
|
||||
}
|
||||
|
||||
#endif // NODE_H
|
||||
|
||||
@@ -18,6 +18,11 @@ void CurvePanel::SetInput(NodeInput *input)
|
||||
static_cast<CurveWidget*>(GetTimeBasedWidget())->SetInput(input);
|
||||
}
|
||||
|
||||
void CurvePanel::SetTimeTarget(Node *target)
|
||||
{
|
||||
static_cast<CurveWidget*>(GetTimeBasedWidget())->SetTimeTarget(target);
|
||||
}
|
||||
|
||||
void CurvePanel::IncreaseTrackHeight()
|
||||
{
|
||||
CurveWidget* c = static_cast<CurveWidget*>(GetTimeBasedWidget());
|
||||
|
||||
@@ -13,6 +13,8 @@ public:
|
||||
public slots:
|
||||
void SetInput(NodeInput* input);
|
||||
|
||||
void SetTimeTarget(Node* target);
|
||||
|
||||
virtual void IncreaseTrackHeight() override;
|
||||
|
||||
virtual void DecreaseTrackHeight() override;
|
||||
|
||||
+23
-17
@@ -26,7 +26,8 @@ PanelManager* PanelManager::instance_ = nullptr;
|
||||
|
||||
PanelManager::PanelManager(QObject *parent) :
|
||||
QObject(parent),
|
||||
locked_(false)
|
||||
locked_(false),
|
||||
last_focused_panel_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -106,26 +107,31 @@ void PanelManager::FocusChanged(QWidget *old, QWidget *now)
|
||||
// Use dynamic_cast to test if this object is a PanelWidget
|
||||
panel_cast_test = dynamic_cast<PanelWidget*>(parent);
|
||||
|
||||
if (panel_cast_test != nullptr) {
|
||||
// If so, bump this to the top of the focus history
|
||||
if (panel_cast_test) {
|
||||
|
||||
int panel_index = focus_history_.indexOf(panel_cast_test);
|
||||
if (last_focused_panel_ != panel_cast_test) {
|
||||
// If so, bump this to the top of the focus history
|
||||
int panel_index = focus_history_.indexOf(panel_cast_test);
|
||||
|
||||
// Force the old panel to repaint (if there is one) so it hides its border
|
||||
if (!focus_history_.isEmpty()) {
|
||||
focus_history_.first()->SetBorderVisible(false);
|
||||
// Disable highlight border on old panel
|
||||
if (!focus_history_.isEmpty()) {
|
||||
focus_history_.first()->SetBorderVisible(false);
|
||||
}
|
||||
|
||||
// Enable new border's highlight
|
||||
panel_cast_test->SetBorderVisible(true);
|
||||
|
||||
// If it's not in the focus history, prepend it, otherwise move it
|
||||
if (panel_index == -1) {
|
||||
focus_history_.prepend(panel_cast_test);
|
||||
} else {
|
||||
focus_history_.move(panel_index, 0);
|
||||
}
|
||||
|
||||
last_focused_panel_ = panel_cast_test;
|
||||
emit FocusedPanelChanged(panel_cast_test);
|
||||
}
|
||||
|
||||
// If it's not in the focus history, prepend it, otherwise move it
|
||||
if (panel_index == -1) {
|
||||
focus_history_.prepend(panel_cast_test);
|
||||
} else {
|
||||
focus_history_.move(panel_index, 0);
|
||||
}
|
||||
|
||||
// Force the panel to repaint so it shows a border
|
||||
panel_cast_test->SetBorderVisible(true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,12 @@ public slots:
|
||||
*/
|
||||
void SetPanelsLocked(bool locked);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when the currently focused panel changes
|
||||
*/
|
||||
void FocusedPanelChanged(PanelWidget* panel);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief History array for traversing through (see MostRecentlyFocused())
|
||||
@@ -146,6 +152,14 @@ private:
|
||||
* @brief PanelManager singleton instance
|
||||
*/
|
||||
static PanelManager* instance_;
|
||||
|
||||
/**
|
||||
* @brief The last panel that was focused
|
||||
*
|
||||
* Stored to prevent emitting FocusedPanelChanged() multiple times for the same panel
|
||||
*/
|
||||
PanelWidget* last_focused_panel_;
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -28,6 +28,7 @@ ParamPanel::ParamPanel(QWidget* parent) :
|
||||
|
||||
NodeParamView* view = new NodeParamView();
|
||||
connect(view, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged);
|
||||
connect(view, &NodeParamView::TimeTargetChanged, this, &ParamPanel::TimeTargetChanged);
|
||||
SetTimeBasedWidget(view);
|
||||
|
||||
Retranslate();
|
||||
|
||||
@@ -36,6 +36,8 @@ public slots:
|
||||
signals:
|
||||
void SelectedInputChanged(NodeInput* input);
|
||||
|
||||
void TimeTargetChanged(Node* node);
|
||||
|
||||
protected:
|
||||
virtual void Retranslate() override;
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ void CurveWidget::SetInput(NodeInput *input)
|
||||
if (input_) {
|
||||
bridge_ = new NodeParamViewWidgetBridge(input_, this);
|
||||
|
||||
bridge_->SetTimeTarget(GetTimeTarget());
|
||||
|
||||
for (int i=0;i<bridge_->widgets().size();i++) {
|
||||
// Insert between two stretches to center the widget
|
||||
widget_bridge_layout_->insertWidget(2 + i, bridge_->widgets().at(i));
|
||||
@@ -165,6 +167,17 @@ void CurveWidget::ScaleChangedEvent(const double &scale)
|
||||
view_->SetScale(scale);
|
||||
}
|
||||
|
||||
void CurveWidget::TimeTargetChangedEvent(Node *target)
|
||||
{
|
||||
key_control_->SetTimeTarget(target);
|
||||
|
||||
view_->SetTimeTarget(target);
|
||||
|
||||
if (bridge_) {
|
||||
bridge_->SetTimeTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveWidget::UpdateInputLabel()
|
||||
{
|
||||
if (input_) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "widget/nodeparamview/nodeparamviewwidgetbridge.h"
|
||||
#include "widget/timebased/timebased.h"
|
||||
|
||||
class CurveWidget : public TimeBasedWidget
|
||||
class CurveWidget : public TimeBasedWidget, public TimeTargetObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -31,6 +31,8 @@ protected:
|
||||
virtual void TimebaseChangedEvent(const rational &) override;
|
||||
virtual void ScaleChangedEvent(const double &) override;
|
||||
|
||||
virtual void TimeTargetChangedEvent(Node* target) override;
|
||||
|
||||
private:
|
||||
void UpdateInputLabel();
|
||||
|
||||
|
||||
@@ -24,5 +24,7 @@ set(OLIVE_SOURCES
|
||||
widget/keyframeview/keyframeviewitem.cpp
|
||||
widget/keyframeview/keyframeviewundo.h
|
||||
widget/keyframeview/keyframeviewundo.cpp
|
||||
widget/keyframeview/timetargetobject.h
|
||||
widget/keyframeview/timetargetobject.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -59,6 +59,7 @@ void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key)
|
||||
KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key)
|
||||
{
|
||||
KeyframeViewItem* item = new KeyframeViewItem(key);
|
||||
item->SetTimeTarget(GetTimeTarget());
|
||||
item->SetScale(GetScale());
|
||||
item_map_.insert(key.get(), item);
|
||||
scene()->addItem(item);
|
||||
@@ -87,9 +88,12 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
|
||||
dragging_bezier_point_ = dynamic_cast<BezierControlPointItem*>(item_under_cursor);
|
||||
|
||||
if (dragging_bezier_point_) {
|
||||
|
||||
dragging_bezier_point_start_ = dragging_bezier_point_->GetCorrespondingKeyframeHandle();
|
||||
dragging_bezier_point_opposing_start_ = dragging_bezier_point_->key()->bezier_control(NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode()));
|
||||
|
||||
} else {
|
||||
|
||||
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
|
||||
|
||||
selected_keys_.resize(selected_items.size());
|
||||
@@ -97,8 +101,12 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
KeyframeViewItem* key = static_cast<KeyframeViewItem*>(selected_items.at(i));
|
||||
|
||||
selected_keys_.replace(i, {key, key->x(), key->key()->time(), key->key()->value().toDouble()});
|
||||
selected_keys_.replace(i, {key,
|
||||
key->x(),
|
||||
GetAdjustedTime(key->key()->parent()->parentNode(), GetTimeTarget(), key->key()->time(), NodeParam::kOutput),
|
||||
key->key()->value().toDouble()});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +136,12 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
|
||||
|
||||
input_parent->blockSignals(true);
|
||||
|
||||
keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()));
|
||||
rational node_time = GetAdjustedTime(GetTimeTarget(),
|
||||
keypair.key->key()->parent()->parentNode(),
|
||||
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
|
||||
NodeParam::kInput);
|
||||
|
||||
keypair.key->key()->set_time(node_time);
|
||||
|
||||
if (y_axis_enabled_) {
|
||||
keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y());
|
||||
@@ -174,7 +187,10 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
|
||||
keypair.key->key()->parent()->blockSignals(true);
|
||||
|
||||
// Calculate the new time for this keyframe
|
||||
rational new_time = CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x());
|
||||
rational node_time = GetAdjustedTime(GetTimeTarget(),
|
||||
keypair.key->key()->parent()->parentNode(),
|
||||
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
|
||||
NodeParam::kInput);
|
||||
|
||||
|
||||
|
||||
@@ -185,7 +201,7 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
|
||||
// the signalling once the undo command is pushed.
|
||||
item->key()->set_time(keypair.time);
|
||||
new NodeParamSetKeyframeTimeCommand(item->key(),
|
||||
new_time,
|
||||
node_time,
|
||||
keypair.time,
|
||||
command);
|
||||
|
||||
@@ -234,6 +250,15 @@ void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *)
|
||||
{
|
||||
}
|
||||
|
||||
void KeyframeViewBase::TimeTargetChangedEvent(Node *target)
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
|
||||
|
||||
for (i=item_map_.begin();i!=item_map_.end();i++) {
|
||||
i.value()->SetTimeTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::SetYAxisEnabled(bool e)
|
||||
{
|
||||
y_axis_enabled_ = e;
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
#include "keyframeviewitem.h"
|
||||
#include "node/keyframe.h"
|
||||
#include "timetargetobject.h"
|
||||
#include "widget/curvewidget/beziercontrolpointitem.h"
|
||||
#include "widget/timelinewidget/view/timelineviewbase.h"
|
||||
|
||||
class KeyframeViewBase : public TimelineViewBase
|
||||
class KeyframeViewBase : public TimelineViewBase, public TimeTargetObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -35,6 +36,8 @@ protected:
|
||||
|
||||
virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key);
|
||||
|
||||
virtual void TimeTargetChangedEvent(Node*) override;
|
||||
|
||||
void SetYAxisEnabled(bool e);
|
||||
|
||||
private:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "node/input.h"
|
||||
|
||||
KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) :
|
||||
QGraphicsRectItem(parent),
|
||||
@@ -76,11 +77,16 @@ void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewItem::TimeTargetChangedEvent(Node *)
|
||||
{
|
||||
UpdatePos();
|
||||
}
|
||||
|
||||
void KeyframeViewItem::UpdatePos()
|
||||
{
|
||||
double x_center = key_->time().toDouble() * scale_;
|
||||
rational adjusted = GetAdjustedTime(key_->parent()->parentNode(), GetTimeTarget(), key_->time(), NodeParam::kOutput);
|
||||
|
||||
setPos(x_center, vert_center_);
|
||||
setPos(adjusted.toDouble() * scale_, vert_center_);
|
||||
}
|
||||
|
||||
void KeyframeViewItem::Redraw()
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#include <QGraphicsRectItem>
|
||||
|
||||
#include "node/keyframe.h"
|
||||
#include "timetargetobject.h"
|
||||
|
||||
class KeyframeViewItem : public QObject, public QGraphicsRectItem
|
||||
class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -20,6 +21,8 @@ public:
|
||||
protected:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
|
||||
virtual void TimeTargetChangedEvent(Node* ) override;
|
||||
|
||||
private:
|
||||
NodeKeyframePtr key_;
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "timetargetobject.h"
|
||||
|
||||
TimeTargetObject::TimeTargetObject() :
|
||||
time_target_(nullptr),
|
||||
path_index_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Node *TimeTargetObject::GetTimeTarget() const
|
||||
{
|
||||
return time_target_;
|
||||
}
|
||||
|
||||
void TimeTargetObject::SetTimeTarget(Node *target)
|
||||
{
|
||||
time_target_ = target;
|
||||
|
||||
TimeTargetChangedEvent(time_target_);
|
||||
}
|
||||
|
||||
void TimeTargetObject::SetPathIndex(int index)
|
||||
{
|
||||
path_index_ = index;
|
||||
}
|
||||
|
||||
rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, NodeParam::Type direction) const
|
||||
{
|
||||
if (!from || !to) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return GetAdjustedTime(from, to, TimeRange(r, r), direction).in();
|
||||
}
|
||||
|
||||
TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, NodeParam::Type direction) const
|
||||
{
|
||||
if (!from || !to) {
|
||||
return r;
|
||||
}
|
||||
|
||||
QList<TimeRange> adjusted = from->TransformTimeTo(r, to, direction);
|
||||
|
||||
if (adjusted.isEmpty()) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return adjusted.at(path_index_);
|
||||
}
|
||||
|
||||
/*int TimeTargetObject::GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const
|
||||
{
|
||||
if (!time_target_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<TimeRange> adjusted = from->TransformTimeTo(TimeRange(), time_target_, direction);
|
||||
|
||||
return adjusted.size();
|
||||
}*/
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef TIMETARGETOBJECT_H
|
||||
#define TIMETARGETOBJECT_H
|
||||
|
||||
#include "node/node.h"
|
||||
|
||||
class TimeTargetObject
|
||||
{
|
||||
public:
|
||||
TimeTargetObject();
|
||||
|
||||
Node* GetTimeTarget() const;
|
||||
void SetTimeTarget(Node* target);
|
||||
|
||||
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;
|
||||
|
||||
//int GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const;
|
||||
|
||||
protected:
|
||||
virtual void TimeTargetChangedEvent(Node* ){}
|
||||
|
||||
private:
|
||||
Node* time_target_;
|
||||
|
||||
int path_index_;
|
||||
|
||||
};
|
||||
|
||||
#endif // TIMETARGETOBJECT_H
|
||||
@@ -123,6 +123,7 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
delete item;
|
||||
}
|
||||
items_.clear();
|
||||
emit TimeTargetChanged(nullptr);
|
||||
|
||||
// Reset keyframe view
|
||||
SetTimebase(rational());
|
||||
@@ -149,21 +150,23 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
}
|
||||
|
||||
if (!nodes_.isEmpty()) {
|
||||
const ViewerOutput* viewer = nodes_.first()->FindOutputNode<ViewerOutput>();
|
||||
ViewerOutput* viewer = nodes_.first()->FindOutputNode<ViewerOutput>();
|
||||
|
||||
if (viewer) {
|
||||
SetTimebase(viewer->video_params().time_base());
|
||||
|
||||
// Set viewer as a time target
|
||||
keyframe_view_->SetTimeTarget(viewer);
|
||||
|
||||
foreach (NodeParamViewItem* item, items_) {
|
||||
item->SetTimeTarget(viewer);
|
||||
}
|
||||
|
||||
emit TimeTargetChanged(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
SetTime(0);
|
||||
|
||||
// FIXME: Test code only!
|
||||
if (nodes_.isEmpty()) {
|
||||
emit SelectedInputChanged(nullptr);
|
||||
} else {
|
||||
emit SelectedInputChanged(static_cast<NodeInput*>(nodes_.first()->parameters().first()));
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::resizeEvent(QResizeEvent *event)
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
signals:
|
||||
void SelectedInputChanged(NodeInput* input);
|
||||
|
||||
void TimeTargetChanged(Node* target);
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
|
||||
@@ -73,6 +73,17 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
void NodeParamViewItem::SetTimeTarget(Node *target)
|
||||
{
|
||||
foreach (NodeParamViewKeyframeControl* control, key_control_list_) {
|
||||
control->SetTimeTarget(target);
|
||||
}
|
||||
|
||||
foreach (NodeParamViewWidgetBridge* bridge, bridges_) {
|
||||
bridge->SetTimeTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::SetTime(const rational &time)
|
||||
{
|
||||
time_ = time;
|
||||
|
||||
@@ -46,6 +46,8 @@ class NodeParamViewItem : public QWidget
|
||||
public:
|
||||
NodeParamViewItem(Node* node, QWidget* parent = nullptr);
|
||||
|
||||
void SetTimeTarget(Node* target);
|
||||
|
||||
void SetTime(const rational& time);
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -102,6 +102,16 @@ void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e)
|
||||
enable_key_btn_->setEnabled(e);
|
||||
}
|
||||
|
||||
rational NodeParamViewKeyframeControl::GetCurrentTimeAsNodeTime() const
|
||||
{
|
||||
return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput);
|
||||
}
|
||||
|
||||
rational NodeParamViewKeyframeControl::ConvertToViewerTime(const rational &r) const
|
||||
{
|
||||
return GetAdjustedTime(input_->parentNode(), GetTimeTarget(), r, NodeParam::kOutput);
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e)
|
||||
{
|
||||
prev_key_btn_->setVisible(e);
|
||||
@@ -111,16 +121,18 @@ void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e)
|
||||
|
||||
void NodeParamViewKeyframeControl::ToggleKeyframe(bool e)
|
||||
{
|
||||
QList<NodeKeyframePtr> keys = input_->get_keyframe_at_time(time_);
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
QList<NodeKeyframePtr> keys = input_->get_keyframe_at_time(node_time);
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
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(time_,
|
||||
input_->get_value_at_time_for_track(time_, i),
|
||||
input_->get_best_keyframe_type_for_time(time_, 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);
|
||||
|
||||
new NodeParamInsertKeyframeCommand(input_, key, command);
|
||||
@@ -134,7 +146,7 @@ void NodeParamViewKeyframeControl::ToggleKeyframe(bool e)
|
||||
// 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(time_, key->track()),
|
||||
input_->get_value_at_time_for_track(node_time, key->track()),
|
||||
command);
|
||||
}
|
||||
}
|
||||
@@ -152,26 +164,36 @@ void NodeParamViewKeyframeControl::UpdateState()
|
||||
NodeKeyframePtr earliest_key = input_->get_earliest_keyframe();
|
||||
NodeKeyframePtr latest_key = input_->get_latest_keyframe();
|
||||
|
||||
prev_key_btn_->setEnabled(earliest_key && time_ > earliest_key->time());
|
||||
next_key_btn_->setEnabled(latest_key && time_ < latest_key->time());
|
||||
toggle_key_btn_->setChecked(input_->has_keyframe_at_time(time_));
|
||||
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));
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::GoToPreviousKey()
|
||||
{
|
||||
NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(time_);
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(node_time);
|
||||
|
||||
if (previous_key) {
|
||||
emit RequestSetTime(previous_key->time());
|
||||
rational key_time = ConvertToViewerTime(previous_key->time());
|
||||
|
||||
emit RequestSetTime(key_time);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::GoToNextKey()
|
||||
{
|
||||
NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(time_);
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(node_time);
|
||||
|
||||
if (next_key) {
|
||||
emit RequestSetTime(next_key->time());
|
||||
rational key_time = ConvertToViewerTime(next_key->time());
|
||||
|
||||
emit RequestSetTime(key_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +214,7 @@ void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e)
|
||||
QVector<QVariant> key_vals = input_->get_split_standard_value();
|
||||
|
||||
for (int i=0;i<key_vals.size();i++) {
|
||||
NodeKeyframePtr key = NodeKeyframe::Create(time_,
|
||||
NodeKeyframePtr key = NodeKeyframe::Create(GetCurrentTimeAsNodeTime(),
|
||||
key_vals.at(i),
|
||||
NodeKeyframe::kDefaultType,
|
||||
i);
|
||||
@@ -207,7 +229,7 @@ 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(time_);
|
||||
QVector<QVariant> stored_vals = input_->get_split_values_at_time(GetCurrentTimeAsNodeTime());
|
||||
|
||||
// Delete all keyframes
|
||||
foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) {
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "node/input.h"
|
||||
#include "widget/keyframeview/timetargetobject.h"
|
||||
|
||||
class NodeParamViewKeyframeControl : public QWidget
|
||||
class NodeParamViewKeyframeControl : public QWidget, public TimeTargetObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -26,6 +27,10 @@ private:
|
||||
|
||||
void SetButtonsEnabled(bool e);
|
||||
|
||||
rational GetCurrentTimeAsNodeTime() const;
|
||||
|
||||
rational ConvertToViewerTime(const rational& r) const;
|
||||
|
||||
QPushButton* prev_key_btn_;
|
||||
QPushButton* toggle_key_btn_;
|
||||
QPushButton* next_key_btn_;
|
||||
|
||||
@@ -36,80 +36,10 @@ void NodeParamViewWidgetBridge::SetTime(const rational &time)
|
||||
return;
|
||||
}
|
||||
|
||||
// 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::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;
|
||||
}
|
||||
UpdateWidgetValues();
|
||||
}
|
||||
|
||||
const QList<QWidget *> &NodeParamViewWidgetBridge::widgets()
|
||||
const QList<QWidget *> &NodeParamViewWidgetBridge::widgets() const
|
||||
{
|
||||
return widgets_;
|
||||
}
|
||||
@@ -207,18 +137,20 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
|
||||
void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value, int track)
|
||||
{
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
if (input_->is_keyframing()) {
|
||||
NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(time_, track);
|
||||
NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(node_time, track);
|
||||
|
||||
if (existing_key) {
|
||||
new NodeParamSetKeyframeValueCommand(existing_key, value, command);
|
||||
} else {
|
||||
// No existing key, create a new one
|
||||
NodeKeyframePtr new_key = NodeKeyframe::Create(time_,
|
||||
NodeKeyframePtr new_key = NodeKeyframe::Create(node_time,
|
||||
value,
|
||||
input_->get_best_keyframe_type_for_time(time_, track),
|
||||
input_->get_best_keyframe_type_for_time(node_time, track),
|
||||
track);
|
||||
|
||||
new NodeParamInsertKeyframeCommand(input_, new_key, command);
|
||||
@@ -232,6 +164,8 @@ void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value, int track)
|
||||
|
||||
void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant &value)
|
||||
{
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
int slider_track = widgets_.indexOf(slider);
|
||||
|
||||
if (slider->IsDragging()) {
|
||||
@@ -244,17 +178,17 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant
|
||||
dragging_ = true;
|
||||
|
||||
// Cache current value
|
||||
drag_old_value_ = input_->get_value_at_time_for_track(time_, slider_track);
|
||||
drag_old_value_ = input_->get_value_at_time_for_track(node_time, slider_track);
|
||||
|
||||
// Determine whether we are creating a keyframe or not
|
||||
if (input_->is_keyframing()) {
|
||||
dragging_keyframe_ = input_->get_keyframe_at_time_on_track(time_, slider_track);
|
||||
dragging_keyframe_ = input_->get_keyframe_at_time_on_track(node_time, slider_track);
|
||||
drag_created_keyframe_ = !dragging_keyframe_;
|
||||
|
||||
if (drag_created_keyframe_) {
|
||||
dragging_keyframe_ = NodeKeyframe::Create(time_,
|
||||
dragging_keyframe_ = NodeKeyframe::Create(node_time,
|
||||
value,
|
||||
input_->get_best_keyframe_type_for_time(time_, slider_track),
|
||||
input_->get_best_keyframe_type_for_time(node_time, slider_track),
|
||||
slider_track);
|
||||
|
||||
input_->insert_keyframe(dragging_keyframe_);
|
||||
@@ -406,11 +340,93 @@ void NodeParamViewWidgetBridge::CreateSliders(int count)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::UpdateWidgetValues()
|
||||
{
|
||||
rational node_time = GetCurrentTimeAsNodeTime();
|
||||
|
||||
// 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::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(node_time).toLongLong());
|
||||
break;
|
||||
case NodeParam::kFloat:
|
||||
static_cast<FloatSlider*>(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble());
|
||||
break;
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
QVector2D vec2 = input_->get_value_at_time(node_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(node_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(node_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(node_time).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kBoolean:
|
||||
static_cast<QCheckBox*>(widgets_.first())->setChecked(input_->get_value_at_time(node_time).toBool());
|
||||
break;
|
||||
case NodeParam::kFont:
|
||||
{
|
||||
// FIXME: Implement this
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFootage:
|
||||
static_cast<FootageComboBox*>(widgets_.first())->SetFootage(input_->get_value_at_time(node_time).value<StreamPtr>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const
|
||||
{
|
||||
return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput);
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::InputValueChanged(const rational &start, const rational &end)
|
||||
{
|
||||
if (!dragging_ && start <= time_ && end >= time_) {
|
||||
// We'll need to update the widgets because the values have changed on our current time
|
||||
SetTime(time_);
|
||||
UpdateWidgetValues();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "node/input.h"
|
||||
#include "widget/keyframeview/timetargetobject.h"
|
||||
#include "widget/slider/sliderbase.h"
|
||||
|
||||
class NodeParamViewWidgetBridge : public QObject
|
||||
class NodeParamViewWidgetBridge : public QObject, public TimeTargetObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -14,7 +15,7 @@ public:
|
||||
|
||||
void SetTime(const rational& time);
|
||||
|
||||
const QList<QWidget*>& widgets();
|
||||
const QList<QWidget*>& widgets() const;
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
@@ -25,6 +26,10 @@ private:
|
||||
|
||||
void CreateSliders(int count);
|
||||
|
||||
void UpdateWidgetValues();
|
||||
|
||||
rational GetCurrentTimeAsNodeTime() const;
|
||||
|
||||
NodeInput* input_;
|
||||
|
||||
QList<QWidget*> widgets_;
|
||||
|
||||
@@ -84,6 +84,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes);
|
||||
connect(param_panel_, &ParamPanel::SelectedInputChanged, curve_panel_, &CurvePanel::SetInput);
|
||||
connect(param_panel_, &ParamPanel::TimebaseChanged, curve_panel_, &CurvePanel::SetTimebase);
|
||||
connect(param_panel_, &ParamPanel::TimeTargetChanged, curve_panel_, &CurvePanel::SetTimeTarget);
|
||||
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime);
|
||||
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);
|
||||
connect(param_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime);
|
||||
@@ -91,6 +92,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(curve_panel_, &CurvePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime);
|
||||
connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime);
|
||||
|
||||
connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged);
|
||||
|
||||
sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_);
|
||||
sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_);
|
||||
|
||||
@@ -253,7 +256,6 @@ TimelinePanel* MainWindow::AppendTimelinePanel()
|
||||
connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime);
|
||||
connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);
|
||||
connect(panel, &TimelinePanel::SelectionChanged, node_panel_, &NodePanel::SelectWithDependencies);
|
||||
connect(panel, &TimelinePanel::visibilityChanged, this, &MainWindow::TimelineFocusedSlot);
|
||||
connect(param_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTime);
|
||||
connect(curve_panel_, &CurvePanel::TimeChanged, panel, &TimelinePanel::SetTime);
|
||||
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, panel, &TimelinePanel::SetTime);
|
||||
@@ -278,10 +280,12 @@ void MainWindow::TimelineFocused(TimelinePanel* panel)
|
||||
node_panel_->SetGraph(seq);
|
||||
}
|
||||
|
||||
void MainWindow::TimelineFocusedSlot(bool visible)
|
||||
void MainWindow::FocusedPanelChanged(PanelWidget *panel)
|
||||
{
|
||||
if (visible) {
|
||||
TimelineFocused(static_cast<TimelinePanel*>(sender()));
|
||||
TimelinePanel* timeline = dynamic_cast<TimelinePanel*>(panel);
|
||||
|
||||
if (timeline) {
|
||||
TimelineFocused(timeline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ private:
|
||||
CurvePanel* curve_panel_;
|
||||
|
||||
private slots:
|
||||
void TimelineFocusedSlot(bool visible);
|
||||
void FocusedPanelChanged(PanelWidget* panel);
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user