implemented bulk of curve editor's functionality

While certainly not entirely complete yet, this implements most of the UI
functionality of the graph editor.
This commit is contained in:
itsmattkc
2019-12-28 18:26:37 +11:00
parent b65abe4881
commit 26cafa7936
21 changed files with 603 additions and 36 deletions
+3 -3
View File
@@ -373,6 +373,9 @@ void Core::StartGUI(bool full_screen)
// Since we're starting GUI mode, create a PanelFocusManager (auto-deletes with QObject)
PanelManager::CreateInstance();
// Initialize audio service
AudioManager::CreateInstance();
// Connect the PanelFocusManager to the application's focus change signal
connect(qApp,
SIGNAL(focusChanged(QWidget*, QWidget*)),
@@ -390,9 +393,6 @@ void Core::StartGUI(bool full_screen)
// When a new project is opened, update the mainwindow
connect(this, SIGNAL(ProjectOpened(Project*)), main_window_, SLOT(ProjectOpen(Project*)));
// Initialize audio service
AudioManager::CreateInstance();
// Start autorecovery timer using the config value as its interval
SetAutorecoveryInterval(Config::Current()["AutorecoveryInterval"].toInt());
autorecovery_timer_.start();
+27
View File
@@ -10,10 +10,37 @@ CurvePanel::CurvePanel(QWidget *parent) :
widget_ = new CurveWidget();
setWidget(widget_);
connect(widget_, &CurveWidget::TimeChanged, this, &CurvePanel::TimeChanged);
// Set strings
Retranslate();
}
void CurvePanel::SetInput(NodeInput *input)
{
widget_->SetInput(input);
}
void CurvePanel::SetTimebase(const rational &timebase)
{
widget_->SetTimebase(timebase);
}
void CurvePanel::SetTime(const int64_t &timestamp)
{
widget_->SetTime(timestamp);
}
void CurvePanel::ZoomIn()
{
widget_->SetScale(widget_->GetScale() * 2);
}
void CurvePanel::ZoomOut()
{
widget_->SetScale(widget_->GetScale() * 0.5);
}
void CurvePanel::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
+15
View File
@@ -6,9 +6,24 @@
class CurvePanel : public PanelWidget
{
Q_OBJECT
public:
CurvePanel(QWidget* parent);
public slots:
void SetInput(NodeInput* input);
void SetTimebase(const rational& timebase);
void SetTime(const int64_t& timestamp);
virtual void ZoomIn() override;
virtual void ZoomOut() override;
signals:
void TimeChanged(const int64_t& timestamp);
protected:
virtual void changeEvent(QEvent* e) override;
+2
View File
@@ -28,6 +28,8 @@ ParamPanel::ParamPanel(QWidget* parent) :
view_ = new NodeParamView(this);
connect(view_, &NodeParamView::TimeChanged, this, &ParamPanel::TimeChanged);
connect(view_, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged);
connect(view_, &NodeParamView::TimebaseChanged, this, &ParamPanel::TimebaseChanged);
setWidget(view_);
+4
View File
@@ -42,6 +42,10 @@ public slots:
signals:
void TimeChanged(const int64_t& timestamp);
void SelectedInputChanged(NodeInput* input);
void TimebaseChanged(const rational& timebase);
protected:
virtual void changeEvent(QEvent* e) override;
+8
View File
@@ -26,6 +26,7 @@
#include "common/timecodefunctions.h"
#include "panel/panelmanager.h"
#include "panel/node/node.h"
#include "panel/curve/curve.h"
#include "panel/param/param.h"
#include "panel/timeline/timeline.h"
#include "panel/viewer/viewer.h"
@@ -45,6 +46,7 @@ void Sequence::Open(SequencePtr sequence)
TimelinePanel* timeline_panel = PanelManager::instance()->MostRecentlyFocused<TimelinePanel>();
NodePanel* node_panel = PanelManager::instance()->MostRecentlyFocused<NodePanel>();
ParamPanel* param_panel = PanelManager::instance()->MostRecentlyFocused<ParamPanel>();
CurvePanel* curve_panel = PanelManager::instance()->MostRecentlyFocused<CurvePanel>();
viewer_panel->ConnectViewerNode(sequence->viewer_output_);
timeline_panel->ConnectTimelineNode(sequence->timeline_output_);
@@ -52,10 +54,16 @@ void Sequence::Open(SequencePtr sequence)
connect(timeline_panel, &TimelinePanel::TimeChanged, param_panel, &ParamPanel::SetTime);
connect(timeline_panel, &TimelinePanel::TimeChanged, viewer_panel, &ViewerPanel::SetTime);
connect(timeline_panel, &TimelinePanel::TimeChanged, curve_panel, &CurvePanel::SetTime);
connect(viewer_panel, &ViewerPanel::TimeChanged, param_panel, &ParamPanel::SetTime);
connect(viewer_panel, &ViewerPanel::TimeChanged, timeline_panel, &TimelinePanel::SetTime);
connect(viewer_panel, &ViewerPanel::TimeChanged, curve_panel, &CurvePanel::SetTime);
connect(param_panel, &ParamPanel::TimeChanged, viewer_panel, &ViewerPanel::SetTime);
connect(param_panel, &ParamPanel::TimeChanged, timeline_panel, &TimelinePanel::SetTime);
connect(param_panel, &ParamPanel::TimeChanged, curve_panel, &CurvePanel::SetTime);
connect(curve_panel, &CurvePanel::TimeChanged, viewer_panel, &ViewerPanel::SetTime);
connect(curve_panel, &CurvePanel::TimeChanged, timeline_panel, &TimelinePanel::SetTime);
connect(curve_panel, &CurvePanel::TimeChanged, param_panel, &ParamPanel::SetTime);
}
void Sequence::add_default_nodes()
+3 -3
View File
@@ -16,9 +16,9 @@ AudioMonitor::AudioMonitor(QWidget *parent) :
{
clear_timer_.setInterval(kClearTimerInterval);
connect(AudioManager::instance(), SIGNAL(SentSamples(QVector<double>)), this, SLOT(SetValues(QVector<double>)));
connect(&clear_timer_, SIGNAL(timeout()), this, SLOT(Clear()));
connect(&clear_timer_, SIGNAL(timeout()), &clear_timer_, SLOT(stop()));
connect(AudioManager::instance(), &AudioManager::SentSamples, this, &AudioMonitor::SetValues);
connect(&clear_timer_, &QTimer::timeout, this, &AudioMonitor::Clear);
connect(&clear_timer_, &QTimer::timeout, &clear_timer_, &QTimer::stop);
}
void AudioMonitor::SetValues(QVector<double> values)
+168 -12
View File
@@ -5,41 +5,197 @@
#include "common/qtversionabstraction.h"
CurveView::CurveView(QWidget *parent) :
TimelineViewBase(parent)
TimelineViewBase(parent),
y_scale_(1.0)
{
setAlignment(Qt::AlignLeft | Qt::AlignBottom);
setDragMode(RubberBandDrag);
setViewportUpdateMode(FullViewportUpdate);
text_padding_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("i"));
minimum_grid_space_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("00000"));
}
void CurveView::Clear()
{
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) {
delete iterator.value();
}
foreach (QGraphicsLineItem* line, lines_) {
delete line;
}
key_item_map_.clear();
lines_.clear();
}
void CurveView::SetXScale(const double& x_scale)
{
SetScale(x_scale);
}
void CurveView::SetYScale(const double &y_scale)
{
y_scale_ = y_scale;
viewport()->update();
}
void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
{
if (timebase().isNull()) {
return;
}
QVector<QLine> lines;
//painter->setPen(palette().window().color());
double x_interval = timebase().flipped().toDouble();
double y_interval = 100.0;
int grid_interval = 100;
int x_grid_interval, y_grid_interval;
int x_start = qCeil(rect.left() / grid_interval) * grid_interval;
int y_start = qCeil(rect.top() / grid_interval) * grid_interval;
painter->setPen(QPen(palette().window().color(), 1));
QPoint viewport_edges(0, qRound(rect.height()));
QPointF scene_edges = mapToScene(viewport_edges);
//QRectF scene_edges = mapToScene(viewport()->geometry()).boundingRect();
do {
x_grid_interval = qRound(x_interval * scale_ * timebase_dbl());
x_interval *= 2.0;
} while (x_grid_interval < minimum_grid_space_);
do {
y_grid_interval = qRound(y_interval * y_scale_);
y_interval *= 2.0;
} while (y_grid_interval < minimum_grid_space_);
int x_start = qCeil(rect.left() / x_grid_interval) * x_grid_interval;
int y_start = qCeil(rect.top() / y_grid_interval) * y_grid_interval;
QPointF scene_bottom_left = mapToScene(QPoint(0, qRound(rect.height())));
QPointF scene_top_right = mapToScene(QPoint(qRound(rect.width()), 0));
// Add vertical lines
for (int i=x_start;i<rect.right();i+=grid_interval) {
painter->drawText(i + text_padding_, qRound(scene_edges.y()) - text_padding_, QString::number(i));
for (int i=x_start;i<rect.right();i+=x_grid_interval) {
int value = qRound(static_cast<double>(i) / scale_ / timebase_dbl());
painter->drawText(i + text_padding_, qRound(scene_bottom_left.y()) - text_padding_, QString::number(value));
lines.append(QLine(i, qRound(rect.top()), i, qRound(rect.bottom())));
}
// Add horizontal lines
for (int i=y_start;i<rect.bottom();i+=grid_interval) {
painter->drawText(qRound(scene_edges.x()) + text_padding_, i - text_padding_, QString::number(-i));
for (int i=y_start;i<rect.bottom();i+=y_grid_interval) {
int value = qRound(static_cast<double>(i) / y_scale_);
painter->drawText(qRound(scene_bottom_left.x()) + text_padding_, i - text_padding_, QString::number(-value));
lines.append(QLine(qRound(rect.left()), i, qRound(rect.right()), i));
}
// Draw grid
painter->drawLines(lines);
// Draw keyframe lines
QList<NodeKeyframe*> keys = GetKeyframesSortedByTime();
painter->setPen(QPen(palette().text().color(), 2));
if (!keys.isEmpty()) {
QVector<QLineF> keyframe_lines;
// Draw straight line leading to first keyframe
QPointF first_key_pos = key_item_map_.value(keys.first())->center_pos();
keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos));
// Draw lines between each keyframe
for (int i=1;i<keys.size();i++) {
NodeKeyframe* before = keys.at(i-1);
NodeKeyframe* after = keys.at(i);
KeyframeViewItem* before_item = key_item_map_.value(before);
KeyframeViewItem* after_item = key_item_map_.value(after);
if (before->type() == NodeKeyframe::kHold) {
// Draw a hold keyframe (basically a right angle)
keyframe_lines.append(QLineF(before_item->center_pos().x(),
before_item->center_pos().y(),
after_item->center_pos().x(),
before_item->center_pos().y()));
keyframe_lines.append(QLineF(after_item->center_pos().x(),
before_item->center_pos().y(),
after_item->center_pos().x(),
after_item->center_pos().y()));
} else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// Draw a cubic bezier
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
// Draw a quadratic bezier
} else {
// Linear to linear
keyframe_lines.append(QLineF(before_item->center_pos(), after_item->center_pos()));
}
}
// Draw straight line leading from end keyframe
QPointF last_key_pos = key_item_map_.value(keys.last())->center_pos();
keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y())));
painter->drawLines(keyframe_lines);
}
}
QList<NodeKeyframe *> CurveView::GetKeyframesSortedByTime()
{
QList<NodeKeyframe *> sorted;
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) {
NodeKeyframe* key = iterator.key();
bool inserted = false;
for (int i=0;i<sorted.size();i++) {
if (sorted.at(i)->time() > key->time()) {
sorted.insert(i, key);
inserted = true;
break;
}
}
if (!inserted) {
sorted.append(key);
}
}
return sorted;
}
qreal CurveView::GetItemYFromKeyframeValue(NodeKeyframe *key)
{
return -key->value().toDouble() * y_scale_;
}
void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *item)
{
item->SetOverrideY(GetItemYFromKeyframeValue(key));
}
void CurveView::KeyframeValueChanged()
{
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
KeyframeViewItem* item = key_item_map_.value(key);
SetItemYFromKeyframeValue(key, item);
}
void CurveView::AddKeyframe(NodeKeyframePtr key)
{
KeyframeViewItem* item = new KeyframeViewItem(key);
SetItemYFromKeyframeValue(key.get(), item);
item->SetScale(scale_);
scene()->addItem(item);
key_item_map_.insert(key.get(), item);
connect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
}
void CurveView::RemoveKeyframe(NodeKeyframePtr key)
{
disconnect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
delete key_item_map_.take(key.get());
}
+32
View File
@@ -1,6 +1,8 @@
#ifndef CURVEVIEW_H
#define CURVEVIEW_H
#include "node/keyframe.h"
#include "widget/keyframeview/keyframeviewitem.h"
#include "widget/timelinewidget/view/timelineviewbase.h"
class CurveView : public TimelineViewBase
@@ -8,12 +10,42 @@ class CurveView : public TimelineViewBase
public:
CurveView(QWidget* parent = nullptr);
void Clear();
void SetXScale(const double& x_scale);
void SetYScale(const double& y_scale);
public slots:
void AddKeyframe(NodeKeyframePtr key);
void RemoveKeyframe(NodeKeyframePtr key);
protected:
virtual void drawBackground(QPainter* painter, const QRectF& rect) override;
private:
QList<NodeKeyframe*> GetKeyframesSortedByTime();
qreal GetItemYFromKeyframeValue(NodeKeyframe* key);
void SetItemYFromKeyframeValue(NodeKeyframe* key, KeyframeViewItem* item);
void AdjustLines();
int text_padding_;
double y_scale_;
int minimum_grid_space_;
QMap<NodeKeyframe*, KeyframeViewItem*> key_item_map_;
QList<QGraphicsLineItem*> lines_;
private slots:
void KeyframeValueChanged();
};
#endif // CURVEVIEW_H
+226 -4
View File
@@ -1,12 +1,20 @@
#include "curvewidget.h"
#include <QEvent>
#include <QLabel>
#include <QVBoxLayout>
#include "core.h"
#include "common/qtversionabstraction.h"
#include "common/timecodefunctions.h"
#include "node/node.h"
#include "widget/keyframeview/keyframeviewundo.h"
#include "widget/nodeparamview/nodeparamviewkeyframecontrol.h"
CurveWidget::CurveWidget(QWidget *parent) :
QWidget(parent)
QWidget(parent),
input_(nullptr),
bridge_(nullptr)
{
QVBoxLayout* layout = new QVBoxLayout(this);
@@ -25,21 +33,235 @@ CurveWidget::CurveWidget(QWidget *parent) :
linear_button_->setCheckable(true);
linear_button_->setEnabled(false);
top_controls->addWidget(linear_button_);
connect(linear_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered);
bezier_button_ = new QPushButton(tr("Bezier"));
bezier_button_->setCheckable(true);
bezier_button_->setEnabled(false);
top_controls->addWidget(bezier_button_);
connect(bezier_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered);
hold_button_ = new QPushButton(tr("Hold"));
hold_button_->setCheckable(true);
hold_button_->setEnabled(false);
top_controls->addWidget(hold_button_);
connect(hold_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered);
layout->addLayout(top_controls);
view_ = new CurveView();
layout->addWidget(view_);
// We use a separate layout for the ruler+view combination so that there's no spacing between them
QVBoxLayout* ruler_view_layout = new QVBoxLayout();
ruler_view_layout->setMargin(0);
ruler_view_layout->setSpacing(0);
layout->addWidget(new QLabel("Values"));
ruler_ = new TimeRuler();
ruler_view_layout->addWidget(ruler_);
view_ = new CurveView();
ruler_view_layout->addWidget(view_);
layout->addLayout(ruler_view_layout);
// Connect ruler and view together
connect(ruler_, &TimeRuler::TimeChanged, view_, &CurveView::SetTime);
connect(view_, &CurveView::TimeChanged, ruler_, &TimeRuler::SetTime);
connect(ruler_, &TimeRuler::TimeChanged, this, &CurveWidget::TimeChanged);
connect(view_, &CurveView::TimeChanged, this, &CurveWidget::TimeChanged);
connect(ruler_, &TimeRuler::TimeChanged, this, &CurveWidget::UpdateBridgeTime);
connect(view_, &CurveView::TimeChanged, this, &CurveWidget::UpdateBridgeTime);
connect(view_->scene(), &QGraphicsScene::selectionChanged, this, &CurveWidget::SelectionChanged);
widget_bridge_layout_ = new QHBoxLayout();
widget_bridge_layout_->addStretch();
input_label_ = new QLabel();
widget_bridge_layout_->addWidget(input_label_);
widget_bridge_layout_->addStretch();
layout->addLayout(widget_bridge_layout_);
SetScale(120.0);
}
CurveWidget::~CurveWidget()
{
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after the buttons have been destroyed
view_->Clear();
}
void CurveWidget::SetInput(NodeInput *input)
{
if (bridge_) {
foreach (QWidget* bridge_widget, bridge_->widgets()) {
delete bridge_widget;
}
delete bridge_;
bridge_ = nullptr;
}
if (input_) {
disconnect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe);
disconnect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe);
}
view_->Clear();
input_ = input;
if (input_) {
bridge_ = new NodeParamViewWidgetBridge(input_, this);
for (int i=0;i<bridge_->widgets().size();i++) {
// Insert between two stretches to center the widget
widget_bridge_layout_->insertWidget(2 + i, bridge_->widgets().at(i));
}
connect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe);
connect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe);
foreach (NodeKeyframePtr key, input_->keyframes()) {
view_->AddKeyframe(key);
}
}
UpdateInputLabel();
}
void CurveWidget::SetTimebase(const rational &timebase)
{
ruler_->SetTimebase(timebase);
view_->SetTimebase(timebase);
}
void CurveWidget::SetTime(const int64_t &timestamp)
{
ruler_->SetTime(timestamp);
view_->SetTime(timestamp);
UpdateBridgeTime(timestamp);
}
const double &CurveWidget::GetScale()
{
return ruler_->scale();
}
void CurveWidget::SetScale(const double &scale)
{
ruler_->SetScale(scale);
view_->SetXScale(scale);
}
void CurveWidget::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
UpdateInputLabel();
}
QWidget::changeEvent(e);
}
void CurveWidget::UpdateInputLabel()
{
if (input_) {
input_label_->setText(QStringLiteral("%1 :: %2:").arg(input_->parentNode()->Name(), input_->name()));
} else {
input_label_->clear();
}
}
void CurveWidget::SetKeyframeButtonEnabled(bool enable)
{
linear_button_->setEnabled(enable);
bezier_button_->setEnabled(enable);
hold_button_->setEnabled(enable);
}
void CurveWidget::SetKeyframeButtonChecked(bool checked)
{
linear_button_->setChecked(checked);
bezier_button_->setChecked(checked);
hold_button_->setChecked(checked);
}
void CurveWidget::SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type)
{
linear_button_->setChecked(type == NodeKeyframe::kLinear);
bezier_button_->setChecked(type == NodeKeyframe::kBezier);
hold_button_->setChecked(type == NodeKeyframe::kHold);
}
void CurveWidget::UpdateBridgeTime(const int64_t &timestamp)
{
if (!input_) {
return;
}
rational time = Timecode::timestamp_to_time(timestamp, view_->timebase());
bridge_->SetTime(time);
}
void CurveWidget::SelectionChanged()
{
QList<QGraphicsItem*> selected = view_->scene()->selectedItems();
SetKeyframeButtonChecked(false);
SetKeyframeButtonEnabled(!selected.isEmpty());
if (!selected.isEmpty()) {
bool all_same_type = true;
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(selected.first())->key()->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));
if (prev_item->key()->type() != this_item->key()->type()) {
all_same_type = false;
break;
}
}
if (all_same_type) {
SetKeyframeButtonCheckedFromType(type);
}
}
}
void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
{
QPushButton* key_btn = static_cast<QPushButton*>(sender());
if (!checked) {
// Keyframe buttons cannot be checked off, we undo this action here
key_btn->setChecked(true);
return;
}
// Get selected items and do nothing if there are none
QList<QGraphicsItem*> selected = view_->scene()->selectedItems();
if (selected.isEmpty()) {
return;
}
// Set all selected keyframes to this type
NodeKeyframe::Type new_type;
// Determine which type to set
if (key_btn == bezier_button_) {
new_type = NodeKeyframe::kBezier;
} else if (key_btn == hold_button_) {
new_type = NodeKeyframe::kHold;
} else {
new_type = NodeKeyframe::kLinear;
}
// Ensure only the appropriate button is checked
SetKeyframeButtonCheckedFromType(new_type);
QUndoCommand* command = new QUndoCommand();
foreach (QGraphicsItem* item, selected) {
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(item);
new KeyframeSetTypeCommand(key_item->key(), new_type, command);
}
Core::instance()->undo_stack()->push(command);
}
+47
View File
@@ -1,25 +1,72 @@
#ifndef CURVEWIDGET_H
#define CURVEWIDGET_H
#include <QHBoxLayout>
#include <QPushButton>
#include <QWidget>
#include "curveview.h"
#include "node/input.h"
#include "widget/nodeparamview/nodeparamviewwidgetbridge.h"
#include "widget/timeruler/timeruler.h"
class CurveWidget : public QWidget
{
Q_OBJECT
public:
CurveWidget(QWidget* parent = nullptr);
virtual ~CurveWidget() override;
void SetInput(NodeInput* input);
void SetTimebase(const rational& timebase);
void SetTime(const int64_t& timestamp);
const double& GetScale();
void SetScale(const double& scale);
signals:
void TimeChanged(const int64_t& timestamp);
protected:
virtual void changeEvent(QEvent *) override;
private:
void UpdateInputLabel();
void SetKeyframeButtonEnabled(bool enable);
void SetKeyframeButtonChecked(bool checked);
void SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type);
QPushButton* linear_button_;
QPushButton* bezier_button_;
QPushButton* hold_button_;
TimeRuler* ruler_;
CurveView* view_;
NodeInput* input_;
QLabel* input_label_;
QHBoxLayout* widget_bridge_layout_;
NodeParamViewWidgetBridge* bridge_;
private slots:
void UpdateBridgeTime(const int64_t& timestamp);
void SelectionChanged();
void KeyframeTypeButtonTriggered(bool checked);
};
#endif // CURVEWIDGET_H
+3 -2
View File
@@ -37,7 +37,8 @@ void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
QPoint local_pt = mapFromGlobal(global_pt);
QPointF scene_pt = mapToScene(local_pt);
KeyframeViewItem* item = new KeyframeViewItem(key, scene_pt.y());
KeyframeViewItem* item = new KeyframeViewItem(key);
item->SetOverrideY(scene_pt.y());
item->SetScale(scale_);
item_map_.insert(key.get(), item);
scene()->addItem(item);
@@ -45,7 +46,7 @@ void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
void KeyframeView::RemoveKeyframe(NodeKeyframePtr key)
{
delete item_map_.value(key.get());
delete item_map_.take(key.get());
}
void KeyframeView::mousePressEvent(QMouseEvent *event)
+14 -3
View File
@@ -7,11 +7,11 @@
#include "common/qtversionabstraction.h"
KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphicsItem *parent) :
KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
scale_(1.0),
middle_(vcenter)
vert_center_(0)
{
keyframe_size_ = QFontMetricsWidth(qApp->fontMetrics(), "Oi");
setFlag(QGraphicsItem::ItemIsSelectable);
@@ -24,6 +24,12 @@ KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphics
UpdatePos();
}
void KeyframeViewItem::SetOverrideY(qreal vertical_center)
{
vert_center_ = vertical_center;
UpdatePos();
}
void KeyframeViewItem::SetScale(double scale)
{
scale_ = scale;
@@ -35,6 +41,11 @@ NodeKeyframePtr KeyframeViewItem::key() const
return key_;
}
QPointF KeyframeViewItem::center_pos() const
{
return pos() + rect().center();
}
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setPen(Qt::black);
@@ -71,7 +82,7 @@ void KeyframeViewItem::UpdatePos()
{
double x_center = key_->time().toDouble() * scale_;
setPos(x_center - keyframe_size_/2, middle_ - keyframe_size_/2);
setPos(x_center - keyframe_size_/2, vert_center_ - keyframe_size_/2);
}
void KeyframeViewItem::Redraw()
+6 -2
View File
@@ -9,12 +9,16 @@ class KeyframeViewItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphicsItem *parent = nullptr);
KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent = nullptr);
void SetOverrideY(qreal vertical_center);
void SetScale(double scale);
NodeKeyframePtr key() const;
QPointF center_pos() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
@@ -23,7 +27,7 @@ private:
double scale_;
qreal middle_;
qreal vert_center_;
int keyframe_size_;
@@ -132,6 +132,7 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged);
connect(item, &NodeParamViewItem::InputClicked, this, &NodeParamView::SelectedInputChanged);
items_.append(item);
@@ -147,6 +148,13 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
}
SetTime(0);
// FIXME: Test code only!
if (nodes_.isEmpty()) {
emit SelectedInputChanged(nullptr);
} else {
emit SelectedInputChanged(static_cast<NodeInput*>(nodes_.first()->parameters().first()));
}
}
void NodeParamView::resizeEvent(QResizeEvent *event)
@@ -184,6 +192,8 @@ void NodeParamView::SetTimebase(const rational &timebase)
{
ruler_->SetTimebase(timebase);
keyframe_view_->SetTimebase(timebase);
emit TimebaseChanged(timebase);
}
void NodeParamView::UpdateItemTime(const int64_t &timestamp)
+4
View File
@@ -47,6 +47,10 @@ public slots:
signals:
void TimeChanged(const int64_t& timestamp);
void SelectedInputChanged(NodeInput* input);
void TimebaseChanged(const rational& timebase);
protected:
virtual void resizeEvent(QResizeEvent *event) override;
+13 -1
View File
@@ -137,7 +137,8 @@ void NodeParamViewItem::SetupUI()
NodeInput* input = static_cast<NodeInput*>(param);
// Add descriptor label
QLabel* param_label = new QLabel();
ClickableLabel* param_label = new ClickableLabel();
connect(param_label, &ClickableLabel::MouseClicked, this, &NodeParamViewItem::LabelClicked);
param_lbls_.append(param_label);
label_map_.insert(input, param_label);
@@ -364,6 +365,17 @@ void NodeParamViewItem::GoToNextKey()
}
}
void NodeParamViewItem::LabelClicked()
{
ClickableLabel* lbl = static_cast<ClickableLabel*>(sender());
NodeInput* input = label_map_.key(lbl, nullptr);
if (input) {
emit InputClicked(input);
}
}
NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) :
QWidget(parent)
{
+6 -1
View File
@@ -30,6 +30,7 @@
#include "node/node.h"
#include "nodeparamviewkeyframecontrol.h"
#include "nodeparamviewwidgetbridge.h"
#include "widget/clickablelabel/clickablelabel.h"
class NodeParamViewItemTitleBar : public QWidget {
public:
@@ -57,6 +58,8 @@ signals:
void RequestSetTime(const rational& time);
void InputClicked(NodeInput* input);
protected:
virtual void changeEvent(QEvent *e) override;
@@ -77,7 +80,7 @@ private:
QLabel* title_bar_lbl_;
QVector<QLabel*> param_lbls_;
QVector<ClickableLabel*> param_lbls_;
QPushButton* title_bar_collapse_btn_;
@@ -110,6 +113,8 @@ private slots:
void GoToNextKey();
void LabelClicked();
};
#endif // NODEPARAMVIEWITEM_H
@@ -31,6 +31,10 @@ void NodeParamViewWidgetBridge::SetTime(const rational &time)
{
time_ = time;
if (!input_) {
return;
}
// We assume the first data type is the "primary" type
switch (input_->data_type()) {
// None of these inputs have applicable UI widgets
+4 -3
View File
@@ -248,13 +248,14 @@ void TimelineWidget::PointerTool::InitiateDrag(const TimelineCoordinate &mouse_p
Timeline::MovementMode trim_mode = Timeline::kNone;
// FIXME: Hardcoded number
const int kTrimHandle = 10;
double kTrimHandle = qMax(10.0, parent()->TimeToScene(parent()->timebase()));
qreal mouse_x = parent()->TimeToScene(mouse_pos.GetFrame());
if (trimming_allowed_ && mouse_x < clicked_item->x() + kTrimHandle) {
if (trimming_allowed_ && mouse_x <= clicked_item->x() + kTrimHandle) {
trim_mode = Timeline::kTrimIn;
} else if (trimming_allowed_ && mouse_x > clicked_item->x() + clicked_item->rect().right() - kTrimHandle) {
} else if (trimming_allowed_ && mouse_x >= clicked_item->x() + clicked_item->rect().right() - kTrimHandle) {
trim_mode = Timeline::kTrimOut;
} else if (movement_allowed_) {
// Some derived classes don't allow movement
+4 -2
View File
@@ -71,7 +71,9 @@ MainWindow::MainWindow(QWidget *parent) :
curve_panel_ = PanelManager::instance()->CreatePanel<CurvePanel>(this);
addDockWidget(Qt::BottomDockWidgetArea, curve_panel_);
connect(node_panel_, SIGNAL(SelectionChanged(QList<Node*>)), param_panel_, SLOT(SetNodes(QList<Node*>)));
connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes);
connect(param_panel_, &ParamPanel::SelectedInputChanged, curve_panel_, &CurvePanel::SetInput);
connect(param_panel_, &ParamPanel::TimebaseChanged, curve_panel_, &CurvePanel::SetTimebase);
}
void MainWindow::SetFullscreen(bool fullscreen)
@@ -154,6 +156,6 @@ void MainWindow::SetDefaultLayout()
Qt::Horizontal);
resizeDocks({project_panel_, tool_panel_, timeline_panel_, audio_monitor_panel_},
{width()/4, 0, width(), 0},
{width()/4, 1, width(), 1},
Qt::Horizontal);
}