reworked much of keyframeview for new architecture

This commit is contained in:
itsmattkc
2021-12-13 14:12:30 -08:00
parent 090fbb09d0
commit 7d82d56f31
25 changed files with 852 additions and 754 deletions
+3
View File
@@ -55,6 +55,9 @@ else()
endif()
set(OLIVE_DEFINITIONS -DQT_DEPRECATED_WARNINGS)
if (WIN32)
list(APPEND OLIVE_DEFINITIONS -DUNICODE -D_UNICODE)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
-1
View File
@@ -29,7 +29,6 @@ ParamPanel::ParamPanel(QWidget* parent) :
{
NodeParamView* view = new NodeParamView();
connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode);
connect(view, &NodeParamView::NodeOrderChanged, this, &ParamPanel::NodeOrderChanged);
connect(view, &NodeParamView::FocusedNodeChanged, this, &ParamPanel::FocusedNodeChanged);
SetTimeBasedWidget(view);
-2
View File
@@ -48,8 +48,6 @@ public slots:
signals:
void RequestSelectNode(const QVector<Node*>& target);
void NodeOrderChanged(const QVector<Node*>& nodes);
void FocusedNodeChanged(Node* n);
protected:
+58 -96
View File
@@ -47,22 +47,6 @@ CurveView::CurveView(QWidget *parent) :
connect(scene(), &QGraphicsScene::selectionChanged, this, &CurveView::SelectionChanged);
}
CurveView::~CurveView()
{
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other members have been destroyed
Clear();
}
void CurveView::Clear()
{
KeyframeViewBase::Clear();
foreach (QGraphicsLineItem* line, lines_) {
delete line;
}
lines_.clear();
}
void CurveView::ConnectInput(const NodeKeyframeTrackReference& ref)
{
if (connected_inputs_.contains(ref)) {
@@ -71,7 +55,9 @@ void CurveView::ConnectInput(const NodeKeyframeTrackReference& ref)
}
// Add keyframes from track
AddKeyframesOfTrack(ref);
KeyframeViewInputConnection *track_con = AddKeyframesOfTrack(ref);
track_con->SetBrush(keyframe_colors_.value(ref));
track_connections_.insert(ref, track_con);
// Append to the list
connected_inputs_.append(ref);
@@ -85,7 +71,7 @@ void CurveView::DisconnectInput(const NodeKeyframeTrackReference& ref)
}
// Remove keyframes belonging to this element and track
RemoveKeyframesOfTrack(ref);
RemoveKeyframesOfTrack(track_connections_.take(ref));
// Remove from the list
connected_inputs_.removeOne(ref);
@@ -95,24 +81,16 @@ void CurveView::SelectKeyframesOfInput(const NodeKeyframeTrackReference& ref)
{
DeselectAll();
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.key()->key_track_ref() == ref) {
it.value()->setSelected(true);
foreach (KeyframeViewInputConnection *con, track_connections_) {
foreach (NodeKeyframe *key, con->GetKeyframes()) {
SelectKeyframe(key);
}
}
}
void CurveView::ZoomToFitInput(const NodeKeyframeTrackReference& ref)
{
QList<NodeKeyframe*> keys;
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.key()->key_track_ref() == ref) {
keys.append(it.key());
}
}
ZoomToFitInternal(keys);
ZoomToFitInternal(track_connections_.value(ref)->GetKeyframes());
}
void CurveView::SetKeyframeTrackColor(const NodeKeyframeTrackReference &ref, const QColor &color)
@@ -121,11 +99,7 @@ void CurveView::SetKeyframeTrackColor(const NodeKeyframeTrackReference &ref, con
keyframe_colors_.insert(ref, color);
// Update all keyframes
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.key()->key_track_ref() == ref) {
it.value()->SetOverrideBrush(color);
}
}
track_connections_.value(ref)->SetBrush(color);
}
void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
@@ -196,7 +170,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
QPainterPath path;
// Draw straight line leading to first keyframe
QPointF first_key_pos = item_map().value(track.first())->pos();
QPointF first_key_pos = GetKeyframePosition(track.first());
path.moveTo(QPointF(scene_bottom_left.x(), first_key_pos.y()));
path.lineTo(first_key_pos);
@@ -205,24 +179,24 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
NodeKeyframe* before = track.at(i-1);
NodeKeyframe* after = track.at(i);
KeyframeViewItem* before_item = item_map().value(before);
KeyframeViewItem* after_item = item_map().value(after);
QPointF before_pos = GetKeyframePosition(before);
QPointF after_pos = GetKeyframePosition(after);
if (before->type() == NodeKeyframe::kHold) {
// Draw a hold keyframe (basically a right angle)
path.lineTo(after_item->pos().x(), before_item->pos().y());
path.lineTo(after_item->pos().x(), after_item->pos().y());
path.lineTo(after_pos.x(), before_pos.y());
path.lineTo(after_pos.x(), after_pos.y());
} else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// Draw a cubic bezier
// Cubic beziers have two control points, so we can just use both
QPointF before_control_point = before_item->pos() + ScalePoint(before->valid_bezier_control_out());
QPointF after_control_point = after_item->pos() + ScalePoint(after->valid_bezier_control_in());
QPointF before_control_point = before_pos + ScalePoint(before->valid_bezier_control_out());
QPointF after_control_point = after_pos + ScalePoint(after->valid_bezier_control_in());
path.cubicTo(before_control_point, after_control_point, after_item->pos());
path.cubicTo(before_control_point, after_control_point, after_pos);
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
// Draw a quadratic bezier
@@ -232,10 +206,10 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
QPointF control_point;
if (before->type() == NodeKeyframe::kBezier) {
key_anchor = before_item->pos();
key_anchor = before_pos;
control_point = before->valid_bezier_control_out();
} else {
key_anchor = after_item->pos();
key_anchor = after_pos;
control_point = after->valid_bezier_control_in();
}
@@ -243,18 +217,18 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
control_point = key_anchor + ScalePoint(control_point);
// Create the path from both keyframes
path.quadTo(control_point, after_item->pos());
path.quadTo(control_point, after_pos);
} else {
// Linear to linear
path.lineTo(after_item->pos());
path.lineTo(after_pos);
}
}
// Draw straight line leading from end keyframe
QPointF last_key_pos = item_map().value(track.last())->pos();
QPointF last_key_pos = GetKeyframePosition(track.last());
path.lineTo(QPointF(scene_top_right.x(), last_key_pos.y()));
painter->drawPath(path);
@@ -263,7 +237,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
}
// Draw bezier control point lines
if (!bezier_control_points_.isEmpty()) {
/*if (!bezier_control_points_.isEmpty()) {
painter->setPen(QPen(palette().text().color(), 1));
QVector<QLineF> bezier_lines;
@@ -274,13 +248,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
bezier_lines.append(QLineF(par->pos(), par->pos() + item->pos()));
}
painter->drawLines(bezier_lines);
}
}
void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key)
{
disconnect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
disconnect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged);
}*/
}
void CurveView::ScaleChangedEvent(const double& scale)
@@ -296,13 +264,11 @@ void CurveView::VerticalScaleChangedEvent(double scale)
{
Q_UNUSED(scale)
for (auto iterator=item_map().begin();iterator!=item_map().end();iterator++) {
SetItemYFromKeyframeValue(iterator.value()->key(), iterator.value());
}
foreach (BezierControlPointItem* item, bezier_control_points_) {
item->SetYScale(scale);
}
viewport()->update();
}
void CurveView::ContextMenuEvent(Menu &m)
@@ -324,7 +290,7 @@ void CurveView::SceneRectUpdateEvent(QRectF &r)
r.setBottom(r.bottom() + this->height());
}
void CurveView::ZoomToFitInternal(const QList<NodeKeyframe *> &keys)
void CurveView::ZoomToFitInternal(const QVector<NodeKeyframe *> &keys)
{
if (keys.isEmpty()) {
// Prevent scaling to DBL_MIN/DBL_MAX
@@ -373,53 +339,58 @@ qreal CurveView::GetItemYFromKeyframeValue(double value)
return -value * GetYScale();
}
void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *item)
{
item->SetOverrideY(GetItemYFromKeyframeValue(key));
}
QPointF CurveView::ScalePoint(const QPointF &point)
{
// Flips Y coordinate because curves are drawn bottom to top
return QPointF(point.x() * GetScale(), - point.y() * GetYScale());
}
void CurveView::CreateBezierControlPoints(KeyframeViewItem* item)
void CurveView::CreateBezierControlPoints(NodeKeyframe* item)
{
BezierControlPointItem* bezier_in_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kInHandle, item);
qDebug() << "STUB!";
/*BezierControlPointItem* bezier_in_pt = new BezierControlPointItem(item, NodeKeyframe::kInHandle, item);
bezier_in_pt->SetXScale(GetScale());
bezier_in_pt->SetYScale(GetYScale());
bezier_control_points_.append(bezier_in_pt);
connect(bezier_in_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);
BezierControlPointItem* bezier_out_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kOutHandle, item);
BezierControlPointItem* bezier_out_pt = new BezierControlPointItem(item, NodeKeyframe::kOutHandle, item);
bezier_out_pt->SetXScale(GetScale());
bezier_out_pt->SetYScale(GetYScale());
bezier_control_points_.append(bezier_out_pt);
connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);
connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);*/
}
QPointF CurveView::GetKeyframePosition(NodeKeyframe *key)
{
return QPointF(GetKeyframeSceneX(key), GetItemYFromKeyframeValue(key));
}
void CurveView::KeyframeValueChanged()
{
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
qDebug() << "STUB!";
/*NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
KeyframeViewItem* item = item_map().value(key);
SetItemYFromKeyframeValue(key, item);
SetItemYFromKeyframeValue(key, item);*/
}
void CurveView::KeyframeTypeChanged()
{
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
qDebug() << "STUB!";
/*NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
KeyframeViewItem* item = item_map().value(key);
if (item->isSelected()) {
item->setSelected(false);
item->setSelected(true);
}
}*/
}
void CurveView::SelectionChanged()
{
qDebug() << "STUB!";
/*
// Clear current bezier handles
while (!bezier_control_points_.isEmpty()) {
delete bezier_control_points_.first();
@@ -434,6 +405,7 @@ void CurveView::SelectionChanged()
CreateBezierControlPoints(this_item);
}
}
*/
}
void CurveView::BezierControlPointDestroyed()
@@ -444,20 +416,22 @@ void CurveView::BezierControlPointDestroyed()
void CurveView::ZoomToFit()
{
ZoomToFitInternal(item_map().keys());
QVector<NodeKeyframe*> keys;
foreach (KeyframeViewInputConnection *con, track_connections_) {
foreach (NodeKeyframe *k, con->GetKeyframes()) {
if (!keys.contains(k)) {
keys.append(k);
}
}
}
ZoomToFitInternal(keys);
}
void CurveView::ZoomToFitSelected()
{
QList<NodeKeyframe*> selected_keys;
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.value()->isSelected()) {
selected_keys.append(it.key());
}
}
ZoomToFitInternal(selected_keys);
ZoomToFitInternal(GetSelectedKeyframes());
}
void CurveView::ResetZoom()
@@ -466,16 +440,4 @@ void CurveView::ResetZoom()
SetYScale(1.0);
}
KeyframeViewItem* CurveView::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = super::AddKeyframe(key);
SetItemYFromKeyframeValue(key, item);
item->SetOverrideBrush(keyframe_colors_.value(key->key_track_ref()));
connect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
connect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged);
return item;
}
}
+5 -13
View File
@@ -24,7 +24,6 @@
#include "beziercontrolpointitem.h"
#include "node/keyframe.h"
#include "widget/keyframeview/keyframeview.h"
#include "widget/keyframeview/keyframeviewitem.h"
namespace olive {
@@ -34,10 +33,6 @@ class CurveView : public KeyframeViewBase
public:
CurveView(QWidget* parent = nullptr);
virtual ~CurveView() override;
virtual void Clear() override;
void ConnectInput(const NodeKeyframeTrackReference &ref);
void DisconnectInput(const NodeKeyframeTrackReference &ref);
@@ -49,8 +44,6 @@ public:
void SetKeyframeTrackColor(const NodeKeyframeTrackReference& ref, const QColor& color);
public slots:
virtual KeyframeViewItem* AddKeyframe(NodeKeyframe* key) override;
void ZoomToFit();
void ZoomToFitSelected();
@@ -60,8 +53,6 @@ public slots:
protected:
virtual void drawBackground(QPainter* painter, const QRectF& rect) override;
virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override;
virtual void ScaleChangedEvent(const double &scale) override;
virtual void VerticalScaleChangedEvent(double scale) override;
@@ -71,20 +62,21 @@ protected:
virtual void SceneRectUpdateEvent(QRectF &r) override;
private:
void ZoomToFitInternal(const QList<NodeKeyframe *> &keys);
void ZoomToFitInternal(const QVector<NodeKeyframe *> &keys);
qreal GetItemYFromKeyframeValue(NodeKeyframe* key);
qreal GetItemYFromKeyframeValue(double value);
void SetItemYFromKeyframeValue(NodeKeyframe* key, KeyframeViewItem* item);
QPointF ScalePoint(const QPointF& point);
void AdjustLines();
void CreateBezierControlPoints(KeyframeViewItem *item);
void CreateBezierControlPoints(NodeKeyframe *item);
QPointF GetKeyframePosition(NodeKeyframe *key);
QHash<NodeKeyframeTrackReference, QColor> keyframe_colors_;
QHash<NodeKeyframeTrackReference, KeyframeViewInputConnection*> track_connections_;
int text_padding_;
+8 -35
View File
@@ -113,12 +113,6 @@ CurveWidget::CurveWidget(QWidget *parent) :
SetScale(120.0);
}
CurveWidget::~CurveWidget()
{
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other members have been destroyed
view_->Clear();
}
const double &CurveWidget::GetVerticalScale()
{
return view_->GetYScale();
@@ -223,15 +217,6 @@ void CurveWidget::ConnectNode(Node *node, bool connect)
ConnectInput(node, input, connect);
}
}
// Connect add/remove signals
if (connect) {
QObject::connect(node, &Node::KeyframeAdded, this, &CurveWidget::AddKeyframe);
QObject::connect(node, &Node::KeyframeRemoved, this, &CurveWidget::RemoveKeyframe);
} else {
QObject::disconnect(node, &Node::KeyframeAdded, this, &CurveWidget::AddKeyframe);
QObject::disconnect(node, &Node::KeyframeRemoved, this, &CurveWidget::RemoveKeyframe);
}
}
void CurveWidget::ConnectInput(Node *node, const QString &input, bool connect)
@@ -287,20 +272,20 @@ void CurveWidget::ConnectInput(Node *node, const QString &input, bool connect)
void CurveWidget::SelectionChanged()
{
QList<QGraphicsItem*> selected = view_->scene()->selectedItems();
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
SetKeyframeButtonChecked(false);
SetKeyframeButtonEnabled(!selected.isEmpty());
if (!selected.isEmpty()) {
bool all_same_type = true;
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(selected.first())->key()->type();
NodeKeyframe::Type type = selected.first()->type();
for (int i=1;i<selected.size();i++) {
KeyframeViewItem* prev_item = static_cast<KeyframeViewItem*>(selected.at(i-1));
KeyframeViewItem* this_item = static_cast<KeyframeViewItem*>(selected.at(i));
NodeKeyframe* prev_item = selected.at(i-1);
NodeKeyframe* this_item = selected.at(i);
if (prev_item->key()->type() != this_item->key()->type()) {
if (prev_item->type() != this_item->type()) {
all_same_type = false;
break;
}
@@ -323,7 +308,7 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
}
// Get selected items and do nothing if there are none
QList<QGraphicsItem*> selected = view_->scene()->selectedItems();
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
if (selected.isEmpty()) {
return;
}
@@ -345,10 +330,8 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
MultiUndoCommand* command = new MultiUndoCommand();
foreach (QGraphicsItem* item, selected) {
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(item);
command->add_child(new KeyframeSetTypeCommand(key_item->key(), new_type));
foreach (NodeKeyframe* item, selected) {
command->add_child(new KeyframeSetTypeCommand(item, new_type));
}
Core::instance()->undo_stack()->push(command);
@@ -368,16 +351,6 @@ void CurveWidget::InputEnabledChanged(const NodeKeyframeTrackReference& ref, boo
}
}
void CurveWidget::AddKeyframe(NodeKeyframe *key)
{
view_->AddKeyframe(key);
}
void CurveWidget::RemoveKeyframe(NodeKeyframe *key)
{
view_->RemoveKeyframe(key);
}
void CurveWidget::InputSelectionChanged(const NodeKeyframeTrackReference& ref)
{
key_control_->SetInput(ref.input());
-6
View File
@@ -40,8 +40,6 @@ class CurveWidget : public TimeBasedWidget, public TimeTargetObject
public:
CurveWidget(QWidget* parent = nullptr);
virtual ~CurveWidget() override;
const double& GetVerticalScale();
void SetVerticalScale(const double& vscale);
@@ -107,10 +105,6 @@ private slots:
void InputEnabledChanged(const NodeKeyframeTrackReference &ref, bool e);
void AddKeyframe(NodeKeyframe* key);
void RemoveKeyframe(NodeKeyframe* key);
void InputSelectionChanged(const NodeKeyframeTrackReference& ref);
void InputDoubleClicked(const NodeKeyframeTrackReference& ref);
+5 -5
View File
@@ -16,13 +16,13 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/keyframeview/keyframeview.h
widget/keyframeview/keyframeview.cpp
widget/keyframeview/keyframeviewbase.h
widget/keyframeview/keyframeview.h
widget/keyframeview/keyframeviewbase.cpp
widget/keyframeview/keyframeviewitem.h
widget/keyframeview/keyframeviewitem.cpp
widget/keyframeview/keyframeviewundo.h
widget/keyframeview/keyframeviewbase.h
widget/keyframeview/keyframeviewinputconnection.cpp
widget/keyframeview/keyframeviewinputconnection.h
widget/keyframeview/keyframeviewundo.cpp
widget/keyframeview/keyframeviewundo.h
PARENT_SCOPE
)
-19
View File
@@ -31,29 +31,10 @@ KeyframeView::KeyframeView(QWidget *parent) :
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void KeyframeView::SetElementY(const NodeInput &c, int y)
{
qreal scene_y = mapToScene(mapFromGlobal(QPoint(0, y))).y();
element_y_.insert(c, scene_y);
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.key()->key_track_ref().input() == c) {
it.value()->SetOverrideY(scene_y);
}
}
}
void KeyframeView::SceneRectUpdateEvent(QRectF &rect)
{
rect.setY(0);
rect.setHeight(max_scroll_);
}
KeyframeViewItem* KeyframeView::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = super::AddKeyframe(key);
item->SetOverrideY(element_y_.value(key->key_track_ref().input()));
return item;
}
}
+1 -7
View File
@@ -34,19 +34,13 @@ public:
void SetMaxScroll(int i)
{
max_scroll_ = i;
UpdateSceneRect();
}
void SetElementY(const NodeInput& c, int y);
protected:
virtual void SceneRectUpdateEvent(QRectF& rect) override;
public slots:
virtual KeyframeViewItem* AddKeyframe(NodeKeyframe* key) override;
private:
QHash<NodeInput, qreal> element_y_;
int max_scroll_;
};
+210 -231
View File
@@ -24,6 +24,7 @@
#include <QToolTip>
#include <QVBoxLayout>
#include "common/qtutils.h"
#include "dialog/keyframeproperties/keyframeproperties.h"
#include "keyframeviewundo.h"
#include "node/node.h"
@@ -33,201 +34,144 @@
namespace olive {
#define super TimeBasedView
KeyframeViewBase::KeyframeViewBase(QWidget *parent) :
TimeBasedView(parent),
super(parent),
dragging_bezier_point_(nullptr),
currently_autoselecting_(false),
dragging_(false)
dragging_(false),
selection_manager_(this)
{
SetDefaultDragMode(RubberBandDrag);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &KeyframeViewBase::customContextMenuRequested, this, &KeyframeViewBase::ShowContextMenu);
connect(scene(), &QGraphicsScene::selectionChanged, this, &KeyframeViewBase::AutoSelectKeyTimeNeighbors);
}
void KeyframeViewBase::Clear()
{
QMap<NodeKeyframe*, KeyframeViewItem*>::iterator iterator;
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
delete iterator.value();
}
item_map_.clear();
}
void KeyframeViewBase::DeleteSelected()
{
MultiUndoCommand* command = new MultiUndoCommand();
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
if (i.value()->isSelected()) {
command->add_child(new NodeParamRemoveKeyframeCommand(i.key()));
}
foreach (NodeKeyframe *key, GetSelectedKeyframes()) {
command->add_child(new NodeParamRemoveKeyframeCommand(key));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void KeyframeViewBase::AddKeyframesOfNode(Node *n)
KeyframeViewBase::NodeConnections KeyframeViewBase::AddKeyframesOfNode(Node *n)
{
NodeConnections map;
foreach (const QString& i, n->inputs()) {
AddKeyframesOfInput(n, i);
map.insert(i, AddKeyframesOfInput(n, i));
}
return map;
}
void KeyframeViewBase::AddKeyframesOfInput(Node* n, const QString& input)
KeyframeViewBase::InputConnections KeyframeViewBase::AddKeyframesOfInput(Node* n, const QString& input)
{
if (!n->IsInputKeyframable(input)) {
return;
InputConnections vec;
if (n->IsInputKeyframable(input)) {
int arr_sz = n->InputArraySize(input);
vec.resize(arr_sz + 1);
for (int i=-1; i<arr_sz; i++) {
vec[i+1] = AddKeyframesOfElement(NodeInput(n, input, i));
}
}
int arr_sz = n->InputArraySize(input);
for (int i=-1; i<arr_sz; i++) {
AddKeyframesOfElement(NodeInput(n, input, i));
}
return vec;
}
void KeyframeViewBase::AddKeyframesOfElement(const NodeInput& input)
KeyframeViewBase::ElementConnections KeyframeViewBase::AddKeyframesOfElement(const NodeInput& input)
{
const QVector<NodeKeyframeTrack>& tracks = input.node()->GetKeyframeTracks(input);
ElementConnections vec(tracks.size());
for (int i=0; i<tracks.size(); i++) {
AddKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
vec[i] = AddKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
}
return vec;
}
void KeyframeViewBase::AddKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
KeyframeViewInputConnection *KeyframeViewBase::AddKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
{
const QVector<NodeKeyframeTrack>& tracks = ref.input().node()->GetKeyframeTracks(ref.input());
const NodeKeyframeTrack& t = tracks.at(ref.track());
foreach (NodeKeyframe* key, t) {
AddKeyframe(key);
}
KeyframeViewInputConnection *track = new KeyframeViewInputConnection(ref, this);
connect(track, &KeyframeViewInputConnection::RequireUpdate, this, &KeyframeViewBase::Redraw);
tracks_.append(track);
Redraw();
return track;
}
void KeyframeViewBase::RemoveKeyframesOfNode(Node *n)
void KeyframeViewBase::RemoveKeyframesOfTrack(KeyframeViewInputConnection *connection)
{
foreach (const QString& i, n->inputs()) {
RemoveKeyframesOfInput(n, i);
}
}
void KeyframeViewBase::RemoveKeyframesOfInput(Node* n, const QString& input)
{
if (!n->IsInputKeyframable(input)) {
return;
}
int arr_sz = n->InputArraySize(input);
for (int i=-1; i<arr_sz; i++) {
RemoveKeyframesOfElement(NodeInput(n, input, i));
}
}
void KeyframeViewBase::RemoveKeyframesOfElement(const NodeInput& input)
{
const QVector<NodeKeyframeTrack>& tracks = input.node()->GetKeyframeTracks(input);
for (int i=0; i<tracks.size(); i++) {
RemoveKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
}
}
void KeyframeViewBase::RemoveKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
{
const QVector<NodeKeyframeTrack>& tracks = ref.input().node()->GetKeyframeTracks(ref.input());
const NodeKeyframeTrack& t = tracks.at(ref.track());
foreach (NodeKeyframe* key, t) {
RemoveKeyframe(key);
if (tracks_.removeOne(connection)) {
delete connection;
Redraw();
}
}
void KeyframeViewBase::SelectAll()
{
for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
it.value()->setSelected(true);
foreach (KeyframeViewInputConnection *track, tracks_) {
foreach (NodeKeyframe *key, track->GetKeyframes()) {
SelectKeyframe(key);
}
}
}
void KeyframeViewBase::DeselectAll()
{
for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
it.value()->setSelected(false);
}
selection_manager_.ClearSelection();
Redraw();
}
void KeyframeViewBase::RemoveKeyframe(NodeKeyframe* key)
void KeyframeViewBase::Clear()
{
KeyframeAboutToBeRemoved(key);
delete item_map_.take(key);
}
KeyframeViewItem *KeyframeViewBase::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = item_map_.value(key);
if (!item) {
item = new KeyframeViewItem(key);
item->SetTimeTarget(GetTimeTarget());
item->SetScale(GetScale());
item_map_.insert(key, item);
scene()->addItem(item);
if (!tracks_.isEmpty()) {
qDeleteAll(tracks_);
tracks_.clear();
Redraw();
}
return item;
}
void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
{
QGraphicsItem* item_under_cursor = itemAt(event->pos());
NodeKeyframe *key_under_cursor = selection_manager_.MousePress(event);
if (key_under_cursor) {
AutoSelectKeyTimeNeighbors();
}
if (HandPress(event) || (!item_under_cursor && PlayheadPress(event))) {
BezierControlPointItem *bezier_under_cursor = dynamic_cast<BezierControlPointItem*>(itemAt(event->pos()));
Redraw();
if (HandPress(event) || (!bezier_under_cursor && !key_under_cursor && PlayheadPress(event))) {
return;
}
active_tool_ = Core::instance()->tool();
if (event->button() == Qt::LeftButton) {
QGraphicsView::mousePressEvent(event);
if (key_under_cursor || bezier_under_cursor) {
dragging_ = true;
drag_start_ = mapToScene(event->pos());
if (active_tool_ == Tool::kPointer) {
if (item_under_cursor) {
// Determine what type of item is under the cursor
dragging_bezier_point_ = bezier_under_cursor;
dragging_ = true;
drag_start_ = mapToScene(event->pos());
if (dragging_bezier_point_) {
// Determine what type of item is under the cursor
dragging_bezier_point_ = dynamic_cast<BezierControlPointItem*>(item_under_cursor);
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()));
if (dragging_bezier_point_) {
} else {
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()));
selection_manager_.DragStart(key_under_cursor, event);
} else {
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
selected_keys_.resize(selected_items.size());
initial_drag_item_ = static_cast<KeyframeViewItem*>(item_under_cursor);
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(),
GetAdjustedTime(key->key()->parent(), GetTimeTarget(), key->key()->time(), false),
key->key()->value().toDouble()});
}
}
}
}
}
@@ -240,11 +184,10 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
}
if (event->buttons() & Qt::LeftButton) {
QGraphicsView::mouseMoveEvent(event);
if (dragging_) {
// Calculate cursor difference and scale it
QPointF mouse_diff_scaled = GetScaledCursorPos(mapToScene(event->pos()) - drag_start_);
QPointF scene_pos = mapToScene(event->pos());
QPointF mouse_diff_scaled = GetScaledCursorPos(scene_pos - drag_start_);
if (event->modifiers() & Qt::ShiftModifier) {
// If holding shift, only move one axis
@@ -284,15 +227,19 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
QPointF bezier_pos = dragging_bezier_point_->pos() + dragging_bezier_point_->parentItem()->pos();
emit Dragged(qRound(bezier_pos.x()), qRound(bezier_pos.y()));
} else if (!selected_keys_.isEmpty()) {
} else if (selection_manager_.IsDragging()) {
QString tip;
/*
// Validate movement - ensure no keyframe goes above its max point or below its min point
FloatSlider::DisplayType display_type = FloatSlider::kNormal;
if (IsYAxisEnabled()) {
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
Node* node = keypair.key->key()->parent();
const QString& input = keypair.key->key()->input();
foreach (const KeyframeItemAndTime& keypair, dragging_keyframes_) {
NodeKeyframe *key = keypair.key;
Node* node = key->parent();
const QString& input = key->input();
double new_val = keypair.value - mouse_diff_scaled.y();
double limited = new_val;
@@ -309,48 +256,37 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
}
}
Node* initial_drag_input = initial_drag_item_->key()->parent();
const QString& initial_drag_input_id = initial_drag_item_->key()->input();
Node* initial_drag_input = initial_drag_item_->parent();
const QString& initial_drag_input_id = initial_drag_item_->input();
if (initial_drag_input->HasInputProperty(initial_drag_input_id, QStringLiteral("view"))) {
display_type = static_cast<FloatSlider::DisplayType>(initial_drag_input->GetInputProperty(initial_drag_input_id, QStringLiteral("view")).toInt());
}
}
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
rational node_time = GetAdjustedTime(GetTimeTarget(),
keypair.key->key()->parent(),
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
true);
keypair.key->key()->set_time(node_time);
foreach (const KeyframeItemAndTime& keypair, dragging_keyframes_) {
if (IsYAxisEnabled()) {
keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y());
key->set_value(keypair.value - mouse_diff_scaled.y());
}
}
// Show information about this keyframe
QString tip = Timecode::time_to_timecode(initial_drag_item_->key()->time(), timebase(),
Core::instance()->GetTimecodeDisplay(), false);
if (IsYAxisEnabled()) {
bool ok;
double num_value = initial_drag_item_->key()->value().toDouble(&ok);
double num_value = initial_drag_item_->value().toDouble(&ok);
if (ok) {
tip.append('\n');
tip = QStringLiteral("%1\n");
tip.append(FloatSlider::ValueToString(num_value, display_type, 2, true));
}
// Force viewport to update since Qt might try to optimize it out if the keyframe is
// offscreen
viewport()->update();
}
*/
QToolTip::hideText();
QToolTip::showText(QCursor::pos(), tip);
selection_manager_.DragMove(event, tip);
emit Dragged(qRound(initial_drag_item_->x()), qRound(initial_drag_item_->y()));
Redraw();
emit Dragged(scene_pos.x(), scene_pos.y());
}
}
@@ -364,8 +300,6 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
}
if (event->button() == Qt::LeftButton) {
QGraphicsView::mouseReleaseEvent(event);
if (dragging_) {
if (dragging_bezier_point_) {
MultiUndoCommand* command = new MultiUndoCommand();
@@ -388,30 +322,19 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
dragging_bezier_point_ = nullptr;
Core::instance()->undo_stack()->push(command);
} else if (!selected_keys_.isEmpty()) {
} else if (selection_manager_.IsDragging()) {
MultiUndoCommand* command = new MultiUndoCommand();
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
NodeKeyframe* item = keypair.key->key();
// Commit movement
command->add_child(new NodeParamSetKeyframeTimeCommand(item,
item->time(),
keypair.time));
// Commit value if we're setting a value
if (IsYAxisEnabled()) {
command->add_child(new NodeParamSetKeyframeValueCommand(item,
item->value(),
keypair.value));
}
}
selection_manager_.DragStop(command);
/*if (IsYAxisEnabled()) {
command->add_child(new NodeParamSetKeyframeValueCommand(item,
item->value(),
keypair.value));
}*/
Core::instance()->undo_stack()->push(command);
}
selected_keys_.clear();
dragging_ = false;
QToolTip::hideText();
@@ -419,31 +342,77 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
}
}
void KeyframeViewBase::drawForeground(QPainter *painter, const QRectF &rect)
{
int key_sz = QtUtils::QFontMetricsWidth(fontMetrics(), "Oi");
int key_rad = key_sz/2;
selection_manager_.ClearDrawnObjects();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
foreach (KeyframeViewInputConnection *track, tracks_) {
foreach (NodeKeyframe *key, track->GetKeyframes()) {
QRectF key_rect(-key_rad, -key_rad, key_sz, key_sz);
key_rect.translate(GetKeyframeSceneX(key), mapFromGlobal(QPoint(0, track->GetKeyframeY())).y());
if (!rect.intersects(key_rect)) {
continue;
}
if (IsKeyframeSelected(key)) {
painter->setBrush(palette().highlight());
} else {
painter->setBrush(track->GetBrush());
}
selection_manager_.DeclareDrawnObject(key, key_rect);
switch (key->type()) {
case NodeKeyframe::kLinear:
{
QPointF points[] = {
QPointF(key_rect.center().x(), key_rect.top()),
QPointF(key_rect.right(), key_rect.center().y()),
QPointF(key_rect.center().x(), key_rect.bottom()),
QPointF(key_rect.left(), key_rect.center().y())
};
painter->drawPolygon(points, 4);
break;
}
case NodeKeyframe::kBezier:
painter->drawEllipse(key_rect);
break;
case NodeKeyframe::kHold:
painter->drawRect(key_rect);
break;
}
}
}
super::drawForeground(painter, rect);
}
void KeyframeViewBase::ScaleChangedEvent(const double &scale)
{
TimeBasedView::ScaleChangedEvent(scale);
super::ScaleChangedEvent(scale);
for (auto iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
iterator.value()->SetScale(scale);
}
}
const QMap<NodeKeyframe *, KeyframeViewItem *> &KeyframeViewBase::item_map() const
{
return item_map_;
}
void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *)
{
Redraw();
}
void KeyframeViewBase::TimeTargetChangedEvent(Node *target)
{
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
Redraw();
}
for (i=item_map_.begin();i!=item_map_.end();i++) {
i.value()->SetTimeTarget(target);
}
void KeyframeViewBase::TimebaseChangedEvent(const rational &timebase)
{
super::TimebaseChangedEvent(timebase);
selection_manager_.SetTimebase(timebase);
}
void KeyframeViewBase::ContextMenuEvent(Menu& m)
@@ -451,6 +420,30 @@ void KeyframeViewBase::ContextMenuEvent(Menu& m)
Q_UNUSED(m)
}
void KeyframeViewBase::SelectKeyframe(NodeKeyframe *key)
{
if (selection_manager_.Select(key)) {
Redraw();
}
}
void KeyframeViewBase::DeselectKeyframe(NodeKeyframe *key)
{
if (selection_manager_.Deselect(key)) {
Redraw();
}
}
rational KeyframeViewBase::GetAdjustedKeyframeTime(NodeKeyframe *key)
{
return GetAdjustedTime(key->parent(), GetTimeTarget(), key->time(), false);
}
double KeyframeViewBase::GetKeyframeSceneX(NodeKeyframe *key)
{
return TimeToScene(GetAdjustedKeyframeTime(key));
}
rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time, double cursor_diff)
{
return rational::fromDouble(old_time.toDouble() + cursor_diff);
@@ -492,16 +485,15 @@ void KeyframeViewBase::ShowContextMenu()
QAction* bezier_key_action = nullptr;
QAction* hold_key_action = nullptr;
QList<QGraphicsItem*> items = scene()->selectedItems();
if (!items.isEmpty()) {
if (!GetSelectedKeyframes().isEmpty()) {
bool all_keys_are_same_type = true;
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(items.first())->key()->type();
NodeKeyframe::Type type = GetSelectedKeyframes().first()->type();
for (int i=1;i<items.size();i++) {
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(items.at(i));
KeyframeViewItem* prev_item = static_cast<KeyframeViewItem*>(items.at(i-1));
for (int i=1;i<GetSelectedKeyframes().size();i++) {
NodeKeyframe* key_item = GetSelectedKeyframes().at(i);
NodeKeyframe* prev_item = GetSelectedKeyframes().at(i-1);
if (key_item->key()->type() != prev_item->key()->type()) {
if (key_item->type() != prev_item->type()) {
all_keys_are_same_type = false;
break;
}
@@ -536,7 +528,7 @@ void KeyframeViewBase::ShowContextMenu()
ContextMenuEvent(m);
if (!items.isEmpty()) {
if (!GetSelectedKeyframes().isEmpty()) {
m.addSeparator();
QAction* properties_action = m.addAction(tr("P&roperties"));
@@ -546,7 +538,7 @@ void KeyframeViewBase::ShowContextMenu()
QAction* selected = m.exec(QCursor::pos());
// Process keyframe type changes
if (!items.isEmpty()) {
if (selected) {
if (selected == linear_key_action
|| selected == bezier_key_action
|| selected == hold_key_action) {
@@ -561,26 +553,18 @@ void KeyframeViewBase::ShowContextMenu()
}
MultiUndoCommand* command = new MultiUndoCommand();
foreach (QGraphicsItem* item, items) {
command->add_child(new KeyframeSetTypeCommand(static_cast<KeyframeViewItem*>(item)->key(),
new_type));
foreach (NodeKeyframe* item, GetSelectedKeyframes()) {
command->add_child(new KeyframeSetTypeCommand(item, new_type));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
Core::instance()->undo_stack()->push(command);
}
}
}
void KeyframeViewBase::ShowKeyframePropertiesDialog()
{
QList<QGraphicsItem*> items = scene()->selectedItems();
QVector<NodeKeyframe*> keys;
foreach (QGraphicsItem* item, items) {
keys.append(static_cast<KeyframeViewItem*>(item)->key());
}
if (!keys.isEmpty()) {
KeyframePropertiesDialog kd(keys, timebase(), this);
if (!GetSelectedKeyframes().isEmpty()) {
KeyframePropertiesDialog kd(GetSelectedKeyframes(), timebase(), this);
kd.exec();
}
}
@@ -594,25 +578,15 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors()
// Prevents infinite loop
currently_autoselecting_ = true;
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
QVector<NodeKeyframe*> copy = GetSelectedKeyframes();
foreach (NodeKeyframe *key, copy) {
rational key_time = key->time();
foreach (QGraphicsItem* g, selected_items) {
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(g);
rational key_time = key_item->key()->time();
QVector<NodeKeyframe*> keys = key_item->key()->parent()->GetKeyframesAtTime(key_item->key()->input(), key_time, key_item->key()->element());
QVector<NodeKeyframe*> keys = key->parent()->GetKeyframesAtTime(key->input(), key_time, key->element());
foreach (NodeKeyframe* k, keys) {
if (k == key_item->key()) {
continue;
}
// Ensure this key is not already selected
KeyframeViewItem* item = item_map_.value(k);
if (item) {
item->setSelected(true);
if (k != key) {
SelectKeyframe(k);
}
}
}
@@ -620,4 +594,9 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors()
currently_autoselecting_ = false;
}
void KeyframeViewBase::Redraw()
{
viewport()->update();
}
}
+39 -36
View File
@@ -21,11 +21,12 @@
#ifndef KEYFRAMEVIEWBASE_H
#define KEYFRAMEVIEWBASE_H
#include "keyframeviewitem.h"
#include "keyframeviewinputconnection.h"
#include "node/keyframe.h"
#include "widget/curvewidget/beziercontrolpointitem.h"
#include "widget/menu/menu.h"
#include "widget/timebased/timebasedview.h"
#include "widget/timebased/timebasedviewselectionmanager.h"
#include "widget/timetarget/timetarget.h"
namespace olive {
@@ -36,51 +37,49 @@ class KeyframeViewBase : public TimeBasedView, public TimeTargetObject
public:
KeyframeViewBase(QWidget* parent = nullptr);
virtual void Clear();
void DeleteSelected();
void AddKeyframesOfNode(Node* n);
using ElementConnections = QVector<KeyframeViewInputConnection *>;
using InputConnections = QVector<ElementConnections>;
using NodeConnections = QMap<QString, InputConnections>;
void AddKeyframesOfInput(Node *n, const QString &input);
NodeConnections AddKeyframesOfNode(Node* n);
void AddKeyframesOfElement(const NodeInput &input);
InputConnections AddKeyframesOfInput(Node *n, const QString &input);
void AddKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
ElementConnections AddKeyframesOfElement(const NodeInput &input);
void RemoveKeyframesOfNode(Node* n);
KeyframeViewInputConnection *AddKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
void RemoveKeyframesOfInput(Node *n, const QString &input);
void RemoveKeyframesOfElement(const NodeInput &input);
void RemoveKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
void RemoveKeyframesOfTrack(KeyframeViewInputConnection *connection);
void SelectAll();
void DeselectAll();
void Clear();
const QVector<NodeKeyframe*> &GetSelectedKeyframes() const
{
return selection_manager_.GetSelectedObjects();
}
signals:
void Dragged(int current_x, int current_y);
public slots:
virtual KeyframeViewItem* AddKeyframe(NodeKeyframe* key);
void RemoveKeyframe(NodeKeyframe* key);
protected:
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
virtual void ScaleChangedEvent(const double& scale) override;
const QMap<NodeKeyframe*, KeyframeViewItem*>& item_map() const;
virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key);
virtual void TimeTargetChangedEvent(Node*) override;
virtual void TimebaseChangedEvent(const rational &timebase) override;
virtual void ContextMenuEvent(Menu &m);
bool IsDragging() const
@@ -88,6 +87,19 @@ protected:
return dragging_;
}
void SelectKeyframe(NodeKeyframe *key);
void DeselectKeyframe(NodeKeyframe *key);
bool IsKeyframeSelected(NodeKeyframe *key) const
{
return selection_manager_.IsSelected(key);
}
rational GetAdjustedKeyframeTime(NodeKeyframe *key);
double GetKeyframeSceneX(NodeKeyframe *key);
private:
rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff);
@@ -97,31 +109,20 @@ private:
QPointF GetScaledCursorPos(const QPointF &cursor_pos);
struct KeyframeItemAndTime {
KeyframeViewItem* key;
qreal item_x;
rational time;
double value;
};
QMap<NodeKeyframe*, KeyframeViewItem*> item_map_;
Tool::Item active_tool_;
QPointF drag_start_;
BezierControlPointItem* dragging_bezier_point_;
QPointF dragging_bezier_point_start_;
QPointF dragging_bezier_point_opposing_start_;
KeyframeViewItem* initial_drag_item_;
QVector<KeyframeItemAndTime> selected_keys_;
QVector<KeyframeViewInputConnection*> tracks_;
bool currently_autoselecting_;
bool dragging_;
TimeBasedViewSelectionManager<NodeKeyframe> selection_manager_;
private slots:
void ShowContextMenu();
@@ -129,6 +130,8 @@ private slots:
void AutoSelectKeyTimeNeighbors();
void Redraw();
};
}
@@ -0,0 +1,83 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "keyframeviewinputconnection.h"
#include "keyframeview.h"
namespace olive {
KeyframeViewInputConnection::KeyframeViewInputConnection(const NodeKeyframeTrackReference &input, KeyframeViewBase *parent) :
QObject(parent),
keyframe_view_(parent),
input_(input),
y_(0),
y_behavior_(kSingleRow),
brush_(Qt::white)
{
Node *n = input.input().node();
connect(n, &Node::KeyframeAdded, this, &KeyframeViewInputConnection::AddKeyframe);
connect(n, &Node::KeyframeRemoved, this, &KeyframeViewInputConnection::RemoveKeyframe);
connect(n, &Node::KeyframeTimeChanged, this, &KeyframeViewInputConnection::RequireUpdate);
}
void KeyframeViewInputConnection::SetKeyframeY(int y)
{
if (y_ != y) {
y_ = y;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::SetYBehavior(YBehavior e)
{
if (y_behavior_ != e) {
y_behavior_ = e;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::SetBrush(const QBrush &brush)
{
if (brush_ != brush) {
brush_ = brush;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::AddKeyframe(NodeKeyframe *key)
{
if (key->key_track_ref() == input_) {
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::RemoveKeyframe(NodeKeyframe *key)
{
if (key->key_track_ref() == input_) {
emit RequireUpdate();
}
}
}
@@ -0,0 +1,88 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef KEYFRAMEVIEWINPUTCONNECTION_H
#define KEYFRAMEVIEWINPUTCONNECTION_H
#include <QObject>
#include "node/node.h"
#include "node/param.h"
namespace olive {
class KeyframeViewBase;
class KeyframeViewInputConnection : public QObject
{
Q_OBJECT
public:
KeyframeViewInputConnection(const NodeKeyframeTrackReference &input, KeyframeViewBase *parent);
const int &GetKeyframeY() const
{
return y_;
}
void SetKeyframeY(int y);
enum YBehavior {
kSingleRow,
kValueIsHeight
};
void SetYBehavior(YBehavior e);
const QVector<NodeKeyframe*> GetKeyframes() const
{
return input_.input().node()->GetKeyframeTracks(input_.input()).at(input_.track());
}
const QBrush &GetBrush() const
{
return brush_;
}
void SetBrush(const QBrush &brush);
signals:
void RequireUpdate();
private:
KeyframeViewBase *keyframe_view_;
NodeKeyframeTrackReference input_;
int y_;
YBehavior y_behavior_;
QBrush brush_;
private slots:
void AddKeyframe(NodeKeyframe *key);
void RemoveKeyframe(NodeKeyframe *key);
};
}
#endif // KEYFRAMEVIEWINPUTCONNECTION_H
@@ -1,129 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "keyframeviewitem.h"
#include <QApplication>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
#include "common/qtutils.h"
namespace olive {
KeyframeViewItem::KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
scale_(1.0),
vert_center_(0),
use_custom_brush_(false)
{
setFlag(QGraphicsItem::ItemIsSelectable);
connect(key, &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos);
connect(key, &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw);
int keyframe_size = QtUtils::QFontMetricsWidth(qApp->fontMetrics(), "Oi");
int half_sz = keyframe_size/2;
setRect(-half_sz, -half_sz, keyframe_size, keyframe_size);
UpdatePos();
// Set default brush
}
void KeyframeViewItem::SetOverrideY(qreal vertical_center)
{
vert_center_ = vertical_center;
UpdatePos();
}
void KeyframeViewItem::SetScale(double scale)
{
scale_ = scale;
UpdatePos();
}
void KeyframeViewItem::SetOverrideBrush(const QBrush &b)
{
use_custom_brush_ = true;
setBrush(b);
}
NodeKeyframe* KeyframeViewItem::key() const
{
return key_;
}
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
if (option->state & QStyle::State_Selected) {
painter->setBrush(widget->palette().highlight());
} else if (use_custom_brush_) {
painter->setBrush(brush());
} else {
painter->setBrush(widget->palette().text());
}
switch (key_->type()) {
case NodeKeyframe::kLinear:
{
QPointF points[] = {
QPointF(rect().center().x(), rect().top()),
QPointF(rect().right(), rect().center().y()),
QPointF(rect().center().x(), rect().bottom()),
QPointF(rect().left(), rect().center().y())
};
painter->drawPolygon(points, 4);
break;
}
case NodeKeyframe::kBezier:
painter->drawEllipse(rect());
break;
case NodeKeyframe::kHold:
painter->drawRect(rect());
break;
}
}
void KeyframeViewItem::TimeTargetChangedEvent(Node *)
{
UpdatePos();
}
void KeyframeViewItem::UpdatePos()
{
rational adjusted = GetAdjustedTime(key_->parent(), GetTimeTarget(), key_->time(), false);
setPos(adjusted.toDouble() * scale_, vert_center_);
}
void KeyframeViewItem::Redraw()
{
QGraphicsItem::update();
}
}
@@ -1,68 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef KEYFRAMEVIEWITEM_H
#define KEYFRAMEVIEWITEM_H
#include <QGraphicsRectItem>
#include "node/keyframe.h"
#include "widget/timetarget/timetarget.h"
namespace olive {
class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject
{
Q_OBJECT
public:
KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent = nullptr);
void SetOverrideY(qreal vertical_center);
void SetScale(double scale);
void SetOverrideBrush(const QBrush& b);
NodeKeyframe* key() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
virtual void TimeTargetChangedEvent(Node* ) override;
private:
NodeKeyframe* key_;
double scale_;
qreal vert_center_;
bool use_custom_brush_;
private slots:
void UpdatePos();
void Redraw();
};
}
#endif // KEYFRAMEVIEWITEM_H
+39 -93
View File
@@ -229,6 +229,10 @@ void NodeParamView::SetContexts(const QVector<Node *> &contexts)
ctx->setVisible(false);
}
if (keyframe_view_) {
keyframe_view_->Clear();
}
if (focused_node_) {
focused_node_ = nullptr;
emit FocusedNodeChanged(nullptr);
@@ -264,6 +268,10 @@ void NodeParamView::SetContexts(const QVector<Node *> &contexts)
foreach (NodeParamViewContext *ctx, context_items_) {
SortItemsInContext(ctx);
}
if (keyframe_view_) {
QueueKeyframePositionUpdate();
}
}
void NodeParamView::resizeEvent(QResizeEvent *event)
@@ -348,54 +356,13 @@ void NodeParamView::QueueKeyframePositionUpdate()
QMetaObject::invokeMethod(this, &NodeParamView::UpdateElementY, Qt::QueuedConnection);
}
void NodeParamView::SignalNodeOrder()
{
/*
// Sort by item Y (apparently there's no way in Qt to get the order of dock widgets)
QVector<Node*> nodes;
QVector<int> item_ys;
for (auto it=items_.cbegin(); it!=items_.cend(); it++) {
int item_y = it.value()->pos().y();
bool inserted = false;
for (int i=0; i<item_ys.size(); i++) {
if (item_ys.at(i) > item_y) {
item_ys.insert(i, item_y);
nodes.insert(i, it.key());
inserted = true;
break;
}
}
if (!inserted) {
item_ys.append(item_y);
nodes.append(it.key());
}
}
emit NodeOrderChanged(nodes);
*/
}
void NodeParamView::AddNode(Node *n, NodeParamViewContext *context)
{
NodeParamViewItem* item = new NodeParamViewItem(n, create_checkboxes_, context);
if (keyframe_view_) {
connect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
}
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal);
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
connect(item, &NodeParamViewItem::dockLocationChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::dockLocationChanged, this, &NodeParamView::SignalNodeOrder);
connect(item, &NodeParamViewItem::PinToggled, this, &NodeParamView::PinNode);
connect(item, &NodeParamViewItem::ArrayExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::ExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::Moved, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::SetInputChecked);
if (create_checkboxes_) {
@@ -422,48 +389,15 @@ void NodeParamView::AddNode(Node *n, NodeParamViewContext *context)
}
if (keyframe_view_) {
keyframe_view_->AddKeyframesOfNode(n);
connect(item, &NodeParamViewItem::dockLocationChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::ArrayExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::ExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
connect(item, &NodeParamViewItem::Moved, this, &NodeParamView::QueueKeyframePositionUpdate);
item->SetKeyframeConnections(keyframe_view_->AddKeyframesOfNode(n));
}
}
/*void NodeParamView::AddNode(Node *node, Node *context, NodeParamViewContext *ctx_item)
{
int dist = GetDistanceBetweenNodes(context, node);
if (dist == -1) {
dist = 0;
}
ctx_item->GetDockArea()->insert
}*/
void NodeParamView::RemoveNode(Node *n)
{
qDebug() << "STUB!";
/*if (keyframe_view_) {
keyframe_view_->RemoveKeyframesOfNode(n);
disconnect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
disconnect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
}
delete items_.take(n);
if (focused_node_ == n) {
// Try to find new node with gizmos to focus
focused_node_ = nullptr;
for (auto it=items_.cbegin(); it!=items_.cend(); it++) {
if (it.key()->HasGizmos()) {
focused_node_ = it.key();
it.value()->SetHighlighted(true);
break;
}
}
emit FocusedNodeChanged(focused_node_);
}*/
}
int GetDistanceBetweenNodes(Node *start, Node *end)
{
if (start == end) {
@@ -516,7 +450,7 @@ void NodeParamView::UpdateGlobalScrollBar()
int height_offscreen = param_widget_container_->height() + scrollbar()->height();
if (keyframe_view_) {
keyframe_view_->SetMaxScroll(height_offscreen);
keyframe_view_->SetMaxScroll(height_offscreen + 2000);
}
vertical_scrollbar_->setRange(0, height_offscreen - param_scroll_area_->height());
@@ -533,8 +467,7 @@ void NodeParamView::PinNode(bool pin)
pinned_nodes_.removeOne(node);
if (!active_nodes_.contains(node)) {
RemoveNode(node);
SignalNodeOrder();
//RemoveNode(node);
}
}
}
@@ -591,21 +524,34 @@ void NodeParamView::KeyframeViewDragged(int x, int y)
void NodeParamView::UpdateElementY()
{
qDebug() << "STUB";
/*if (keyframe_view_) {
for (auto it=items_.cbegin(); it!=items_.cend(); it++) {
foreach (const QString& input, it.key()->inputs()) {
int arr_sz = it.key()->InputArraySize(input);
foreach (NodeParamViewContext *ctx, context_items_) {
for (auto it=ctx->GetItems().cbegin(); it!=ctx->GetItems().cend(); it++) {
const KeyframeViewBase::NodeConnections &connections = it.value()->GetKeyframeConnections();
for (int i=-1; i<arr_sz; i++) {
NodeInput ic = {it.key(), input, i};
if (!connections.isEmpty()) {
foreach (const QString& input, it.key()->inputs()) {
if (!(it.key()->GetInputFlags(input) & kInputFlagHidden)) {
int arr_sz = it.key()->InputArraySize(input);
int y = it.value()->GetElementY(ic);
keyframe_view_->SetElementY(ic, y);
for (int i=-1; i<arr_sz; i++) {
NodeInput ic = {it.key(), input, i};
int y = it.value()->GetElementY(ic);
const KeyframeViewBase::InputConnections &input_con = connections.value(input);
int use_index = i + 1;
if (use_index < input_con.size()) {
const KeyframeViewBase::ElementConnections &ele_con = input_con.at(ic.element()+1);
foreach (KeyframeViewInputConnection *track, ele_con) {
track->SetKeyframeY(y);
}
}
}
}
}
}
}
}*/
}
}
}
-8
View File
@@ -99,8 +99,6 @@ public slots:
signals:
void RequestSelectNode(const QVector<Node*>& target);
void NodeOrderChanged(const QVector<Node*>& nodes);
void FocusedNodeChanged(Node* n);
protected:
@@ -117,14 +115,8 @@ private:
void QueueKeyframePositionUpdate();
void SignalNodeOrder();
void AddNode(Node* n, NodeParamViewContext *context);
//void AddNode(Node *node, Node *context, NodeParamViewContext *ctx_item);
void RemoveNode(Node* n);
void SortItemsInContext(NodeParamViewContext *context);
KeyframeView* keyframe_view_;
@@ -36,6 +36,7 @@
#include "nodeparamviewwidgetbridge.h"
#include "widget/clickablelabel/clickablelabel.h"
#include "widget/collapsebutton/collapsebutton.h"
#include "widget/keyframeview/keyframeviewbase.h"
namespace olive {
@@ -187,6 +188,16 @@ public:
void SetInputChecked(const NodeInput &input, bool e);
const KeyframeViewBase::NodeConnections &GetKeyframeConnections() const
{
return keyframe_connections_;
}
void SetKeyframeConnections(const KeyframeViewBase::NodeConnections &c)
{
keyframe_connections_ = c;
}
signals:
void RequestSetTime(const rational& time);
@@ -206,6 +217,8 @@ private:
rational time_;
KeyframeViewBase::NodeConnections keyframe_connections_;
};
}
+2
View File
@@ -18,6 +18,8 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/timebased/timebasedview.cpp
widget/timebased/timebasedview.h
widget/timebased/timebasedviewselectionmanager.cpp
widget/timebased/timebasedviewselectionmanager.h
widget/timebased/timebasedwidget.cpp
widget/timebased/timebasedwidget.h
widget/timebased/timescaledobject.cpp
@@ -0,0 +1,26 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "timebasedviewselectionmanager.h"
namespace olive {
}
@@ -0,0 +1,256 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef TIMEBASEDVIEWSELECTIONMANAGER_H
#define TIMEBASEDVIEWSELECTIONMANAGER_H
#include <QGraphicsView>
#include <QMouseEvent>
#include <QToolTip>
#include "common/rational.h"
#include "common/timecodefunctions.h"
#include "timebasedview.h"
namespace olive {
template <typename T>
class TimeBasedViewSelectionManager
{
public:
TimeBasedViewSelectionManager(TimeBasedView *view) :
view_(view)
{}
void ClearDrawnObjects()
{
drawn_objects_.clear();
}
void DeclareDrawnObject(T *object, const QRectF &pos)
{
drawn_objects_.append({object, pos});
}
bool Select(T *key)
{
if (!IsSelected(key)) {
selected_.append(key);
return true;
}
return false;
}
bool Deselect(T *key)
{
return selected_.removeOne(key);
}
void ClearSelection()
{
selected_.clear();
}
bool IsSelected(T *key) const
{
return selected_.contains(key);
}
const QVector<T*> &GetSelectedObjects() const
{
return selected_;
}
void SetTimebase(const rational &tb)
{
timebase_ = tb;
}
T *MousePress(QMouseEvent *event)
{
T *key_under_cursor = nullptr;
if (event->button() == Qt::LeftButton) {
// See if there's a keyframe in this position
QPointF scene_pos = view_->mapToScene(event->pos());
foreach (const DrawnObject &kp, drawn_objects_) {
if (kp.second.contains(scene_pos)) {
key_under_cursor = kp.first;
break;
}
}
bool holding_shift = event->modifiers() & Qt::ShiftModifier;
if (IsSelected(key_under_cursor)) {
if (holding_shift) {
// If selected and holding shift, de-select this item but do nothing else
Deselect(key_under_cursor);
}
} else {
if (!holding_shift) {
// If not already selecting and not holding shift, clear the current selection
ClearSelection();
}
// Add item to selection, either nothing if shift wasn't held, or the existing selection
Select(key_under_cursor);
}
}
return key_under_cursor;
}
bool IsDragging() const
{
return !dragging_.isEmpty();
}
void DragStart(T *initial_item, QMouseEvent *event)
{
initial_drag_item_ = initial_item;
dragging_.clear();
dragging_.resize(selected_.size());
for (int i=0; i<selected_.size(); i++) {
T *obj = selected_.at(i);
dragging_[i] = {obj->time()};
}
drag_mouse_start_ = view_->mapToScene(event->pos());
}
void DragMove(QMouseEvent *event, const QString &tip_format)
{
QPointF diff = view_->mapToScene(event->pos()) - drag_mouse_start_;
for (int i=0; i<selected_.size(); i++) {
const rational &old_time = dragging_.at(i).time;
rational proposed_time = old_time + view_->SceneToTimeNoGrid(diff.x());
T *sel = selected_.at(i);
// Magic number: use interval of 1ms to avoid collisions
rational adj(1, 1000);
if (old_time < proposed_time) {
adj = -adj;
}
while (true) {
NodeKeyframe *key_at_time = sel->parent()->GetKeyframeAtTimeOnTrack(sel->input(), proposed_time, sel->track(), sel->element());
if (!key_at_time || key_at_time == sel) {
break;
}
proposed_time += adj;
}
sel->set_time(proposed_time);
}
// Show information about this keyframe
QString tip = Timecode::time_to_timecode(initial_drag_item_->time(), timebase_,
Core::instance()->GetTimecodeDisplay(), false);
if (!tip_format.isEmpty()) {
tip = tip_format.arg(tip);
}
QToolTip::hideText();
QToolTip::showText(QCursor::pos(), tip);
}
void DragStop(MultiUndoCommand *command)
{
QToolTip::hideText();
for (int i=0; i<selected_.size(); i++) {
command->add_child(new SetTimeCommand(selected_.at(i), selected_.at(i)->time(), dragging_.at(i).time));
}
}
private:
class SetTimeCommand : public UndoCommand
{
public:
SetTimeCommand(T* key, const rational& time)
{
key_ = key;
new_time_ = time;
old_time_ = key_->time();
}
SetTimeCommand(T* key, const rational& new_time, const rational& old_time)
{
key_ = key;
new_time_ = new_time;
old_time_ = old_time;
}
virtual Project* GetRelevantProject() const override
{
return key_->parent()->project();
}
protected:
virtual void redo() override
{
key_->set_time(new_time_);
}
virtual void undo() override
{
key_->set_time(old_time_);
}
private:
T* key_;
rational old_time_;
rational new_time_;
};
TimeBasedView *view_;
using DrawnObject = QPair<T*, QRectF>;
QVector<DrawnObject> drawn_objects_;
QVector<T*> selected_;
struct DragObject
{
rational time;
};
QVector<DragObject> dragging_;
T *initial_drag_item_;
QPointF drag_mouse_start_;
rational timebase_;
};
}
#endif // TIMEBASEDVIEWSELECTIONMANAGER_H
+12
View File
@@ -72,6 +72,13 @@ rational TimeScaledObject::SceneToTime(const double &x, const double &x_scale, c
return rational(rounded_x_mvmt * timebase.numerator(), timebase.denominator());
}
rational TimeScaledObject::SceneToTimeNoGrid(const double &x, const double &x_scale)
{
double unscaled_time = x / x_scale;
return rational::fromDouble(unscaled_time);
}
double TimeScaledObject::TimeToScene(const rational &time) const
{
return time.toDouble() * scale_;
@@ -82,6 +89,11 @@ rational TimeScaledObject::SceneToTime(const double &x, bool round) const
return SceneToTime(x, scale_, timebase_, round);
}
rational TimeScaledObject::SceneToTimeNoGrid(const double &x) const
{
return SceneToTimeNoGrid(x, scale_);
}
void TimeScaledObject::SetMaximumScale(const double &max)
{
max_scale_ = max;
+2
View File
@@ -42,6 +42,7 @@ public:
const double& timebase_dbl() const;
static rational SceneToTime(const double &x, const double& x_scale, const rational& timebase, bool round = false);
static rational SceneToTimeNoGrid(const double &x, const double& x_scale);
const double& GetScale() const;
const double &GetMaximumScale() const { return max_scale_; }
@@ -54,6 +55,7 @@ public:
double TimeToScene(const rational& time) const;
rational SceneToTime(const double &x, bool round = false) const;
rational SceneToTimeNoGrid(const double &x) const;
protected:
virtual void TimebaseChangedEvent(const rational&){}
+2 -5
View File
@@ -47,7 +47,7 @@ MainWindow::MainWindow(QWidget *parent) :
#ifdef Q_OS_WINDOWS
// Set up taskbar button progress bar (used for some modal tasks like exporting)
taskbar_btn_id_ = RegisterWindowMessage("TaskbarButtonCreated");
taskbar_btn_id_ = RegisterWindowMessage(TEXT("TaskbarButtonCreated"));
taskbar_interface_ = nullptr;
#endif
@@ -106,9 +106,6 @@ MainWindow::MainWindow(QWidget *parent) :
connect(curve_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime);
connect(curve_panel_, &ParamPanel::TimeChanged, param_panel_, &NodeTablePanel::SetTime);
// Connect node order signals
connect(param_panel_, &ParamPanel::NodeOrderChanged, curve_panel_, &CurvePanel::SetNodes);
connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged);
sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_);
@@ -116,7 +113,7 @@ MainWindow::MainWindow(QWidget *parent) :
UpdateTitle();
QMetaObject::invokeMethod(this, "SetDefaultLayout", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, &MainWindow::SetDefaultLayout, Qt::QueuedConnection);
}
MainWindow::~MainWindow()