Files
oak-editor/app/widget/nodeparamview/nodeparamviewitem.cpp
T
itsmattkc 71ec148e76 renderer: moved all shader code into one solidified function
Makes texture-based optimizations easier when they're all in one place.
2020-06-10 01:54:02 +10:00

396 lines
12 KiB
C++

/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 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 "nodeparamviewitem.h"
#include <QCheckBox>
#include <QDebug>
#include <QEvent>
#include <QPainter>
#include "core.h"
#include "nodeparamviewundo.h"
#include "project/item/sequence/sequence.h"
OLIVE_NAMESPACE_ENTER
NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
QWidget(parent),
node_(node)
{
QVBoxLayout* main_layout = new QVBoxLayout(this);
main_layout->setSpacing(0);
main_layout->setMargin(0);
// Create title bar widget
title_bar_ = new NodeParamViewItemTitleBar(this);
title_bar_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
QHBoxLayout* title_bar_layout = new QHBoxLayout(title_bar_);
title_bar_collapse_btn_ = new CollapseButton();
title_bar_layout->addWidget(title_bar_collapse_btn_);
title_bar_lbl_ = new QLabel(title_bar_);
title_bar_layout->addWidget(title_bar_lbl_);
// Add title bar to widget
main_layout->addWidget(title_bar_);
// Create and add contents widget
QVector<NodeInput*> inputs;
// Filter out inputs
foreach (NodeParam* p, node->parameters()) {
if (p->type() == NodeParam::kInput) {
inputs.append(static_cast<NodeInput*>(p));
}
}
body_ = new NodeParamViewItemBody(inputs);
connect(body_, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItem::InputDoubleClicked);
connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode);
connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime);
connect(body_, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItem::KeyframeAdded);
connect(body_, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItem::KeyframeRemoved);
connect(title_bar_collapse_btn_, &QPushButton::toggled, body_, &NodeParamViewItemBody::setVisible);
main_layout->addWidget(body_);
connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate);
Retranslate();
}
void NodeParamViewItem::SetTimeTarget(Node *target)
{
body_->SetTimeTarget(target);
}
void NodeParamViewItem::SetTime(const rational &time)
{
time_ = time;
body_->SetTime(time_);
}
Node *NodeParamViewItem::GetNode() const
{
return node_;
}
void NodeParamViewItem::SignalAllKeyframes()
{
body_->SignalAllKeyframes();
}
void NodeParamViewItem::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
Retranslate();
}
QWidget::changeEvent(e);
}
void NodeParamViewItem::Retranslate()
{
node_->Retranslate();
if (node_->GetLabel().isEmpty()) {
title_bar_lbl_->setText(node_->Name());
} else {
title_bar_lbl_->setText(tr("%1 (%2)").arg(node_->GetLabel(), node_->Name()));
}
body_->Retranslate();
}
NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) :
QWidget(parent)
{
}
void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
QPainter p(this);
// Draw bottom border using text color
int bottom = height() - 1;
p.setPen(palette().text().color());
p.drawLine(0, bottom, width(), bottom);
}
NodeParamViewItemBody::NodeParamViewItemBody(const QVector<NodeInput *> &inputs, QWidget *parent) :
QWidget(parent)
{
int row_count = 0;
const int max_col = 10;
QGridLayout* content_layout = new QGridLayout(this);
foreach (NodeInput* input, inputs) {
InputUI ui_objects;
// Add descriptor label
ui_objects.main_label = new ClickableLabel();
connect(ui_objects.main_label, &ClickableLabel::MouseDoubleClicked, this, &NodeParamViewItemBody::LabelDoubleClicked);
if (input->IsArray()) {
QHBoxLayout* array_label_layout = new QHBoxLayout();
array_label_layout->setMargin(0);
CollapseButton* array_collapse_btn = new CollapseButton();
array_label_layout->addWidget(array_collapse_btn);
array_label_layout->addWidget(ui_objects.main_label);
content_layout->addLayout(array_label_layout, row_count, 0);
NodeParamViewItemBody* sub_body = new NodeParamViewItemBody(static_cast<NodeInputArray*>(input)->sub_params());
sub_bodies_.append(sub_body);
sub_body->layout()->setMargin(0);
content_layout->addWidget(sub_body, row_count + 1, 0, 1, max_col + 1);
connect(array_collapse_btn, &CollapseButton::toggled, sub_body, &NodeParamViewItemBody::setVisible);
connect(sub_body, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItemBody::KeyframeAdded);
connect(sub_body, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
connect(sub_body, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(sub_body, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItemBody::InputDoubleClicked);
connect(sub_body, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);
} else {
content_layout->addWidget(ui_objects.main_label, row_count, 0);
}
// Create a widget/input bridge for this input
ui_objects.widget_bridge = new NodeParamViewWidgetBridge(input, this);
// Add widgets for this parameter to the layout
{
int column = 1;
foreach (QWidget* w, ui_objects.widget_bridge->widgets()) {
content_layout->addWidget(w, row_count, column);
column++;
}
}
if (input->is_connectable()) {
// Create clickable label used when an input is connected
ui_objects.connected_label = new NodeParamViewConnectedLabel(input);
connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::ConnectionClicked, this, &NodeParamViewItemBody::ConnectionClicked);
content_layout->addWidget(ui_objects.connected_label, row_count, 1);
connect(input, &NodeInput::EdgeAdded, this, &NodeParamViewItemBody::EdgeChanged);
connect(input, &NodeInput::EdgeRemoved, this, &NodeParamViewItemBody::EdgeChanged);
}
// Add keyframe control to this layout if parameter is keyframable
if (input->is_keyframable()) {
// Hacky but effective way to make sure this widget is always as far right as possible
int control_column = max_col;
ui_objects.key_control = new NodeParamViewKeyframeControl();
ui_objects.key_control->SetInput(input);
content_layout->addWidget(ui_objects.key_control, row_count, control_column);
connect(ui_objects.key_control, &NodeParamViewKeyframeControl::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItemBody::InputKeyframeEnableChanged);
connect(input, &NodeInput::KeyframeAdded, this, &NodeParamViewItemBody::InputAddedKeyframe);
connect(input, &NodeInput::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
}
input_ui_map_.insert(input, ui_objects);
// Update "connected" label
if (input->is_connectable()) {
UpdateUIForEdgeConnection(input);
}
row_count++;
// If the row count is an array, we put an extra body widget in the next row so we skip over it here
if (input->IsArray()) {
row_count++;
}
}
}
void NodeParamViewItemBody::SetTimeTarget(Node *target)
{
foreach (const InputUI& ui_obj, input_ui_map_) {
// Only keyframable inputs have a key control widget
if (ui_obj.key_control) {
ui_obj.key_control->SetTimeTarget(target);
}
ui_obj.widget_bridge->SetTimeTarget(target);
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SetTimeTarget(target);
}
}
void NodeParamViewItemBody::SetTime(const rational &time)
{
foreach (const InputUI& ui_obj, input_ui_map_) {
// Only keyframable inputs have a key control widget
if (ui_obj.key_control) {
ui_obj.key_control->SetTime(time);
}
ui_obj.widget_bridge->SetTime(time);
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SetTime(time);
}
}
void NodeParamViewItemBody::Retranslate()
{
QMap<NodeInput*, InputUI>::const_iterator i;
for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
i.value().main_label->setText(tr("%1:").arg(i.key()->name()));
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->Retranslate();
}
}
void NodeParamViewItemBody::SignalAllKeyframes()
{
QMap<NodeInput*, InputUI>::const_iterator i;
for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
NodeInput* input = i.key();
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
InputAddedKeyframeInternal(input, key);
}
}
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SignalAllKeyframes();
}
}
void NodeParamViewItemBody::EdgeChanged()
{
UpdateUIForEdgeConnection(static_cast<NodeInput*>(sender()));
}
void NodeParamViewItemBody::UpdateUIForEdgeConnection(NodeInput *input)
{
// Show/hide bridge widgets
const InputUI& ui_objects = input_ui_map_[input];
foreach (QWidget* w, ui_objects.widget_bridge->widgets()) {
w->setVisible(!input->is_connected());
}
// Show/hide connection label
ui_objects.connected_label->setVisible(input->is_connected());
}
void NodeParamViewItemBody::InputKeyframeEnableChanged(bool e)
{
NodeInput* input = static_cast<NodeInput*>(sender());
foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
if (e) {
// Add a keyframe item for each keyframe
InputAddedKeyframeInternal(input, key);
} else {
// Remove each keyframe item
emit KeyframeRemoved(key);
}
}
}
}
void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframePtr key)
{
// Get NodeInput that emitted this signal
NodeInput* input = static_cast<NodeInput*>(sender());
InputAddedKeyframeInternal(input, key);
}
void NodeParamViewItemBody::LabelDoubleClicked()
{
QMap<NodeInput*, InputUI>::const_iterator iterator;
for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().main_label == sender()) {
emit InputDoubleClicked(iterator.key());
return;
}
}
}
void NodeParamViewItemBody::ConnectionClicked()
{
QMap<NodeInput*, InputUI>::const_iterator iterator;
for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().connected_label == sender()) {
Node* connected = iterator.key()->get_connected_node();
if (connected) {
emit RequestSelectNode({connected});
}
return;
}
}
}
void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframePtr keyframe)
{
// Find its row in the parameters
QLabel* lbl = input_ui_map_.value(input).main_label;
// Find label's Y position
QPoint lbl_center = lbl->rect().center();
// Find global position
lbl_center = lbl->mapToGlobal(lbl_center);
emit KeyframeAdded(keyframe, lbl_center.y());
}
NodeParamViewItemBody::InputUI::InputUI() :
main_label(nullptr),
widget_bridge(nullptr),
connected_label(nullptr),
key_control(nullptr)
{
}
OLIVE_NAMESPACE_EXIT