reworked much of keyframeview for new architecture
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -48,8 +48,6 @@ public slots:
|
||||
signals:
|
||||
void RequestSelectNode(const QVector<Node*>& target);
|
||||
|
||||
void NodeOrderChanged(const QVector<Node*>& nodes);
|
||||
|
||||
void FocusedNodeChanged(Node* n);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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&){}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user