Merge branch 'master' into gizmos
This commit is contained in:
@@ -168,6 +168,11 @@ void CurveWidget::SetVerticalScale(const double &vscale)
|
||||
view_->SetYScale(vscale);
|
||||
}
|
||||
|
||||
void CurveWidget::DeleteSelected()
|
||||
{
|
||||
view_->DeleteSelected();
|
||||
}
|
||||
|
||||
void CurveWidget::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
@@ -200,6 +205,8 @@ void CurveWidget::ScaleChangedEvent(const double &scale)
|
||||
|
||||
void CurveWidget::TimeTargetChangedEvent(Node *target)
|
||||
{
|
||||
ConnectViewerNode(nullptr);
|
||||
|
||||
key_control_->SetTimeTarget(target);
|
||||
|
||||
view_->SetTimeTarget(target);
|
||||
@@ -207,6 +214,12 @@ void CurveWidget::TimeTargetChangedEvent(Node *target)
|
||||
if (bridge_) {
|
||||
bridge_->SetTimeTarget(target);
|
||||
}
|
||||
|
||||
// FIXME: If a non-viewer node is ever set here, it will fail to update the length
|
||||
ViewerOutput* viewer = dynamic_cast<ViewerOutput*>(target);
|
||||
if (viewer) {
|
||||
ConnectViewerNode(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveWidget::UpdateInputLabel()
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
const double& GetVerticalScale();
|
||||
void SetVerticalScale(const double& vscale);
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent *) override;
|
||||
|
||||
|
||||
@@ -73,6 +73,25 @@ void KeyframeViewBase::SetYScale(const double &y_scale)
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::DeleteSelected()
|
||||
{
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
|
||||
|
||||
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
|
||||
if (i.value()->isSelected()) {
|
||||
NodeInput* input_parent = i.key()->parent();
|
||||
|
||||
new NodeParamRemoveKeyframeCommand(input_parent,
|
||||
input_parent->get_keyframe_shared_ptr_from_raw(i.key()),
|
||||
command);
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
KeyframeAboutToBeRemoved(key.get());
|
||||
@@ -391,7 +410,7 @@ void KeyframeViewBase::ShowContextMenu()
|
||||
{
|
||||
Menu m;
|
||||
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m);
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m, false);
|
||||
|
||||
QAction* linear_key_action = nullptr;
|
||||
QAction* bezier_key_action = nullptr;
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
const double& GetYScale() const;
|
||||
void SetYScale(const double& y_scale);
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
public slots:
|
||||
void RemoveKeyframe(NodeKeyframePtr key);
|
||||
|
||||
|
||||
@@ -32,6 +32,11 @@ ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
}
|
||||
|
||||
ManagedDisplayWidget::~ManagedDisplayWidget()
|
||||
{
|
||||
ContextCleanup();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::ConnectColorManager(ColorManager *color_manager)
|
||||
{
|
||||
if (color_manager_ == color_manager) {
|
||||
@@ -142,9 +147,13 @@ void ManagedDisplayWidget::MenuLookSelect(QAction *action)
|
||||
|
||||
void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform)
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
color_transform_ = transform;
|
||||
SetupColorProcessor();
|
||||
ColorProcessorChangedEvent();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::initializeGL()
|
||||
@@ -248,9 +257,7 @@ void ManagedDisplayWidget::SetupColorProcessor()
|
||||
color_manager_->GetReferenceColorSpace(),
|
||||
color_transform_);
|
||||
|
||||
makeCurrent();
|
||||
color_service_->Enable(context(), true);
|
||||
doneCurrent();
|
||||
|
||||
} catch (OCIO::Exception& e) {
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class ManagedDisplayWidget : public QOpenGLWidget
|
||||
public:
|
||||
ManagedDisplayWidget(QWidget* parent = nullptr);
|
||||
|
||||
virtual ~ManagedDisplayWidget() override;
|
||||
|
||||
/**
|
||||
* @brief Disconnect a ColorManager (equivalent to ConnectColorManager(nullptr))
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,17 @@ Menu::Menu(const QString &s, QWidget *parent) :
|
||||
Init();
|
||||
}
|
||||
|
||||
QAction *Menu::AddActionWithData(const QString &text, const QVariant &data, const QVariant &compare)
|
||||
{
|
||||
QAction* a = addAction(text);
|
||||
|
||||
a->setData(data);
|
||||
a->setCheckable(true);
|
||||
a->setChecked(data == compare);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
QAction* Menu::InsertAlphabetically(const QString &s)
|
||||
{
|
||||
QAction* action = new QAction(s, this);
|
||||
|
||||
@@ -131,6 +131,10 @@ public:
|
||||
return a;
|
||||
}
|
||||
|
||||
QAction* AddActionWithData(const QString& text,
|
||||
const QVariant& data,
|
||||
const QVariant& compare);
|
||||
|
||||
QAction *InsertAlphabetically(const QString& s);
|
||||
void InsertAlphabetically(QAction* entry);
|
||||
void InsertAlphabetically(Menu* menu);
|
||||
|
||||
@@ -79,7 +79,7 @@ void MenuShared::AddItemsForNewMenu(Menu *m)
|
||||
m->addAction(new_folder_item_);
|
||||
}
|
||||
|
||||
void MenuShared::AddItemsForEditMenu(Menu *m)
|
||||
void MenuShared::AddItemsForEditMenu(Menu *m, bool for_clips)
|
||||
{
|
||||
m->addAction(edit_cut_item_);
|
||||
m->addAction(edit_copy_item_);
|
||||
@@ -87,8 +87,11 @@ void MenuShared::AddItemsForEditMenu(Menu *m)
|
||||
m->addAction(edit_paste_insert_item_);
|
||||
m->addAction(edit_duplicate_item_);
|
||||
m->addAction(edit_delete_item_);
|
||||
m->addAction(edit_ripple_delete_item_);
|
||||
m->addAction(edit_split_item_);
|
||||
|
||||
if (for_clips) {
|
||||
m->addAction(edit_ripple_delete_item_);
|
||||
m->addAction(edit_split_item_);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuShared::AddItemsForInOutMenu(Menu *m)
|
||||
@@ -185,7 +188,7 @@ void MenuShared::PasteInsertTriggered()
|
||||
|
||||
void MenuShared::DuplicateTriggered()
|
||||
{
|
||||
qDebug() << "FIXME: Stub";
|
||||
PanelManager::instance()->CurrentlyFocused()->Duplicate();
|
||||
}
|
||||
|
||||
void MenuShared::EnableDisableTriggered()
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
void Retranslate();
|
||||
|
||||
void AddItemsForNewMenu(Menu* m);
|
||||
void AddItemsForEditMenu(Menu* m);
|
||||
void AddItemsForEditMenu(Menu* m, bool for_clips);
|
||||
void AddItemsForInOutMenu(Menu* m);
|
||||
void AddItemsForClipEditMenu(Menu* m);
|
||||
|
||||
|
||||
@@ -158,7 +158,9 @@ void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
|
||||
items_.append(item);
|
||||
|
||||
QMetaObject::invokeMethod(item, "SignalAllKeyframes", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(item,
|
||||
"SignalAllKeyframes",
|
||||
Qt::QueuedConnection);
|
||||
|
||||
emit OpenedNode(node);
|
||||
|
||||
@@ -225,6 +227,16 @@ const QList<Node *> &NodeParamView::nodes()
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
Node *NodeParamView::GetTimeTarget() const
|
||||
{
|
||||
return keyframe_view_->GetTimeTarget();
|
||||
}
|
||||
|
||||
void NodeParamView::DeleteSelected()
|
||||
{
|
||||
keyframe_view_->DeleteSelected();
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateItemTime(const int64_t ×tamp)
|
||||
{
|
||||
rational time = Timecode::timestamp_to_time(timestamp, keyframe_view_->timebase());
|
||||
|
||||
@@ -40,6 +40,10 @@ public:
|
||||
void SetNodes(QList<Node*> nodes);
|
||||
const QList<Node*>& nodes();
|
||||
|
||||
Node* GetTimeTarget() const;
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
signals:
|
||||
void InputDoubleClicked(NodeInput* input);
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
connect(title_bar_collapse_btn_, &QPushButton::toggled, body_, &NodeParamViewItemBody::setVisible);
|
||||
main_layout->addWidget(body_);
|
||||
|
||||
connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate);
|
||||
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
@@ -111,7 +113,11 @@ void NodeParamViewItem::Retranslate()
|
||||
{
|
||||
node_->Retranslate();
|
||||
|
||||
title_bar_lbl_->setText(node_->Name());
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -129,8 +129,6 @@ protected:
|
||||
virtual void changeEvent(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void Retranslate();
|
||||
|
||||
NodeParamViewItemTitleBar* title_bar_;
|
||||
|
||||
QLabel* title_bar_lbl_;
|
||||
@@ -143,6 +141,9 @@ private:
|
||||
|
||||
rational time_;
|
||||
|
||||
private slots:
|
||||
void Retranslate();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -18,6 +18,7 @@ set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/nodeview/nodeview.h
|
||||
widget/nodeview/nodeview.cpp
|
||||
widget/nodeview/nodeviewcommon.h
|
||||
widget/nodeview/nodeviewedge.h
|
||||
widget/nodeview/nodeviewedge.cpp
|
||||
widget/nodeview/nodeviewitem.h
|
||||
|
||||
@@ -20,30 +20,34 @@
|
||||
|
||||
#include "nodeview.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "core.h"
|
||||
#include "nodeviewundo.h"
|
||||
#include "node/factory.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
|
||||
#define super HandMovableView
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
NodeView::NodeView(QWidget *parent) :
|
||||
QGraphicsView(parent),
|
||||
HandMovableView(parent),
|
||||
graph_(nullptr),
|
||||
attached_item_(nullptr),
|
||||
drop_edge_(nullptr)
|
||||
{
|
||||
setScene(&scene_);
|
||||
setDragMode(RubberBandDrag);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setMouseTracking(true);
|
||||
setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
connect(&scene_, &QGraphicsScene::changed, this, &NodeView::ItemsChanged);
|
||||
connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
|
||||
connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu);
|
||||
|
||||
setMouseTracking(true);
|
||||
setRenderHint(QPainter::Antialiasing);
|
||||
SetFlowDirection(NodeViewCommon::kTopToBottom);
|
||||
}
|
||||
|
||||
NodeView::~NodeView()
|
||||
@@ -93,21 +97,33 @@ void NodeView::DeleteSelected()
|
||||
return;
|
||||
}
|
||||
|
||||
QList<Node*> selected_nodes = scene_.GetSelectedNodes();
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Ensure no nodes are "undeletable"
|
||||
for (int i=0;i<selected_nodes.size();i++) {
|
||||
if (!selected_nodes.at(i)->CanBeDeleted()) {
|
||||
selected_nodes.removeAt(i);
|
||||
i--;
|
||||
{
|
||||
QList<NodeEdge*> selected_edges = scene_.GetSelectedEdges();
|
||||
|
||||
foreach (NodeEdge* edge, selected_edges) {
|
||||
new NodeEdgeRemoveCommand(edge->output(), edge->input(), command);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_nodes.isEmpty()) {
|
||||
return;
|
||||
{
|
||||
QList<Node*> selected_nodes = scene_.GetSelectedNodes();
|
||||
|
||||
// Ensure no nodes are "undeletable"
|
||||
for (int i=0;i<selected_nodes.size();i++) {
|
||||
if (!selected_nodes.at(i)->CanBeDeleted()) {
|
||||
selected_nodes.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selected_nodes.isEmpty()) {
|
||||
new NodeRemoveCommand(graph_, selected_nodes, command);
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(new NodeRemoveCommand(graph_, selected_nodes));
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void NodeView::SelectAll()
|
||||
@@ -181,7 +197,60 @@ void NodeView::Paste()
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
|
||||
if (!pasted_nodes.isEmpty()) {
|
||||
// FIXME: Attach to cursor so user can drop in place
|
||||
AttachNodesToCursor(pasted_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::Duplicate()
|
||||
{
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<Node*> selected = scene_.GetSelectedNodes();
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
QList<Node*> duplicated_nodes;
|
||||
|
||||
foreach (Node* n, selected) {
|
||||
Node* copy = n->copy();
|
||||
|
||||
Node::CopyInputs(n, copy, false);
|
||||
|
||||
duplicated_nodes.append(copy);
|
||||
|
||||
new NodeAddCommand(graph_, copy, command);
|
||||
}
|
||||
|
||||
for (int i=0;i<selected.size();i++) {
|
||||
Node* src = selected.at(i);
|
||||
|
||||
for (int j=0;j<selected.size();j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Node* dst = selected.at(j);
|
||||
|
||||
foreach (NodeEdgePtr edge, src->output()->edges()) {
|
||||
if (edge->input()->parentNode() == dst) {
|
||||
new NodeEdgeAddCommand(duplicated_nodes.at(i)->output(),
|
||||
duplicated_nodes.at(j)->GetInputWithID(edge->input()->id()),
|
||||
command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
|
||||
if (!duplicated_nodes.isEmpty()) {
|
||||
AttachNodesToCursor(duplicated_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +265,10 @@ void NodeView::ItemsChanged()
|
||||
|
||||
void NodeView::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
super::keyPressEvent(event);
|
||||
|
||||
if (event->key() == Qt::Key_Escape && attached_item_) {
|
||||
DetachItemFromCursor();
|
||||
if (event->key() == Qt::Key_Escape && !attached_items_.isEmpty()) {
|
||||
DetachItemsFromCursor();
|
||||
|
||||
// We undo the last action which SHOULD be adding the node
|
||||
// FIXME: Possible danger of this not being the case?
|
||||
@@ -209,93 +278,111 @@ void NodeView::keyPressEvent(QKeyEvent *event)
|
||||
|
||||
void NodeView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (attached_item_) {
|
||||
Node* dropping_node = attached_item_->GetNode();
|
||||
if (HandPress(event)) return;
|
||||
|
||||
DetachItemFromCursor();
|
||||
if (!attached_items_.isEmpty()) {
|
||||
if (attached_items_.size() == 1) {
|
||||
Node* dropping_node = attached_items_.first().item->GetNode();
|
||||
|
||||
if (drop_edge_) {
|
||||
NodeEdgePtr old_edge = drop_edge_->edge();
|
||||
if (drop_edge_) {
|
||||
NodeEdgePtr old_edge = drop_edge_->edge();
|
||||
|
||||
// We have everything we need to place the node in between
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
// We have everything we need to place the node in between
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Remove old edge
|
||||
new NodeEdgeRemoveCommand(old_edge, command);
|
||||
// Remove old edge
|
||||
new NodeEdgeRemoveCommand(old_edge, command);
|
||||
|
||||
// Place new edges
|
||||
new NodeEdgeAddCommand(old_edge->output(), drop_compatible_input_, command);
|
||||
new NodeEdgeAddCommand(dropping_node->output(), old_edge->input(), command);
|
||||
// Place new edges
|
||||
new NodeEdgeAddCommand(old_edge->output(), drop_input_, command);
|
||||
new NodeEdgeAddCommand(dropping_node->output(), old_edge->input(), command);
|
||||
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
}
|
||||
|
||||
drop_edge_ = nullptr;
|
||||
}
|
||||
|
||||
drop_edge_ = nullptr;
|
||||
DetachItemsFromCursor();
|
||||
}
|
||||
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
super::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void NodeView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QGraphicsView::mouseMoveEvent(event);
|
||||
if (HandMove(event)) return;
|
||||
|
||||
if (attached_item_) {
|
||||
attached_item_->setPos(mapToScene(event->pos()));
|
||||
super::mouseMoveEvent(event);
|
||||
|
||||
// See if the user clicked on an edge
|
||||
QRect edge_detect_rect(event->pos(), event->pos());
|
||||
if (!attached_items_.isEmpty()) {
|
||||
MoveAttachedNodesToCursor(event->pos());
|
||||
|
||||
// FIXME: Hardcoded numbers
|
||||
edge_detect_rect.adjust(-20, -20, 20, 20);
|
||||
// See if the user clicked on an edge (only when dropping single nodes)
|
||||
if (attached_items_.size() == 1) {
|
||||
Node* attached_node = attached_items_.first().item->GetNode();
|
||||
|
||||
QList<QGraphicsItem*> items = this->items(edge_detect_rect);
|
||||
QRect edge_detect_rect(event->pos(), event->pos());
|
||||
|
||||
NodeViewEdge* new_drop_edge = nullptr;
|
||||
// FIXME: Hardcoded numbers
|
||||
edge_detect_rect.adjust(-20, -20, 20, 20);
|
||||
|
||||
foreach (QGraphicsItem* item, items) {
|
||||
NodeViewEdge* edge = dynamic_cast<NodeViewEdge*>(item);
|
||||
QList<QGraphicsItem*> items = this->items(edge_detect_rect);
|
||||
|
||||
if (edge) {
|
||||
// Try to place this node inside this edge
|
||||
NodeViewEdge* new_drop_edge = nullptr;
|
||||
|
||||
// See if the node we're dropping has an input of a compatible data type
|
||||
NodeInput* edges_input = edge->edge()->input();
|
||||
NodeParam::DataType input_type = edges_input->data_type();
|
||||
// See if there is an edge here
|
||||
foreach (QGraphicsItem* item, items) {
|
||||
new_drop_edge = dynamic_cast<NodeViewEdge*>(item);
|
||||
|
||||
NodeInput* compatible_input = nullptr;
|
||||
if (new_drop_edge) {
|
||||
drop_input_ = nullptr;
|
||||
|
||||
foreach (NodeParam* drop_node_param, attached_item_->GetNode()->parameters()) {
|
||||
if (drop_node_param->type() == NodeParam::kInput
|
||||
&& static_cast<NodeInput*>(drop_node_param)->data_type() & input_type) {
|
||||
compatible_input = static_cast<NodeInput*>(drop_node_param);
|
||||
foreach (NodeParam* param, attached_node->parameters()) {
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
|
||||
if (input->IsConnectable()) {
|
||||
if (input->data_type() & new_drop_edge->edge()->input()->data_type()) {
|
||||
drop_input_ = input;
|
||||
break;
|
||||
} else if (!drop_input_) {
|
||||
drop_input_ = input;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_input_) {
|
||||
break;
|
||||
} else {
|
||||
new_drop_edge = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compatible_input) {
|
||||
new_drop_edge = edge;
|
||||
drop_compatible_input_ = compatible_input;
|
||||
|
||||
break;
|
||||
if (drop_edge_ != new_drop_edge) {
|
||||
if (drop_edge_) {
|
||||
drop_edge_->SetHighlighted(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_edge_ != new_drop_edge) {
|
||||
if (drop_edge_) {
|
||||
drop_edge_->SetHighlighted(false);
|
||||
}
|
||||
drop_edge_ = new_drop_edge;
|
||||
|
||||
drop_edge_ = new_drop_edge;
|
||||
|
||||
if (drop_edge_) {
|
||||
drop_edge_->SetHighlighted(true);
|
||||
if (drop_edge_) {
|
||||
drop_edge_->SetHighlighted(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (HandRelease(event)) return;
|
||||
|
||||
super::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void NodeView::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
@@ -321,10 +408,59 @@ void NodeView::ShowContextMenu(const QPoint &pos)
|
||||
|
||||
Menu m;
|
||||
|
||||
Menu* add_menu = NodeFactory::CreateMenu(&m);
|
||||
add_menu->setTitle(tr("Add"));
|
||||
connect(add_menu, &Menu::triggered, this, &NodeView::CreateNodeSlot);
|
||||
m.addMenu(add_menu);
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m, false);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
QList<NodeViewItem*> selected = scene_.GetSelectedItems();
|
||||
|
||||
if (itemAt(pos) && !selected.isEmpty()) {
|
||||
|
||||
if (selected.size() == 1) {
|
||||
|
||||
// Label node action
|
||||
QAction* label_action = m.addAction(tr("Label"));
|
||||
connect(label_action, &QAction::triggered, this, &NodeView::ContextMenuLabelNode);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
}
|
||||
|
||||
// Auto-position action
|
||||
QAction* autopos = m.addAction(tr("Auto-Position"));
|
||||
connect(autopos, &QAction::triggered, this, &NodeView::AutoPositionDescendents);
|
||||
|
||||
} else {
|
||||
|
||||
Menu* direction_menu = new Menu(tr("Direction"), &m);
|
||||
m.addMenu(direction_menu);
|
||||
|
||||
direction_menu->AddActionWithData(tr("Top to Bottom"),
|
||||
NodeViewCommon::kTopToBottom,
|
||||
scene_.GetFlowDirection());
|
||||
|
||||
direction_menu->AddActionWithData(tr("Bottom to Top"),
|
||||
NodeViewCommon::kBottomToTop,
|
||||
scene_.GetFlowDirection());
|
||||
|
||||
direction_menu->AddActionWithData(tr("Left to Right"),
|
||||
NodeViewCommon::kLeftToRight,
|
||||
scene_.GetFlowDirection());
|
||||
|
||||
direction_menu->AddActionWithData(tr("Right to Left"),
|
||||
NodeViewCommon::kRightToLeft,
|
||||
scene_.GetFlowDirection());
|
||||
|
||||
connect(direction_menu, &Menu::triggered, this, &NodeView::ContextMenuSetDirection);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
Menu* add_menu = NodeFactory::CreateMenu(&m);
|
||||
add_menu->setTitle(tr("Add"));
|
||||
connect(add_menu, &Menu::triggered, this, &NodeView::CreateNodeSlot);
|
||||
m.addMenu(add_menu);
|
||||
|
||||
}
|
||||
|
||||
m.exec(mapToGlobal(pos));
|
||||
}
|
||||
@@ -337,7 +473,45 @@ void NodeView::CreateNodeSlot(QAction *action)
|
||||
Core::instance()->undo_stack()->push(new NodeAddCommand(graph_, new_node));
|
||||
|
||||
NodeViewItem* item = scene_.NodeToUIObject(new_node);
|
||||
AttachItemToCursor(item);
|
||||
AttachItemsToCursor({item});
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::ContextMenuSetDirection(QAction *action)
|
||||
{
|
||||
SetFlowDirection(static_cast<NodeViewCommon::FlowDirection>(action->data().toInt()));
|
||||
}
|
||||
|
||||
void NodeView::AutoPositionDescendents()
|
||||
{
|
||||
QList<Node*> selected = scene_.GetSelectedNodes();
|
||||
|
||||
foreach (Node* n, selected) {
|
||||
scene_.ReorganizeFrom(n);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::ContextMenuLabelNode()
|
||||
{
|
||||
QList<Node*> nodes = scene_.GetSelectedNodes();
|
||||
|
||||
if (nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* n = nodes.first();
|
||||
|
||||
bool ok;
|
||||
|
||||
QString s = QInputDialog::getText(this,
|
||||
tr("Label Node"),
|
||||
tr("Set node label"),
|
||||
QLineEdit::Normal,
|
||||
n->GetLabel(),
|
||||
&ok);
|
||||
|
||||
if (ok) {
|
||||
n->SetLabel(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,16 +649,50 @@ void NodeView::PlaceNode(NodeViewItem *n, const QPointF &pos)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::AttachItemToCursor(NodeViewItem *item)
|
||||
void NodeView::AttachNodesToCursor(const QList<Node *> &nodes)
|
||||
{
|
||||
attached_item_ = item;
|
||||
QList<NodeViewItem*> items;
|
||||
|
||||
setMouseTracking(attached_item_);
|
||||
foreach (Node* p, nodes) {
|
||||
items.append(scene_.NodeToUIObject(p));
|
||||
}
|
||||
|
||||
AttachItemsToCursor(items);
|
||||
}
|
||||
|
||||
void NodeView::DetachItemFromCursor()
|
||||
void NodeView::AttachItemsToCursor(const QList<NodeViewItem*>& items)
|
||||
{
|
||||
AttachItemToCursor(nullptr);
|
||||
DetachItemsFromCursor();
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
foreach (NodeViewItem* i, items) {
|
||||
attached_items_.append({i, i->pos() - items.first()->pos()});
|
||||
}
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
MoveAttachedNodesToCursor(mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::DetachItemsFromCursor()
|
||||
{
|
||||
attached_items_.clear();
|
||||
setMouseTracking(false);
|
||||
}
|
||||
|
||||
void NodeView::SetFlowDirection(NodeViewCommon::FlowDirection dir)
|
||||
{
|
||||
scene_.SetFlowDirection(dir);
|
||||
}
|
||||
|
||||
void NodeView::MoveAttachedNodesToCursor(const QPoint& p)
|
||||
{
|
||||
QPointF item_pos = mapToScene(p);
|
||||
|
||||
foreach (const AttachedItem& i, attached_items_) {
|
||||
i.item->setPos(item_pos + i.original_pos);
|
||||
}
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "node/graph.h"
|
||||
#include "nodeviewscene.h"
|
||||
#include "widget/timelinewidget/view/handmovableview.h"
|
||||
#include "widget/nodecopypaste/nodecopypaste.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -36,7 +37,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
* This widget takes a NodeGraph object and constructs a QGraphicsScene representing its data, viewing and allowing
|
||||
* the user to make modifications to it.
|
||||
*/
|
||||
class NodeView : public QGraphicsView, public NodeCopyPasteWidget
|
||||
class NodeView : public HandMovableView, public NodeCopyPasteWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -63,6 +64,8 @@ public:
|
||||
void CopySelected(bool cut);
|
||||
void Paste();
|
||||
|
||||
void Duplicate();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when the selected nodes have changed
|
||||
@@ -73,24 +76,35 @@ protected:
|
||||
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
|
||||
virtual void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
void PlaceNode(NodeViewItem* n, const QPointF& pos);
|
||||
|
||||
void AttachItemToCursor(NodeViewItem* item);
|
||||
void AttachNodesToCursor(const QList<Node*>& nodes);
|
||||
|
||||
void DetachItemFromCursor();
|
||||
void AttachItemsToCursor(const QList<NodeViewItem*>& items);
|
||||
|
||||
void DetachItemsFromCursor();
|
||||
|
||||
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
|
||||
|
||||
void MoveAttachedNodesToCursor(const QPoint &p);
|
||||
|
||||
NodeGraph* graph_;
|
||||
|
||||
NodeViewItem* attached_item_;
|
||||
struct AttachedItem {
|
||||
NodeViewItem* item;
|
||||
QPointF original_pos;
|
||||
};
|
||||
|
||||
QList<AttachedItem> attached_items_;
|
||||
|
||||
NodeViewEdge* drop_edge_;
|
||||
NodeInput* drop_compatible_input_;
|
||||
NodeInput* drop_input_;
|
||||
|
||||
NodeViewScene scene_;
|
||||
|
||||
@@ -117,6 +131,21 @@ private slots:
|
||||
*/
|
||||
void CreateNodeSlot(QAction* action);
|
||||
|
||||
/**
|
||||
* @brief Receiver for setting the direction from the context menu
|
||||
*/
|
||||
void ContextMenuSetDirection(QAction* action);
|
||||
|
||||
/**
|
||||
* @brief Receiver for auto-position descendents menu action
|
||||
*/
|
||||
void AutoPositionDescendents();
|
||||
|
||||
/**
|
||||
* @brief Receiver for labelling a node from the context menu
|
||||
*/
|
||||
void ContextMenuLabelNode();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef NODEVIEWCOMMON_H
|
||||
#define NODEVIEWCOMMON_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "common/define.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class NodeViewCommon {
|
||||
public:
|
||||
enum FlowDirection {
|
||||
kTopToBottom,
|
||||
kBottomToTop,
|
||||
kLeftToRight,
|
||||
kRightToLeft
|
||||
};
|
||||
|
||||
static Qt::Orientation GetFlowOrientation(FlowDirection dir) {
|
||||
if (dir == kTopToBottom || dir == kBottomToTop) {
|
||||
return Qt::Vertical;
|
||||
} else {
|
||||
return Qt::Horizontal;
|
||||
}
|
||||
}
|
||||
|
||||
static bool DirectionsAreOpposing(FlowDirection a, FlowDirection b) {
|
||||
return ((a == NodeViewCommon::kLeftToRight && b == NodeViewCommon::kRightToLeft)
|
||||
|| (a == NodeViewCommon::kRightToLeft && b == NodeViewCommon::kLeftToRight)
|
||||
|| (a == NodeViewCommon::kTopToBottom && b == NodeViewCommon::kBottomToTop)
|
||||
|| (a == NodeViewCommon::kBottomToTop && b == NodeViewCommon::kTopToBottom));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // NODEVIEWCOMMON_H
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
#include "common/clamp.h"
|
||||
#include "common/lerp.h"
|
||||
@@ -34,9 +35,12 @@ OLIVE_NAMESPACE_ENTER
|
||||
NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
|
||||
QGraphicsPathItem(parent),
|
||||
edge_(nullptr),
|
||||
color_group_(QPalette::Active),
|
||||
color_role_(QPalette::Text)
|
||||
connected_(false),
|
||||
highlighted_(false),
|
||||
flow_dir_(NodeViewCommon::kLeftToRight)
|
||||
{
|
||||
setFlag(QGraphicsItem::ItemIsSelectable);
|
||||
|
||||
// Ensures this UI object is drawn behind other objects
|
||||
setZValue(-1);
|
||||
|
||||
@@ -75,45 +79,79 @@ void NodeViewEdge::Adjust()
|
||||
}
|
||||
|
||||
// Draw a line between the two
|
||||
SetPoints(output->GetParamPoint(edge_->output()), input->GetParamPoint(edge_->input()));
|
||||
SetPoints(output->GetParamPoint(edge_->output(), output->pos()),
|
||||
input->GetParamPoint(edge_->input(), output->pos()),
|
||||
input->IsExpanded());
|
||||
}
|
||||
|
||||
void NodeViewEdge::SetConnected(bool c)
|
||||
{
|
||||
if (c) {
|
||||
color_group_ = QPalette::Active;
|
||||
} else {
|
||||
color_group_ = QPalette::Disabled;
|
||||
}
|
||||
connected_ = c;
|
||||
|
||||
UpdatePen();
|
||||
update();
|
||||
}
|
||||
|
||||
void NodeViewEdge::SetHighlighted(bool e)
|
||||
{
|
||||
if (e) {
|
||||
color_role_ = QPalette::Highlight;
|
||||
} else {
|
||||
color_role_ = QPalette::Text;
|
||||
}
|
||||
highlighted_ = e;
|
||||
|
||||
UpdatePen();
|
||||
update();
|
||||
}
|
||||
|
||||
void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end)
|
||||
void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool input_is_expanded)
|
||||
{
|
||||
QPainterPath path;
|
||||
double half_x = lerp(start.x(), end.x(), 0.5);
|
||||
path.moveTo(start);
|
||||
path.cubicTo(QPointF(half_x, start.y()), QPointF(half_x, end.y()), end);
|
||||
|
||||
double half_x = lerp(start.x(), end.x(), 0.5);
|
||||
double half_y = lerp(start.y(), end.y(), 0.5);
|
||||
|
||||
QPointF cp1, cp2;
|
||||
|
||||
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
|
||||
cp1 = QPointF(half_x, start.y());
|
||||
} else {
|
||||
cp1 = QPointF(start.x(), half_y);
|
||||
}
|
||||
|
||||
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal || input_is_expanded) {
|
||||
cp2 = QPointF(half_x, end.y());
|
||||
} else {
|
||||
cp2 = QPointF(end.x(), half_y);
|
||||
}
|
||||
|
||||
path.cubicTo(cp1, cp2, end);
|
||||
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
void NodeViewEdge::UpdatePen()
|
||||
void NodeViewEdge::SetFlowDirection(NodeViewCommon::FlowDirection dir)
|
||||
{
|
||||
setPen(QPen(qApp->palette().color(color_group_, color_role_), edge_width_));
|
||||
flow_dir_ = dir;
|
||||
|
||||
//update();
|
||||
Adjust();
|
||||
}
|
||||
|
||||
void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
||||
{
|
||||
QPalette::ColorGroup group;
|
||||
QPalette::ColorRole role;
|
||||
|
||||
if (connected_) {
|
||||
group = QPalette::Active;
|
||||
} else {
|
||||
group = QPalette::Disabled;
|
||||
}
|
||||
|
||||
if (highlighted_ != bool(option->state & QStyle::State_Selected)) {
|
||||
role = QPalette::Highlight;
|
||||
} else {
|
||||
role = QPalette::Text;
|
||||
}
|
||||
|
||||
painter->setPen(QPen(qApp->palette().color(group, role), edge_width_));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawPath(path());
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QPalette>
|
||||
|
||||
#include "node/edge.h"
|
||||
#include "nodeviewcommon.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -81,18 +82,26 @@ public:
|
||||
/**
|
||||
* @brief Set points to create curve from
|
||||
*/
|
||||
void SetPoints(const QPointF& start, const QPointF& end);
|
||||
void SetPoints(const QPointF& start, const QPointF& end, bool input_is_expanded);
|
||||
|
||||
/**
|
||||
* @brief Sets the direction nodes are flowing
|
||||
*/
|
||||
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
|
||||
private:
|
||||
void UpdatePen();
|
||||
|
||||
NodeEdgePtr edge_;
|
||||
|
||||
int edge_width_;
|
||||
|
||||
QPalette::ColorGroup color_group_;
|
||||
bool connected_;
|
||||
|
||||
QPalette::ColorRole color_role_;
|
||||
bool highlighted_;
|
||||
|
||||
NodeViewCommon::FlowDirection flow_dir_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -44,9 +44,11 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
||||
cached_drop_item_(nullptr),
|
||||
cached_drop_item_expanded_(false),
|
||||
expanded_(false),
|
||||
hide_titlebar_(false),
|
||||
standard_click_(false),
|
||||
highlighted_index_(-1),
|
||||
node_edge_change_command_(nullptr)
|
||||
node_edge_change_command_(nullptr),
|
||||
flow_dir_(NodeViewCommon::kLeftToRight)
|
||||
{
|
||||
// Set flags for this widget
|
||||
setFlag(QGraphicsItem::ItemIsMovable);
|
||||
@@ -57,26 +59,110 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
||||
// We use font metrics to set all the UI measurements for DPI-awareness
|
||||
//
|
||||
|
||||
QFont default_font;
|
||||
QFontMetrics font_metrics(default_font);
|
||||
|
||||
// Set border width
|
||||
node_border_width_ = font_metrics.height() / 12;
|
||||
node_border_width_ = DefaultItemBorder();
|
||||
|
||||
// Set text and icon padding
|
||||
int node_text_padding = font_metrics.height() / 4;
|
||||
|
||||
// Not particularly great way of using text scaling to set the width (DPI-awareness, etc.)
|
||||
int widget_width = QFontMetricsWidth(font_metrics, "HHHHHHHHHHHHHH");
|
||||
|
||||
// Use the current default font height to size this widget
|
||||
// Set default "collapsed" size
|
||||
int widget_height = font_metrics.height() + node_text_padding * 2;
|
||||
int widget_width = DefaultItemWidth();
|
||||
int widget_height = DefaultItemHeight();
|
||||
|
||||
title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height);
|
||||
setRect(title_bar_rect_);
|
||||
}
|
||||
|
||||
QPointF NodeViewItem::GetNodePosition() const
|
||||
{
|
||||
QPointF node_pos;
|
||||
|
||||
qreal adjusted_x = pos().x() / DefaultItemHorizontalPadding();
|
||||
qreal adjusted_y = pos().y() / DefaultItemVerticalPadding();
|
||||
|
||||
switch (flow_dir_) {
|
||||
case NodeViewCommon::kLeftToRight:
|
||||
node_pos.setX(adjusted_x);
|
||||
node_pos.setY(adjusted_y);
|
||||
break;
|
||||
case NodeViewCommon::kRightToLeft:
|
||||
node_pos.setX(-adjusted_x);
|
||||
node_pos.setY(adjusted_y);
|
||||
break;
|
||||
case NodeViewCommon::kTopToBottom:
|
||||
node_pos.setX(adjusted_y);
|
||||
node_pos.setY(adjusted_x);
|
||||
break;
|
||||
case NodeViewCommon::kBottomToTop:
|
||||
node_pos.setX(-adjusted_y);
|
||||
node_pos.setY(adjusted_x);
|
||||
break;
|
||||
}
|
||||
|
||||
return node_pos;
|
||||
}
|
||||
|
||||
void NodeViewItem::SetNodePosition(const QPointF &pos)
|
||||
{
|
||||
switch (flow_dir_) {
|
||||
case NodeViewCommon::kLeftToRight:
|
||||
setPos(pos.x() * DefaultItemHorizontalPadding(),
|
||||
pos.y() * DefaultItemVerticalPadding());
|
||||
break;
|
||||
case NodeViewCommon::kRightToLeft:
|
||||
setPos(-pos.x() * DefaultItemHorizontalPadding(),
|
||||
pos.y() * DefaultItemVerticalPadding());
|
||||
break;
|
||||
case NodeViewCommon::kTopToBottom:
|
||||
setPos(pos.y() * DefaultItemHorizontalPadding(),
|
||||
pos.x() * DefaultItemVerticalPadding());
|
||||
break;
|
||||
case NodeViewCommon::kBottomToTop:
|
||||
setPos(pos.y() * DefaultItemHorizontalPadding(),
|
||||
-pos.x() * DefaultItemVerticalPadding());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int NodeViewItem::DefaultTextPadding()
|
||||
{
|
||||
return QFontMetrics(QFont()).height() / 4;
|
||||
}
|
||||
|
||||
int NodeViewItem::DefaultItemHeight()
|
||||
{
|
||||
return QFontMetrics(QFont()).height() + DefaultTextPadding() * 2;
|
||||
}
|
||||
|
||||
int NodeViewItem::DefaultItemWidth()
|
||||
{
|
||||
return QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHHHH");;
|
||||
}
|
||||
|
||||
int NodeViewItem::DefaultMaximumTextWidth()
|
||||
{
|
||||
return QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHH");;
|
||||
}
|
||||
|
||||
int NodeViewItem::DefaultItemBorder()
|
||||
{
|
||||
return QFontMetrics(QFont()).height() / 12;
|
||||
}
|
||||
|
||||
qreal NodeViewItem::DefaultItemHorizontalPadding() const
|
||||
{
|
||||
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
|
||||
return DefaultItemWidth() * 1.5;
|
||||
} else {
|
||||
return DefaultItemWidth() * 1.25;
|
||||
}
|
||||
}
|
||||
|
||||
qreal NodeViewItem::DefaultItemVerticalPadding() const
|
||||
{
|
||||
if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) {
|
||||
return DefaultItemHeight() * 1.5;
|
||||
} else {
|
||||
return DefaultItemHeight() * 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewItem::SetNode(Node *n)
|
||||
{
|
||||
node_ = n;
|
||||
@@ -96,7 +182,7 @@ void NodeViewItem::SetNode(Node *n)
|
||||
}
|
||||
}
|
||||
|
||||
setPos(node_->GetPosition());
|
||||
SetNodePosition(node_->GetPosition());
|
||||
}
|
||||
|
||||
update();
|
||||
@@ -112,18 +198,26 @@ bool NodeViewItem::IsExpanded() const
|
||||
return expanded_;
|
||||
}
|
||||
|
||||
void NodeViewItem::SetExpanded(bool e)
|
||||
void NodeViewItem::SetExpanded(bool e, bool hide_titlebar)
|
||||
{
|
||||
if (expanded_ == e) {
|
||||
if (node_inputs_.isEmpty()
|
||||
|| (expanded_ == e && hide_titlebar_ == hide_titlebar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
expanded_ = e;
|
||||
hide_titlebar_ = hide_titlebar;
|
||||
|
||||
if (expanded_ && !node_inputs_.isEmpty()) {
|
||||
// Create new rect
|
||||
QRectF new_rect = title_bar_rect_;
|
||||
new_rect.setHeight(new_rect.height() * node_inputs_.size());
|
||||
|
||||
if (hide_titlebar_) {
|
||||
new_rect.setHeight(new_rect.height() * node_inputs_.size());
|
||||
} else {
|
||||
new_rect.setHeight(new_rect.height() * (node_inputs_.size() + 1));
|
||||
}
|
||||
|
||||
setRect(new_rect);
|
||||
} else {
|
||||
setRect(title_bar_rect_);
|
||||
@@ -143,33 +237,14 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||
// don't want here)
|
||||
QPalette app_pal = Core::instance()->main_window()->palette();
|
||||
|
||||
{
|
||||
QPen border_pen;
|
||||
border_pen.setWidth(node_border_width_);
|
||||
|
||||
QBrush bkg_color;
|
||||
|
||||
if (option->state & QStyle::State_Selected) {
|
||||
border_pen.setColor(app_pal.color(QPalette::Highlight));
|
||||
} else {
|
||||
border_pen.setColor(css_proxy_.BorderColor());
|
||||
}
|
||||
|
||||
if (IsExpanded()) {
|
||||
bkg_color = app_pal.color(QPalette::Window);
|
||||
} else {
|
||||
bkg_color = css_proxy_.TitleBarColor();
|
||||
}
|
||||
|
||||
painter->setPen(border_pen);
|
||||
painter->setBrush(bkg_color);
|
||||
// Draw background rect if expanded
|
||||
if (IsExpanded()) {
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(app_pal.color(QPalette::Window));
|
||||
|
||||
painter->drawRect(rect());
|
||||
}
|
||||
|
||||
painter->setPen(app_pal.color(QPalette::Text));
|
||||
|
||||
if (IsExpanded()) {
|
||||
painter->setPen(app_pal.color(QPalette::Text));
|
||||
|
||||
for (int i=0;i<node_inputs_.size();i++) {
|
||||
QRectF input_rect = GetInputRect(i);
|
||||
@@ -180,13 +255,65 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||
|
||||
painter->drawText(input_rect, Qt::AlignCenter, node_inputs_.at(i)->name());
|
||||
}
|
||||
}
|
||||
|
||||
} else if (node_) {
|
||||
// Draw the titlebar
|
||||
if (!hide_titlebar_ && node_) {
|
||||
|
||||
painter->setPen(Qt::black);
|
||||
painter->setBrush(css_proxy_.TitleBarColor());
|
||||
|
||||
painter->drawRect(title_bar_rect_);
|
||||
|
||||
painter->setPen(app_pal.color(QPalette::Text));
|
||||
|
||||
QString node_label;
|
||||
|
||||
if (node_->GetLabel().isEmpty()) {
|
||||
node_label = node_->ShortName();
|
||||
} else {
|
||||
node_label = node_->GetLabel();
|
||||
}
|
||||
|
||||
{
|
||||
QFont f;
|
||||
QFontMetrics fm(f);
|
||||
|
||||
int max_text_width = DefaultMaximumTextWidth();
|
||||
|
||||
if (QFontMetricsWidth(fm, node_label) > max_text_width) {
|
||||
QString concatenated;
|
||||
|
||||
do {
|
||||
node_label.chop(1);
|
||||
concatenated = QCoreApplication::translate("NodeViewItem", "%1...").arg(node_label);
|
||||
} while (QFontMetricsWidth(fm, concatenated) > max_text_width);
|
||||
|
||||
node_label = concatenated;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the text in a rect (the rect is sized around text already in the constructor)
|
||||
painter->drawText(title_bar_rect_, Qt::AlignCenter, node_->Name());
|
||||
painter->drawText(title_bar_rect_,
|
||||
Qt::AlignCenter,
|
||||
node_label);
|
||||
|
||||
}
|
||||
|
||||
// Draw final border
|
||||
QPen border_pen;
|
||||
border_pen.setWidth(node_border_width_);
|
||||
|
||||
if (option->state & QStyle::State_Selected) {
|
||||
border_pen.setColor(app_pal.color(QPalette::Highlight));
|
||||
} else {
|
||||
border_pen.setColor(css_proxy_.BorderColor());
|
||||
}
|
||||
|
||||
painter->setPen(border_pen);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
painter->drawRect(rect());
|
||||
}
|
||||
|
||||
void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
@@ -203,6 +330,7 @@ void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
// Create draggable object
|
||||
dragging_edge_ = new NodeViewEdge();
|
||||
dragging_edge_->SetFlowDirection(flow_dir_);
|
||||
|
||||
// Set up a QUndoCommand to make this action undoable
|
||||
node_edge_change_command_ = new QUndoCommand();
|
||||
@@ -213,7 +341,7 @@ void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
drag_src_param_ = param;
|
||||
|
||||
// Set the starting position to the current param's connector
|
||||
dragging_edge_start_ = GetParamPoint(param);
|
||||
dragging_edge_start_ = GetParamPoint(param, QPointF());
|
||||
|
||||
} else if (param->type() == NodeParam::kInput) {
|
||||
// For an input param, we default to moving an existing edge
|
||||
@@ -229,8 +357,8 @@ void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
drag_source_ = static_cast<NodeViewScene*>(scene())->NodeToUIObject(drag_src_param_->parentNode());
|
||||
|
||||
// Get the opposing parameter's rect center using the line's current coordinates
|
||||
// (we use the current coordinates because a complex formula is used for the line's coords if the opposing
|
||||
// node is collapsed, therefore it's easier to just retrieve it from line itself)
|
||||
// (we use the current coordinates because a complex formula is used for the line's coords if
|
||||
// the opposing node is collapsed, therefore it's easier to just retrieve it from line itself)
|
||||
NodeViewEdge* existing_edge_ui = static_cast<NodeViewScene*>(scene())->EdgeToUIObject(edge);
|
||||
QPainterPath existing_edge_line = existing_edge_ui->path();
|
||||
QPointF edge_start = existing_edge_line.pointAtPercent(0);
|
||||
@@ -288,6 +416,8 @@ void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
cached_drop_item_->SetExpanded(false);
|
||||
}
|
||||
|
||||
cached_drop_item_->SetHighlightedIndex(-1);
|
||||
|
||||
cached_drop_item_->setZValue(0);
|
||||
cached_drop_item_ = nullptr;
|
||||
}
|
||||
@@ -303,7 +433,7 @@ void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
cached_drop_item_expanded_ = !cached_drop_item_->IsExpanded();
|
||||
|
||||
if (cached_drop_item_expanded_) {
|
||||
cached_drop_item_->SetExpanded(true);
|
||||
cached_drop_item_->SetExpanded(true, true);
|
||||
}
|
||||
|
||||
cached_drop_item_->setZValue(1);
|
||||
@@ -330,7 +460,9 @@ void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
if (!cached_drop_item_->GetNode()->OutputsTo(node_)) {
|
||||
drag_dest_param_ = comp_param;
|
||||
highlight_their_index = i;
|
||||
end_point = cached_drop_item_->mapToScene(cached_drop_item_->GetInputPoint(i));
|
||||
|
||||
QPointF end_point_local = cached_drop_item_->GetInputPoint(i, pos());
|
||||
end_point = cached_drop_item_->mapToScene(end_point_local);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -340,9 +472,11 @@ void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
cached_drop_item_->SetHighlightedIndex(highlight_their_index);
|
||||
}
|
||||
|
||||
dragging_edge_->SetConnected(drag_dest_param_ != nullptr);
|
||||
dragging_edge_->SetConnected(drag_dest_param_);
|
||||
|
||||
dragging_edge_->SetPoints(dragging_edge_start_, end_point);
|
||||
dragging_edge_->SetPoints(dragging_edge_start_,
|
||||
end_point,
|
||||
cached_drop_item_ ? cached_drop_item_->IsExpanded() : false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -363,8 +497,14 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
scene()->removeItem(dragging_edge_);
|
||||
|
||||
// If we expanded an item in the drag, re-collapse it now
|
||||
if (cached_drop_item_ != nullptr) {
|
||||
cached_drop_item_->SetExpanded(false);
|
||||
if (cached_drop_item_) {
|
||||
if (cached_drop_item_expanded_) {
|
||||
cached_drop_item_->SetExpanded(false);
|
||||
}
|
||||
|
||||
cached_drop_item_->SetHighlightedIndex(-1);
|
||||
cached_drop_item_->setZValue(0);
|
||||
|
||||
cached_drop_item_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -405,10 +545,19 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
QGraphicsRectItem::mouseDoubleClickEvent(event);
|
||||
|
||||
SetExpanded(!IsExpanded());
|
||||
}
|
||||
|
||||
QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemPositionHasChanged && node_) {
|
||||
node_->SetPosition(value.toPointF());
|
||||
node_->blockSignals(true);
|
||||
node_->SetPosition(GetNodePosition());
|
||||
node_->blockSignals(false);
|
||||
}
|
||||
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
@@ -429,6 +578,10 @@ QRectF NodeViewItem::GetInputRect(int index) const
|
||||
{
|
||||
QRectF r = title_bar_rect_;
|
||||
|
||||
if (!hide_titlebar_) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (IsExpanded()) {
|
||||
r.translate(0, r.height() * index);
|
||||
}
|
||||
@@ -436,10 +589,22 @@ QRectF NodeViewItem::GetInputRect(int index) const
|
||||
return r;
|
||||
}
|
||||
|
||||
QPointF NodeViewItem::GetParamPoint(NodeParam *param) const
|
||||
QPointF NodeViewItem::GetParamPoint(NodeParam *param, const QPointF& source_pos) const
|
||||
{
|
||||
if (param->type() == NodeParam::kOutput) {
|
||||
return pos() + QPointF(rect().right(), rect().center().y());
|
||||
|
||||
switch (flow_dir_) {
|
||||
case NodeViewCommon::kLeftToRight:
|
||||
default:
|
||||
return pos() + QPointF(rect().right(), rect().center().y());
|
||||
case NodeViewCommon::kRightToLeft:
|
||||
return pos() + QPointF(rect().left(), rect().center().y());
|
||||
case NodeViewCommon::kTopToBottom:
|
||||
return pos() + QPointF(rect().center().x(), rect().bottom());
|
||||
case NodeViewCommon::kBottomToTop:
|
||||
return pos() + QPointF(rect().center().x(), rect().top());
|
||||
}
|
||||
|
||||
} else {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
|
||||
@@ -448,15 +613,35 @@ QPointF NodeViewItem::GetParamPoint(NodeParam *param) const
|
||||
input = static_cast<NodeInput*>(input->parent());
|
||||
}
|
||||
|
||||
return pos() + GetInputPoint(node_inputs_.indexOf(input));
|
||||
return pos() + GetInputPoint(node_inputs_.indexOf(input), source_pos);
|
||||
}
|
||||
}
|
||||
|
||||
QPointF NodeViewItem::GetInputPoint(int index) const
|
||||
void NodeViewItem::SetFlowDirection(NodeViewCommon::FlowDirection dir)
|
||||
{
|
||||
flow_dir_ = dir;
|
||||
}
|
||||
|
||||
QPointF NodeViewItem::GetInputPoint(int index, const QPointF& source_pos) const
|
||||
{
|
||||
QRectF input_rect = GetInputRect(index);
|
||||
|
||||
return QPointF(input_rect.left(), input_rect.center().y());
|
||||
Qt::Orientation flow_orientation = NodeViewCommon::GetFlowOrientation(flow_dir_);
|
||||
|
||||
if (flow_orientation == Qt::Horizontal || IsExpanded()) {
|
||||
if (flow_dir_ == NodeViewCommon::kLeftToRight
|
||||
|| (flow_orientation == Qt::Vertical && source_pos.x() < pos().x())) {
|
||||
return QPointF(input_rect.left(), input_rect.center().y());
|
||||
} else {
|
||||
return QPointF(input_rect.right(), input_rect.center().y());
|
||||
}
|
||||
} else {
|
||||
if (flow_dir_ == NodeViewCommon::kTopToBottom) {
|
||||
return QPointF(input_rect.center().x(), input_rect.top());
|
||||
} else {
|
||||
return QPointF(input_rect.center().x(), input_rect.bottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "node/node.h"
|
||||
#include "nodeviewcommon.h"
|
||||
#include "nodeviewedge.h"
|
||||
#include "nodeviewitemwidgetproxy.h"
|
||||
|
||||
@@ -45,6 +46,9 @@ class NodeViewItem : public QGraphicsRectItem
|
||||
public:
|
||||
NodeViewItem(QGraphicsItem* parent = nullptr);
|
||||
|
||||
QPointF GetNodePosition() const;
|
||||
void SetNodePosition(const QPointF& pos);
|
||||
|
||||
/**
|
||||
* @brief Set the Node to correspond to this widget
|
||||
*/
|
||||
@@ -63,13 +67,32 @@ public:
|
||||
/**
|
||||
* @brief Set expanded state
|
||||
*/
|
||||
void SetExpanded(bool e);
|
||||
void SetExpanded(bool e, bool hide_titlebar = false);
|
||||
void ToggleExpanded();
|
||||
|
||||
/**
|
||||
* @brief Returns GLOBAL point that edges should connect to for any NodeParam member of this object
|
||||
*/
|
||||
QPointF GetParamPoint(NodeParam* param) const;
|
||||
QPointF GetParamPoint(NodeParam* param, const QPointF &source_pos) const;
|
||||
|
||||
/**
|
||||
* @brief Sets the direction nodes are flowing
|
||||
*/
|
||||
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
|
||||
|
||||
static int DefaultTextPadding();
|
||||
|
||||
static int DefaultItemHeight();
|
||||
|
||||
static int DefaultItemWidth();
|
||||
|
||||
static int DefaultMaximumTextWidth();
|
||||
|
||||
static int DefaultItemBorder();
|
||||
|
||||
qreal DefaultItemHorizontalPadding() const;
|
||||
|
||||
qreal DefaultItemVerticalPadding() const;
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
@@ -77,6 +100,7 @@ protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
||||
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||
|
||||
@@ -94,7 +118,7 @@ private:
|
||||
/**
|
||||
* @brief Returns local point that edges should connect to for a NodeInput in array node_inputs_[index]
|
||||
*/
|
||||
QPointF GetInputPoint(int index) const;
|
||||
QPointF GetInputPoint(int index, const QPointF &source_pos) const;
|
||||
|
||||
/**
|
||||
* @brief Reference to attached Node
|
||||
@@ -136,6 +160,8 @@ private:
|
||||
*/
|
||||
bool expanded_;
|
||||
|
||||
bool hide_titlebar_;
|
||||
|
||||
/**
|
||||
* @brief Current click mode
|
||||
*
|
||||
@@ -153,6 +179,8 @@ private:
|
||||
*/
|
||||
QUndoCommand* node_edge_change_command_;
|
||||
|
||||
NodeViewCommon::FlowDirection flow_dir_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -20,14 +20,40 @@
|
||||
|
||||
#include "nodeviewscene.h"
|
||||
|
||||
#include "nodeviewedge.h"
|
||||
#include "nodeviewitem.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
NodeViewScene::NodeViewScene(QObject *parent) :
|
||||
QGraphicsScene(parent),
|
||||
graph_(nullptr)
|
||||
graph_(nullptr),
|
||||
direction_(NodeViewCommon::kLeftToRight)
|
||||
{
|
||||
connect(&reorganize_timer_, &QTimer::timeout, &reorganize_timer_, &QTimer::stop);
|
||||
connect(&reorganize_timer_, &QTimer::timeout, this, &NodeViewScene::Reorganize);
|
||||
}
|
||||
|
||||
void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction)
|
||||
{
|
||||
direction_ = direction;
|
||||
|
||||
{
|
||||
// Iterate over node items setting direction
|
||||
QHash<Node*, NodeViewItem*>::const_iterator i;
|
||||
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
|
||||
i.value()->SetFlowDirection(direction_);
|
||||
|
||||
// Update position too
|
||||
i.value()->SetNodePosition(i.key()->GetPosition());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Iterate over edge items setting direction
|
||||
QHash<NodeEdge*, NodeViewEdge*>::const_iterator i;
|
||||
for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) {
|
||||
i.value()->SetFlowDirection(direction_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewScene::clear()
|
||||
@@ -35,7 +61,7 @@ void NodeViewScene::clear()
|
||||
// Deselect everything (prevents signals that a selection has changed after deleting an object)
|
||||
DeselectAll();
|
||||
|
||||
// HACK: QGraphicsScene contains some sort of internal hashing of the selected items which doesn't update unless
|
||||
// HACK: QGraphicsScene contains some sort of internal caching of the selected items which doesn't update unless
|
||||
// we call a function like this. That means even though we deselect all items above, QGraphicsScene will
|
||||
// continue to incorrectly signal selectionChanged() when items that were selected (but are now not) get
|
||||
// deleted. Calling this function appears to update the internal cache and prevent this.
|
||||
@@ -119,6 +145,21 @@ QList<NodeViewItem *> NodeViewScene::GetSelectedItems() const
|
||||
return selected;
|
||||
}
|
||||
|
||||
QList<NodeEdge*> NodeViewScene::GetSelectedEdges() const
|
||||
{
|
||||
QList<NodeEdge*> edges;
|
||||
|
||||
QHash<NodeEdge*, NodeViewEdge*>::const_iterator i;
|
||||
|
||||
for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) {
|
||||
if (i.value()->isSelected()) {
|
||||
edges.append(i.key());
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
const QHash<Node *, NodeViewItem *> &NodeViewScene::item_map() const
|
||||
{
|
||||
return item_map_;
|
||||
@@ -133,6 +174,7 @@ void NodeViewScene::AddNode(Node* node)
|
||||
{
|
||||
NodeViewItem* item = new NodeViewItem();
|
||||
|
||||
item->SetFlowDirection(direction_);
|
||||
item->SetNode(node);
|
||||
|
||||
addItem(item);
|
||||
@@ -152,11 +194,15 @@ void NodeViewScene::AddNode(Node* node)
|
||||
}
|
||||
}
|
||||
|
||||
QueueReorganize();
|
||||
connect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged);
|
||||
connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged);
|
||||
}
|
||||
|
||||
void NodeViewScene::RemoveNode(Node *node)
|
||||
{
|
||||
disconnect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged);
|
||||
disconnect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged);
|
||||
|
||||
delete item_map_.take(node);
|
||||
}
|
||||
|
||||
@@ -165,11 +211,10 @@ void NodeViewScene::AddEdge(NodeEdgePtr edge)
|
||||
NodeViewEdge* edge_ui = new NodeViewEdge();
|
||||
|
||||
edge_ui->SetEdge(edge);
|
||||
edge_ui->SetFlowDirection(direction_);
|
||||
|
||||
addItem(edge_ui);
|
||||
edge_map_.insert(edge.get(), edge_ui);
|
||||
|
||||
QueueReorganize();
|
||||
}
|
||||
|
||||
void NodeViewScene::RemoveEdge(NodeEdgePtr edge)
|
||||
@@ -177,146 +222,47 @@ void NodeViewScene::RemoveEdge(NodeEdgePtr edge)
|
||||
delete edge_map_.take(edge.get());
|
||||
}
|
||||
|
||||
void NodeViewScene::QueueReorganize()
|
||||
Qt::Orientation NodeViewScene::GetFlowOrientation() const
|
||||
{
|
||||
// Avoids the fairly complex Reorganize() function every single time a connection or node is added
|
||||
|
||||
reorganize_timer_.stop();
|
||||
reorganize_timer_.start(20);
|
||||
return NodeViewCommon::GetFlowOrientation(direction_);
|
||||
}
|
||||
|
||||
QList<Node *> NodeViewScene::GetNodeDirectDescendants(Node* n, const QList<Node*> connected_nodes, QList<Node*>& processed_nodes)
|
||||
NodeViewCommon::FlowDirection NodeViewScene::GetFlowDirection() const
|
||||
{
|
||||
QList<Node*> direct_descendants = connected_nodes;
|
||||
|
||||
processed_nodes.append(n);
|
||||
|
||||
// Remove any nodes that aren't necessarily attached directly
|
||||
for (int i=0;i<direct_descendants.size();i++) {
|
||||
Node* connected = direct_descendants.at(i);
|
||||
|
||||
for (int j=1;j<connected->output()->edges().size();j++) {
|
||||
Node* this_output_connection = connected->output()->edges().at(j)->input()->parentNode();
|
||||
if (!processed_nodes.contains(this_output_connection)) {
|
||||
direct_descendants.removeAt(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return direct_descendants;
|
||||
return direction_;
|
||||
}
|
||||
|
||||
int NodeViewScene::FindWeightsInternal(Node *node, QHash<Node *, int> &weights, QList<Node*>& weighted_nodes)
|
||||
void NodeViewScene::ReorganizeFrom(Node* n)
|
||||
{
|
||||
QList<Node*> connected_nodes = node->GetImmediateDependencies();
|
||||
QList<Node*> immediates = n->GetImmediateDependencies();
|
||||
|
||||
int weight = 0;
|
||||
|
||||
if (!connected_nodes.isEmpty()) {
|
||||
QList<Node*> direct_descendants = GetNodeDirectDescendants(node, connected_nodes, weighted_nodes);
|
||||
|
||||
foreach (Node* dep, direct_descendants) {
|
||||
weight += FindWeightsInternal(dep, weights, weighted_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
weight = qMax(weight, 1);
|
||||
|
||||
weights.insert(node, weight);
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
void NodeViewScene::ReorganizeInternal(NodeViewItem* src_item, QHash<Node*, int>& weights, QList<Node*>& positioned_nodes)
|
||||
{
|
||||
if (!src_item) {
|
||||
if (immediates.isEmpty()) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
Node* n = src_item->GetNode();
|
||||
QPointF parent_pos = n->GetPosition();
|
||||
|
||||
QList<Node*> connected_nodes = n->GetImmediateDependencies();
|
||||
qreal child_x = parent_pos.x() - 1.0;
|
||||
qreal children_height = immediates.size()-1;
|
||||
qreal children_y = parent_pos.y() - children_height * 0.5;
|
||||
|
||||
if (connected_nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (int i=0;i<immediates.size();i++) {
|
||||
immediates.at(i)->SetPosition(QPointF(child_x,
|
||||
children_y + i));
|
||||
|
||||
QList<Node*> direct_descendants = GetNodeDirectDescendants(n, connected_nodes, positioned_nodes);
|
||||
|
||||
int descendant_weight = 0;
|
||||
foreach (Node* dep, direct_descendants) {
|
||||
descendant_weight += weights.value(dep);
|
||||
}
|
||||
|
||||
qreal center_y = src_item->y();
|
||||
qreal total_height = descendant_weight * src_item->rect().height() + (direct_descendants.size()-1) * src_item->rect().height()/2;
|
||||
double item_top = center_y - (total_height/2) + src_item->rect().height()/2;
|
||||
|
||||
// Set each node's position
|
||||
int weight_index = 0;
|
||||
for (int i=0;i<direct_descendants.size();i++) {
|
||||
Node* connected = direct_descendants.at(i);
|
||||
|
||||
NodeViewItem* item = NodeToUIObject(connected);
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double item_y = item_top;
|
||||
|
||||
// Multiply the index by the item height (with 1.5 for padding)
|
||||
item_y += weight_index * src_item->rect().height() * 1.5;
|
||||
|
||||
QPointF item_pos(src_item->pos().x() - item->rect().width() * 3 / 2,
|
||||
item_y);
|
||||
|
||||
item->setPos(item_pos);
|
||||
|
||||
weight_index += weights.value(connected);
|
||||
}
|
||||
|
||||
// Recursively work on each node
|
||||
foreach (Node* connected, connected_nodes) {
|
||||
NodeViewItem* item = NodeToUIObject(connected);
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ReorganizeInternal(item, weights, positioned_nodes);
|
||||
ReorganizeFrom(immediates.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewScene::Reorganize()
|
||||
void NodeViewScene::NodePositionChanged(const QPointF &pos)
|
||||
{
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
item_map_.value(static_cast<Node*>(sender()))->SetNodePosition(pos);
|
||||
}
|
||||
|
||||
QList<Node*> end_nodes;
|
||||
|
||||
// Calculate the nodes that don't output to anything, they'll be our anchors
|
||||
foreach (Node* node, graph_->nodes()) {
|
||||
if (!node->HasConnectedOutputs()) {
|
||||
end_nodes.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Node*> processed_nodes;
|
||||
|
||||
QHash<Node*, int> node_weights;
|
||||
foreach (Node* end_node, end_nodes) {
|
||||
FindWeightsInternal(end_node, node_weights, processed_nodes);
|
||||
}
|
||||
|
||||
processed_nodes.clear();
|
||||
|
||||
foreach (Node* end_node, end_nodes) {
|
||||
ReorganizeInternal(NodeToUIObject(end_node), node_weights, processed_nodes);
|
||||
}
|
||||
void NodeViewScene::NodeLabelChanged()
|
||||
{
|
||||
item_map_.value(static_cast<Node*>(sender()))->update();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include <QTimer>
|
||||
|
||||
#include "node/graph.h"
|
||||
#include "widget/nodeview/nodeviewedge.h"
|
||||
#include "widget/nodeview/nodeviewitem.h"
|
||||
#include "nodeviewedge.h"
|
||||
#include "nodeviewitem.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -65,10 +65,21 @@ public:
|
||||
|
||||
QList<Node*> GetSelectedNodes() const;
|
||||
QList<NodeViewItem*> GetSelectedItems() const;
|
||||
QList<NodeEdge *> GetSelectedEdges() const;
|
||||
|
||||
const QHash<Node*, NodeViewItem*>& item_map() const;
|
||||
const QHash<NodeEdge*, NodeViewEdge*>& edge_map() const;
|
||||
|
||||
Qt::Orientation GetFlowOrientation() const;
|
||||
|
||||
NodeViewCommon::FlowDirection GetFlowDirection() const;
|
||||
void SetFlowDirection(NodeViewCommon::FlowDirection direction);
|
||||
|
||||
/**
|
||||
* @brief Automatically reposition the nodes based on their connections
|
||||
*/
|
||||
void ReorganizeFrom(Node* n);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Slot when a Node is added to a graph (SetGraph() connects this)
|
||||
@@ -103,27 +114,24 @@ public slots:
|
||||
void RemoveEdge(NodeEdgePtr edge);
|
||||
|
||||
private:
|
||||
void QueueReorganize();
|
||||
|
||||
QList<Node*> GetNodeDirectDescendants(Node* n, const QList<Node*> connected_nodes, QList<Node*>& processed_nodes);
|
||||
|
||||
int FindWeightsInternal(Node* node, QHash<Node*, int>& weights, QList<Node*>& weighted_nodes);
|
||||
|
||||
void ReorganizeInternal(NodeViewItem *src_item, QHash<Node*, int>& weights, QList<Node *> &positioned_nodes);
|
||||
|
||||
QHash<Node*, NodeViewItem*> item_map_;
|
||||
|
||||
QHash<NodeEdge*, NodeViewEdge*> edge_map_;
|
||||
|
||||
QTimer reorganize_timer_;
|
||||
|
||||
NodeGraph* graph_;
|
||||
|
||||
NodeViewCommon::FlowDirection direction_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Automatically reposition the nodes based on their connections
|
||||
* @brief Receiver for whenever a node position changes
|
||||
*/
|
||||
void Reorganize();
|
||||
void NodePositionChanged(const QPointF& pos);
|
||||
|
||||
/**
|
||||
* @brief Receiver for when a node's label has changed
|
||||
*/
|
||||
void NodeLabelChanged();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -165,6 +165,8 @@ public:
|
||||
|
||||
virtual void ToggleSelectedEnabled(){}
|
||||
|
||||
virtual void Duplicate(){}
|
||||
|
||||
signals:
|
||||
void CloseRequested();
|
||||
|
||||
|
||||
@@ -49,7 +49,9 @@ void HistogramScope::SetBuffer(Frame* frame)
|
||||
{
|
||||
buffer_ = frame;
|
||||
|
||||
StartUpdate();
|
||||
if (isVisible()) {
|
||||
StartUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramScope::FinishedProcessing(QVector<double> red, QVector<double> green, QVector<double> blue)
|
||||
@@ -111,6 +113,13 @@ void HistogramScope::StartUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramScope::showEvent(QShowEvent* e)
|
||||
{
|
||||
ManagedDisplayWidget::showEvent(e);
|
||||
|
||||
StartUpdate();
|
||||
}
|
||||
|
||||
HistogramScopeWorker::HistogramScopeWorker() :
|
||||
cancelled_(false)
|
||||
{
|
||||
|
||||
@@ -78,6 +78,8 @@ protected:
|
||||
|
||||
virtual void ColorProcessorChangedEvent() override;
|
||||
|
||||
virtual void showEvent(QShowEvent* e) override;
|
||||
|
||||
private:
|
||||
void StartUpdate();
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
#include "waveform.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
#include <QDebug>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "node/node.h"
|
||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
||||
|
||||
@@ -28,16 +33,32 @@ OLIVE_NAMESPACE_ENTER
|
||||
|
||||
WaveformScope::WaveformScope(QWidget* parent) :
|
||||
ManagedDisplayWidget(parent),
|
||||
texture_(nullptr)
|
||||
buffer_(nullptr)
|
||||
{
|
||||
EnableDefaultContextMenu();
|
||||
}
|
||||
|
||||
void WaveformScope::SetTexture(OpenGLTexture *texture)
|
||||
WaveformScope::~WaveformScope()
|
||||
{
|
||||
texture_ = texture;
|
||||
CleanUp();
|
||||
|
||||
update();
|
||||
if (context()) {
|
||||
disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp);
|
||||
}
|
||||
}
|
||||
|
||||
void WaveformScope::SetBuffer(Frame *frame)
|
||||
{
|
||||
buffer_ = frame;
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
void WaveformScope::showEvent(QShowEvent* e)
|
||||
{
|
||||
ManagedDisplayWidget::showEvent(e);
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
void WaveformScope::initializeGL()
|
||||
@@ -49,37 +70,153 @@ void WaveformScope::initializeGL()
|
||||
pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex());
|
||||
pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag"));
|
||||
pipeline_->link();
|
||||
|
||||
framebuffer_.Create(context());
|
||||
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp, Qt::DirectConnection);
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
void WaveformScope::paintGL()
|
||||
{
|
||||
context()->functions()->glClearColor(0, 0, 0, 0);
|
||||
context()->functions()->glClear(GL_COLOR_BUFFER_BIT);
|
||||
QOpenGLFunctions* f = context()->functions();
|
||||
|
||||
if (!pipeline_ || !texture_) {
|
||||
f->glClearColor(0, 0, 0, 0);
|
||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
float waveform_scale = 0.80f;
|
||||
float waveform_dim_x = width() * waveform_scale;
|
||||
float waveform_dim_y = height() * waveform_scale;
|
||||
float waveform_start_dim_x = (width() - waveform_dim_x) / 2.0f;
|
||||
float waveform_start_dim_y = (height() - waveform_dim_y) / 2.0f;
|
||||
float waveform_end_dim_x = width() - waveform_start_dim_x;
|
||||
float waveform_end_dim_y = height() - waveform_start_dim_y;
|
||||
|
||||
if (buffer_ && pipeline_ && texture_.IsCreated()) {
|
||||
// Convert reference frame to display space
|
||||
framebuffer_.Attach(&managed_tex_);
|
||||
framebuffer_.Bind();
|
||||
|
||||
texture_.Bind();
|
||||
|
||||
f->glViewport(0, 0, texture_.width(), texture_.height());
|
||||
|
||||
color_service()->ProcessOpenGL();
|
||||
|
||||
texture_.Release();
|
||||
|
||||
framebuffer_.Release();
|
||||
framebuffer_.Detach();
|
||||
|
||||
// Draw waveform through shader
|
||||
pipeline_->bind();
|
||||
pipeline_->setUniformValue("ove_resolution", texture_.width(), texture_.height());
|
||||
pipeline_->setUniformValue("ove_viewport", width(), height());
|
||||
GLfloat luma[3] = {0.0, 0.0, 0.0};
|
||||
color_manager()->GetDefaultLumaCoefs(luma);
|
||||
pipeline_->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]);
|
||||
|
||||
// Scale of the waveform relative to the viewport surface.
|
||||
pipeline_->setUniformValue("waveform_scale", waveform_scale);
|
||||
pipeline_->setUniformValue(
|
||||
"waveform_dims", waveform_dim_x, waveform_dim_y);
|
||||
|
||||
pipeline_->setUniformValue(
|
||||
"waveform_region",
|
||||
waveform_start_dim_x, waveform_start_dim_y,
|
||||
waveform_end_dim_x, waveform_end_dim_y);
|
||||
|
||||
float waveform_start_uv_x = waveform_start_dim_x / width();
|
||||
float waveform_start_uv_y = waveform_start_dim_y / height();
|
||||
float waveform_end_uv_x = waveform_end_dim_x / width();
|
||||
float waveform_end_uv_y = waveform_end_dim_y / height();
|
||||
pipeline_->setUniformValue(
|
||||
"waveform_uv",
|
||||
waveform_start_uv_x, waveform_start_uv_y,
|
||||
waveform_end_uv_x, waveform_end_uv_y);
|
||||
|
||||
pipeline_->release();
|
||||
|
||||
f->glViewport(0, 0, width(), height());
|
||||
|
||||
managed_tex_.Bind();
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline_);
|
||||
|
||||
managed_tex_.Release();
|
||||
}
|
||||
|
||||
// Draw line overlays
|
||||
QPainter p(this);
|
||||
QFontMetrics font_metrics = QFontMetrics(QFont());
|
||||
QString label;
|
||||
float ire_increment = 0.1f;
|
||||
float ire_steps = int(1.0 / ire_increment);
|
||||
QVector<QLine> ire_lines(ire_steps + 1);
|
||||
int font_x_offset = 0;
|
||||
int font_y_offset = font_metrics.capHeight() / 2.0f;
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_Plus);
|
||||
|
||||
p.setPen(QColor(0.0, 0.6 * 255.0, 0.0));
|
||||
p.setFont(QFont());
|
||||
|
||||
for (int i=0; i <= ire_steps; i++) {
|
||||
ire_lines[i].setLine(
|
||||
waveform_start_dim_x,
|
||||
(waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y,
|
||||
waveform_end_dim_x,
|
||||
(waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y);
|
||||
label = QString::number(1.0 - (i * ire_increment), 'f', 1);
|
||||
font_x_offset = QFontMetricsWidth(font_metrics, label) + 4;
|
||||
|
||||
p.drawText(
|
||||
waveform_start_dim_x - font_x_offset,
|
||||
(waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y + font_y_offset,
|
||||
label);
|
||||
}
|
||||
p.drawLines(ire_lines);
|
||||
}
|
||||
|
||||
void WaveformScope::UploadTextureFromBuffer()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pipeline_->bind();
|
||||
pipeline_->setUniformValue("ove_resolution", texture_->width(), texture_->height());
|
||||
pipeline_->setUniformValue("ove_viewport", width(), height());
|
||||
if (buffer_) {
|
||||
makeCurrent();
|
||||
|
||||
// The general size of a pixel
|
||||
pipeline_->setUniformValue("threshold", 2.0f / static_cast<float>(height()));
|
||||
if (!texture_.IsCreated()
|
||||
|| texture_.width() != buffer_->width()
|
||||
|| texture_.height() != buffer_->height()
|
||||
|| texture_.format() != buffer_->format()) {
|
||||
texture_.Destroy();
|
||||
managed_tex_.Destroy();
|
||||
|
||||
pipeline_->release();
|
||||
texture_.Create(context(), buffer_);
|
||||
managed_tex_.Create(context(), buffer_->width(), buffer_->height(), buffer_->format());
|
||||
} else {
|
||||
texture_.Upload(buffer_);
|
||||
}
|
||||
|
||||
texture_->Bind();
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline_);
|
||||
|
||||
texture_->Release();
|
||||
update();
|
||||
}
|
||||
|
||||
void WaveformScope::CleanUp()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
pipeline_ = nullptr;
|
||||
texture_ = nullptr;
|
||||
texture_.Destroy();
|
||||
managed_tex_.Destroy();
|
||||
framebuffer_.Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "codec/frame.h"
|
||||
#include "render/backend/opengl/openglcolorprocessor.h"
|
||||
#include "render/backend/opengl/openglframebuffer.h"
|
||||
#include "render/backend/opengl/openglshader.h"
|
||||
#include "render/backend/opengl/opengltexture.h"
|
||||
#include "widget/manageddisplay/manageddisplay.h"
|
||||
@@ -35,18 +36,30 @@ class WaveformScope : public ManagedDisplayWidget
|
||||
public:
|
||||
WaveformScope(QWidget* parent = nullptr);
|
||||
|
||||
virtual ~WaveformScope() override;
|
||||
|
||||
public slots:
|
||||
void SetTexture(OpenGLTexture* texture);
|
||||
void SetBuffer(Frame* frame);
|
||||
|
||||
protected:
|
||||
virtual void initializeGL() override;
|
||||
|
||||
virtual void paintGL() override;
|
||||
|
||||
virtual void showEvent(QShowEvent* e) override;
|
||||
|
||||
private:
|
||||
void UploadTextureFromBuffer();
|
||||
|
||||
OpenGLShaderPtr pipeline_;
|
||||
|
||||
OpenGLTexture* texture_;
|
||||
OpenGLTexture texture_;
|
||||
|
||||
OpenGLTexture managed_tex_;
|
||||
|
||||
OpenGLFramebuffer framebuffer_;
|
||||
|
||||
Frame* buffer_;
|
||||
|
||||
private slots:
|
||||
void CleanUp();
|
||||
|
||||
@@ -91,7 +91,7 @@ void TimelineWidget::PointerTool::MousePress(TimelineViewMouseEvent *event)
|
||||
if (!(event->GetModifiers() & Qt::AltModifier)) {
|
||||
parent()->SetBlockLinksSelected(item->block(), true);
|
||||
}
|
||||
} else {
|
||||
} else if (event->GetButton() == Qt::LeftButton) {
|
||||
// Start rubberband drag
|
||||
parent()->StartRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier));
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/timelinewidget/view/handmovableview.h
|
||||
widget/timelinewidget/view/handmovableview.cpp
|
||||
widget/timelinewidget/view/timelineplayhead.h
|
||||
widget/timelinewidget/view/timelineplayhead.cpp
|
||||
widget/timelinewidget/view/timelineview.h
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/***
|
||||
|
||||
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 "handmovableview.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
HandMovableView::HandMovableView(QWidget* parent) :
|
||||
QGraphicsView(parent),
|
||||
dragging_hand_(false)
|
||||
{
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged);
|
||||
}
|
||||
|
||||
void HandMovableView::ApplicationToolChanged(Tool::Item tool)
|
||||
{
|
||||
if (tool == Tool::kHand) {
|
||||
setDragMode(ScrollHandDrag);
|
||||
} else {
|
||||
setDragMode(default_drag_mode_);
|
||||
}
|
||||
|
||||
ToolChangedEvent(tool);
|
||||
}
|
||||
|
||||
bool HandMovableView::HandPress(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::MiddleButton) {
|
||||
pre_hand_drag_mode_ = dragMode();
|
||||
dragging_hand_ = true;
|
||||
|
||||
setDragMode(ScrollHandDrag);
|
||||
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mousePressEvent(&transformed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HandMovableView::HandMove(QMouseEvent *event)
|
||||
{
|
||||
if (dragging_hand_) {
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mouseMoveEvent(&transformed);
|
||||
}
|
||||
return dragging_hand_;
|
||||
}
|
||||
|
||||
bool HandMovableView::HandRelease(QMouseEvent *event)
|
||||
{
|
||||
if (dragging_hand_) {
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mouseReleaseEvent(&transformed);
|
||||
|
||||
setDragMode(pre_hand_drag_mode_);
|
||||
|
||||
dragging_hand_ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandMovableView::SetDefaultDragMode(QGraphicsView::DragMode mode)
|
||||
{
|
||||
default_drag_mode_ = mode;
|
||||
setDragMode(default_drag_mode_);
|
||||
}
|
||||
|
||||
const QGraphicsView::DragMode &HandMovableView::GetDefaultDragMode() const
|
||||
{
|
||||
return default_drag_mode_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -0,0 +1,59 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef HANDMOVABLEVIEW_H
|
||||
#define HANDMOVABLEVIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
#include "tool/tool.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class HandMovableView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HandMovableView(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
virtual void ToolChangedEvent(Tool::Item tool){Q_UNUSED(tool)}
|
||||
|
||||
bool HandPress(QMouseEvent* event);
|
||||
bool HandMove(QMouseEvent* event);
|
||||
bool HandRelease(QMouseEvent* event);
|
||||
|
||||
void SetDefaultDragMode(DragMode mode);
|
||||
const DragMode& GetDefaultDragMode() const;
|
||||
|
||||
private:
|
||||
bool dragging_hand_;
|
||||
DragMode pre_hand_drag_mode_;
|
||||
|
||||
DragMode default_drag_mode_;
|
||||
|
||||
private slots:
|
||||
void ApplicationToolChanged(Tool::Item tool);
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // HANDMOVABLEVIEW_H
|
||||
@@ -81,7 +81,7 @@ void TimelineView::mousePressEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->modifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event);
|
||||
|
||||
emit MousePressed(&timeline_event);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->modifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event);
|
||||
|
||||
emit MouseMoved(&timeline_event);
|
||||
}
|
||||
@@ -115,14 +115,14 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->modifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event);
|
||||
|
||||
emit MouseReleased(&timeline_event);
|
||||
}
|
||||
|
||||
void TimelineView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->modifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event);
|
||||
|
||||
emit MouseDoubleClicked(&timeline_event);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ void TimelineView::wheelEvent(QWheelEvent *event)
|
||||
|
||||
void TimelineView::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->keyboardModifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers());
|
||||
|
||||
timeline_event.SetMimeData(event->mimeData());
|
||||
timeline_event.SetEvent(event);
|
||||
@@ -156,7 +156,7 @@ void TimelineView::dragEnterEvent(QDragEnterEvent *event)
|
||||
|
||||
void TimelineView::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->keyboardModifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers());
|
||||
|
||||
timeline_event.SetMimeData(event->mimeData());
|
||||
timeline_event.SetEvent(event);
|
||||
@@ -171,7 +171,7 @@ void TimelineView::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
|
||||
void TimelineView::dropEvent(QDropEvent *event)
|
||||
{
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), event->keyboardModifiers());
|
||||
TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers());
|
||||
|
||||
timeline_event.SetMimeData(event->mimeData());
|
||||
timeline_event.SetEvent(event);
|
||||
@@ -273,17 +273,21 @@ TimelineCoordinate TimelineView::SceneToCoordinate(const QPointF& pt)
|
||||
return TimelineCoordinate(SceneToTime(pt.x()), TrackReference(ConnectedTrackType(), SceneToTrack(pt.y())));
|
||||
}
|
||||
|
||||
TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::KeyboardModifiers modifiers)
|
||||
TimelineViewMouseEvent TimelineView::CreateMouseEvent(QMouseEvent *event)
|
||||
{
|
||||
return CreateMouseEvent(event->pos(), event->button(), event->modifiers());
|
||||
}
|
||||
|
||||
TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
QPointF scene_pt = mapToScene(pos);
|
||||
|
||||
TimelineViewMouseEvent timeline_event(scene_pt.x(),
|
||||
GetScale(),
|
||||
timebase(),
|
||||
TrackReference(ConnectedTrackType(), SceneToTrack(scene_pt.y())),
|
||||
modifiers);
|
||||
|
||||
return timeline_event;
|
||||
return TimelineViewMouseEvent(scene_pt.x(),
|
||||
GetScale(),
|
||||
timebase(),
|
||||
TrackReference(ConnectedTrackType(), SceneToTrack(scene_pt.y())),
|
||||
button,
|
||||
modifiers);
|
||||
}
|
||||
|
||||
int TimelineView::GetHeightOfAllTracks() const
|
||||
|
||||
@@ -100,7 +100,8 @@ private:
|
||||
TimelineCoordinate ScreenToCoordinate(const QPoint& pt);
|
||||
TimelineCoordinate SceneToCoordinate(const QPointF& pt);
|
||||
|
||||
TimelineViewMouseEvent CreateMouseEvent(const QPoint &pos, Qt::KeyboardModifiers modifiers);
|
||||
TimelineViewMouseEvent CreateMouseEvent(QMouseEvent* event);
|
||||
TimelineViewMouseEvent CreateMouseEvent(const QPoint &pos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
int GetHeightOfAllTracks() const;
|
||||
|
||||
|
||||
@@ -34,12 +34,11 @@ OLIVE_NAMESPACE_ENTER
|
||||
const double TimelineViewBase::kMaximumScale = 8192;
|
||||
|
||||
TimelineViewBase::TimelineViewBase(QWidget *parent) :
|
||||
QGraphicsView(parent),
|
||||
HandMovableView(parent),
|
||||
playhead_(0),
|
||||
playhead_scene_left_(-1),
|
||||
playhead_scene_right_(-1),
|
||||
dragging_playhead_(false),
|
||||
dragging_hand_(false),
|
||||
limit_y_axis_(false)
|
||||
{
|
||||
setScene(&scene_);
|
||||
@@ -50,7 +49,6 @@ TimelineViewBase::TimelineViewBase(QWidget *parent) :
|
||||
SetDefaultDragMode(NoDrag);
|
||||
|
||||
connect(&scene_, SIGNAL(changed(const QList<QRectF>&)), this, SLOT(UpdateSceneRect()));
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &TimelineViewBase::ApplicationToolChanged);
|
||||
|
||||
SetMaximumScale(kMaximumScale);
|
||||
}
|
||||
@@ -100,17 +98,6 @@ rational TimelineViewBase::GetPlayheadTime() const
|
||||
return Timecode::timestamp_to_time(playhead_, timebase());
|
||||
}
|
||||
|
||||
void TimelineViewBase::SetDefaultDragMode(QGraphicsView::DragMode mode)
|
||||
{
|
||||
default_drag_mode_ = mode;
|
||||
setDragMode(default_drag_mode_);
|
||||
}
|
||||
|
||||
const QGraphicsView::DragMode &TimelineViewBase::GetDefaultDragMode() const
|
||||
{
|
||||
return default_drag_mode_;
|
||||
}
|
||||
|
||||
bool TimelineViewBase::PlayheadPress(QMouseEvent *event)
|
||||
{
|
||||
QPointF scene_pos = mapToScene(event->pos());
|
||||
@@ -148,70 +135,6 @@ bool TimelineViewBase::PlayheadRelease(QMouseEvent*)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TimelineViewBase::HandPress(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::MiddleButton) {
|
||||
pre_hand_drag_mode_ = dragMode();
|
||||
dragging_hand_ = true;
|
||||
|
||||
setDragMode(ScrollHandDrag);
|
||||
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mousePressEvent(&transformed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TimelineViewBase::HandMove(QMouseEvent *event)
|
||||
{
|
||||
if (dragging_hand_) {
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mouseMoveEvent(&transformed);
|
||||
}
|
||||
return dragging_hand_;
|
||||
}
|
||||
|
||||
bool TimelineViewBase::HandRelease(QMouseEvent *event)
|
||||
{
|
||||
if (dragging_hand_) {
|
||||
// Transform mouse event to act like the left button is pressed
|
||||
QMouseEvent transformed(event->type(),
|
||||
event->localPos(),
|
||||
Qt::LeftButton,
|
||||
Qt::LeftButton,
|
||||
event->modifiers());
|
||||
|
||||
QGraphicsView::mouseReleaseEvent(&transformed);
|
||||
|
||||
setDragMode(pre_hand_drag_mode_);
|
||||
|
||||
dragging_hand_ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TimelineViewBase::ToolChangedEvent(Tool::Item)
|
||||
{
|
||||
}
|
||||
|
||||
qreal TimelineViewBase::GetPlayheadX()
|
||||
{
|
||||
return TimeToScene(Timecode::timestamp_to_time(playhead_, timebase()));
|
||||
@@ -305,15 +228,4 @@ void TimelineViewBase::SetLimitYAxis(bool)
|
||||
UpdateSceneRect();
|
||||
}
|
||||
|
||||
void TimelineViewBase::ApplicationToolChanged(Tool::Item tool)
|
||||
{
|
||||
if (tool == Tool::kHand) {
|
||||
setDragMode(ScrollHandDrag);
|
||||
} else {
|
||||
setDragMode(default_drag_mode_);
|
||||
}
|
||||
|
||||
ToolChangedEvent(tool);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
#include <QGraphicsView>
|
||||
|
||||
#include "core.h"
|
||||
#include "handmovableview.h"
|
||||
#include "timelineplayhead.h"
|
||||
#include "widget/timelinewidget/timelinescaledobject.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class TimelineViewBase : public QGraphicsView, public TimelineScaledObject
|
||||
class TimelineViewBase : public HandMovableView, public TimelineScaledObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -66,19 +67,10 @@ protected:
|
||||
|
||||
rational GetPlayheadTime() const;
|
||||
|
||||
void SetDefaultDragMode(DragMode mode);
|
||||
const DragMode& GetDefaultDragMode() const;
|
||||
|
||||
bool PlayheadPress(QMouseEvent* event);
|
||||
bool PlayheadMove(QMouseEvent* event);
|
||||
bool PlayheadRelease(QMouseEvent* event);
|
||||
|
||||
bool HandPress(QMouseEvent* event);
|
||||
bool HandMove(QMouseEvent* event);
|
||||
bool HandRelease(QMouseEvent* event);
|
||||
|
||||
virtual void ToolChangedEvent(Tool::Item tool);
|
||||
|
||||
virtual void TimebaseChangedEvent(const rational &) override;
|
||||
|
||||
private:
|
||||
@@ -93,15 +85,10 @@ private:
|
||||
|
||||
bool dragging_playhead_;
|
||||
|
||||
bool dragging_hand_;
|
||||
DragMode pre_hand_drag_mode_;
|
||||
|
||||
QGraphicsScene scene_;
|
||||
|
||||
bool limit_y_axis_;
|
||||
|
||||
DragMode default_drag_mode_;
|
||||
|
||||
rational end_time_;
|
||||
|
||||
private slots:
|
||||
@@ -118,8 +105,6 @@ private slots:
|
||||
*/
|
||||
void PageScrollToPlayhead();
|
||||
|
||||
void ApplicationToolChanged(Tool::Item tool);
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -145,7 +145,7 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
|
||||
QFontMetrics fm = painter->fontMetrics();
|
||||
int text_width = qMin(qRound(rect().width()), QFontMetricsWidth(fm, block_->block_name()));
|
||||
|
||||
QPointF underline_start = rect().topLeft() + QPointF(0, fm.height());
|
||||
QPointF underline_start = rect().topLeft() + QPointF(0, text_top + fm.height());
|
||||
QPointF underline_end = underline_start + QPointF(text_width, 0);
|
||||
|
||||
painter->drawLine(underline_start, underline_end);
|
||||
|
||||
@@ -30,11 +30,13 @@ TimelineViewMouseEvent::TimelineViewMouseEvent(const qreal &scene_x,
|
||||
const double &scale_x,
|
||||
const rational &timebase,
|
||||
const TrackReference &track,
|
||||
const Qt::MouseButton &button,
|
||||
const Qt::KeyboardModifiers &modifiers) :
|
||||
scene_x_(scene_x),
|
||||
scale_x_(scale_x),
|
||||
timebase_(timebase),
|
||||
track_(track),
|
||||
button_(button),
|
||||
modifiers_(modifiers),
|
||||
source_event_(nullptr),
|
||||
mime_data_(nullptr)
|
||||
@@ -81,6 +83,11 @@ const qreal &TimelineViewMouseEvent::GetSceneX() const
|
||||
return scene_x_;
|
||||
}
|
||||
|
||||
const Qt::MouseButton &TimelineViewMouseEvent::GetButton() const
|
||||
{
|
||||
return button_;
|
||||
}
|
||||
|
||||
void TimelineViewMouseEvent::accept()
|
||||
{
|
||||
if (source_event_ != nullptr)
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
const double& scale_x,
|
||||
const rational& timebase,
|
||||
const TrackReference &track,
|
||||
const Qt::MouseButton &button,
|
||||
const Qt::KeyboardModifiers& modifiers = Qt::NoModifier);
|
||||
|
||||
TimelineCoordinate GetCoordinates(bool round_time = false) const;
|
||||
@@ -61,6 +62,8 @@ public:
|
||||
|
||||
const qreal& GetSceneX() const;
|
||||
|
||||
const Qt::MouseButton& GetButton() const;
|
||||
|
||||
void accept();
|
||||
void ignore();
|
||||
|
||||
@@ -71,6 +74,8 @@ private:
|
||||
|
||||
TrackReference track_;
|
||||
|
||||
Qt::MouseButton button_;
|
||||
|
||||
Qt::KeyboardModifiers modifiers_;
|
||||
|
||||
QEvent* source_event_;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "manageddisplayobject.h"
|
||||
|
||||
ManagedDisplayObject::ManagedDisplayObject()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef MANAGEDDISPLAYOBJECT_H
|
||||
#define MANAGEDDISPLAYOBJECT_H
|
||||
|
||||
|
||||
class ManagedDisplayObject
|
||||
{
|
||||
public:
|
||||
ManagedDisplayObject();
|
||||
};
|
||||
|
||||
#endif // MANAGEDDISPLAYOBJECT_H
|
||||
@@ -66,8 +66,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
connect(main_widget, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
||||
connect(main_widget, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor);
|
||||
connect(main_widget, &ViewerDisplayWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer);
|
||||
connect(main_widget, &ViewerDisplayWidget::LoadedTexture, this, &ViewerWidget::LoadedTexture);
|
||||
connect(main_widget, &ViewerDisplayWidget::DrewManagedTexture, this, &ViewerWidget::DrewManagedTexture);
|
||||
connect(main_widget, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
|
||||
connect(main_widget, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
|
||||
connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerDisplayWidget::SetMatrix);
|
||||
@@ -750,11 +748,6 @@ void ViewerWidget::SetSignalCursorColorEnabled(bool e)
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::SetEmitDrewManagedTextureEnabled(bool e)
|
||||
{
|
||||
main_gl_widget()->SetEmitDrewManagedTextureEnabled(e);
|
||||
}
|
||||
|
||||
void ViewerWidget::TimebaseChangedEvent(const rational &timebase)
|
||||
{
|
||||
TimeBasedWidget::TimebaseChangedEvent(timebase);
|
||||
|
||||
@@ -109,11 +109,6 @@ public slots:
|
||||
*/
|
||||
void SetSignalCursorColorEnabled(bool e);
|
||||
|
||||
/**
|
||||
* @brief Wrapper for ViewerGLWidget::SetEmitDrewManagedTextureEnabled()
|
||||
*/
|
||||
void SetEmitDrewManagedTextureEnabled(bool e);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Wrapper for ViewerGLWidget::CursorColor()
|
||||
@@ -125,16 +120,6 @@ signals:
|
||||
*/
|
||||
void LoadedBuffer(Frame* load_buffer);
|
||||
|
||||
/**
|
||||
* @brief Wrapper for ViewerGLWidget::LoadedTexture()
|
||||
*/
|
||||
void LoadedTexture(OpenGLTexture* texture);
|
||||
|
||||
/**
|
||||
* @brief Wrapper for ViewerGLWidget::DrewManagedTexture()
|
||||
*/
|
||||
void DrewManagedTexture(OpenGLTexture* texture);
|
||||
|
||||
/**
|
||||
* @brief Request a scope panel
|
||||
*
|
||||
|
||||
@@ -42,10 +42,8 @@ bool ViewerDisplayWidget::nouveau_check_done_ = false;
|
||||
|
||||
ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
||||
ManagedDisplayWidget(parent),
|
||||
managed_copy_pipeline_(nullptr),
|
||||
has_image_(false),
|
||||
signal_cursor_color_(false),
|
||||
enable_display_referred_signal_(false),
|
||||
gizmos_(nullptr)
|
||||
{
|
||||
}
|
||||
@@ -92,14 +90,12 @@ void ViewerDisplayWidget::SetImage(const QString &fn)
|
||||
input->read_image(input->spec().format, load_buffer_.data(), OIIO::AutoStride, load_buffer_.linesize_bytes());
|
||||
input->close();
|
||||
|
||||
emit LoadedBuffer(&load_buffer_);
|
||||
|
||||
texture_.Upload(load_buffer_.data(), load_buffer_.linesize_pixels());
|
||||
|
||||
emit LoadedTexture(&texture_);
|
||||
texture_.Upload(&load_buffer_);
|
||||
|
||||
doneCurrent();
|
||||
|
||||
emit LoadedBuffer(&load_buffer_);
|
||||
|
||||
has_image_ = true;
|
||||
|
||||
#if OIIO_VERSION < 10903
|
||||
@@ -139,7 +135,7 @@ void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer)
|
||||
|| texture_.format() != in_buffer->format()) {
|
||||
texture_.Create(context(), in_buffer->width(), in_buffer->height(), in_buffer->format(), in_buffer->data(), load_buffer_.linesize_pixels());
|
||||
} else {
|
||||
texture_.Upload(in_buffer->data(), load_buffer_.linesize_pixels());
|
||||
texture_.Upload(in_buffer);
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
@@ -148,18 +144,6 @@ void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer)
|
||||
update();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetEmitDrewManagedTextureEnabled(bool e)
|
||||
{
|
||||
enable_display_referred_signal_ = e;
|
||||
|
||||
if (!enable_display_referred_signal_) {
|
||||
// Destroy the texture now
|
||||
managed_texture_.Destroy();
|
||||
managed_copy_pipeline_ = nullptr;
|
||||
framebuffer_.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::ConnectSibling(ViewerDisplayWidget *sibling)
|
||||
{
|
||||
connect(this, &ViewerDisplayWidget::LoadedBuffer, sibling, &ViewerDisplayWidget::SetImageFromLoadBuffer, Qt::QueuedConnection);
|
||||
@@ -251,33 +235,6 @@ void ViewerDisplayWidget::paintGL()
|
||||
// We only draw if we have a pipeline
|
||||
if (has_image_ && color_service() && texture_.IsCreated()) {
|
||||
|
||||
// If we're distributing our display-referred final buffer, we'll have to make a copy of it
|
||||
if (enable_display_referred_signal_) {
|
||||
|
||||
if (!managed_texture_.IsCreated()
|
||||
|| managed_texture_.width() != texture_.width()
|
||||
|| managed_texture_.height() != texture_.height()
|
||||
|| managed_texture_.format() != texture_.format()) {
|
||||
managed_texture_.Destroy();
|
||||
|
||||
managed_texture_.Create(context(), texture_.width(), texture_.height(), texture_.format());
|
||||
}
|
||||
|
||||
if (!managed_copy_pipeline_) {
|
||||
managed_copy_pipeline_ = OpenGLShader::CreateDefault();
|
||||
}
|
||||
|
||||
if (!framebuffer_.IsCreated()) {
|
||||
framebuffer_.Create(context());
|
||||
}
|
||||
|
||||
framebuffer_.Attach(&managed_texture_);
|
||||
framebuffer_.Bind();
|
||||
|
||||
f->glViewport(0, 0, managed_texture_.width(), managed_texture_.height());
|
||||
|
||||
}
|
||||
|
||||
// Bind retrieved texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
|
||||
|
||||
@@ -287,24 +244,6 @@ void ViewerDisplayWidget::paintGL()
|
||||
// Release retrieved texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (enable_display_referred_signal_) {
|
||||
|
||||
framebuffer_.Release();
|
||||
framebuffer_.Detach();
|
||||
|
||||
emit DrewManagedTexture(&managed_texture_);
|
||||
|
||||
// Bind retrieved texture
|
||||
managed_texture_.Bind();
|
||||
|
||||
f->glViewport(0, 0, width(), height());
|
||||
|
||||
OpenGLRenderFunctions::Blit(managed_copy_pipeline_);
|
||||
|
||||
// Bind retrieved texture
|
||||
managed_texture_.Release();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Draw gizmos if we have any
|
||||
@@ -362,10 +301,7 @@ void ViewerDisplayWidget::ContextCleanup()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
managed_copy_pipeline_ = nullptr;
|
||||
texture_.Destroy();
|
||||
managed_texture_.Destroy();
|
||||
framebuffer_.Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
@@ -104,15 +104,6 @@ public slots:
|
||||
*/
|
||||
void SetImageFromLoadBuffer(Frame* in_buffer);
|
||||
|
||||
/**
|
||||
* @brief Enables or disables DrewManagedTexture()
|
||||
*
|
||||
* To emit a display referred texture, it needs to be copied after the color transform is complete. This naturally
|
||||
* adds extra GPU cycles that are wasted if there's nothing receiving the signal. Therefore, the signal is disabled
|
||||
* by default.
|
||||
*/
|
||||
void SetEmitDrewManagedTextureEnabled(bool e);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when the user starts dragging from the viewer
|
||||
@@ -133,18 +124,6 @@ signals:
|
||||
*/
|
||||
void LoadedBuffer(Frame* load_buffer);
|
||||
|
||||
/**
|
||||
* @brief Signal emitted when a buffer is loaded into a texture
|
||||
*
|
||||
* This texture will be the direct output of the renderer in reference space in GPU VRAM.
|
||||
*/
|
||||
void LoadedTexture(OpenGLTexture* texture);
|
||||
|
||||
/**
|
||||
* @brief Emitted when the a texture has been transformed to display
|
||||
*/
|
||||
void DrewManagedTexture(OpenGLTexture* texture);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Override the mouse press event simply to emit the DragStarted() signal
|
||||
@@ -176,23 +155,6 @@ private:
|
||||
*/
|
||||
OpenGLTexture texture_;
|
||||
|
||||
/**
|
||||
* @brief Internal framebuffer used to draw to managed_texture_
|
||||
*/
|
||||
OpenGLFramebuffer framebuffer_;
|
||||
|
||||
/**
|
||||
* @brief Internal referenceto the OpenGL texture that's been managed
|
||||
*
|
||||
* Kept so that scopes can use the display-referred buffer without having to transform again.
|
||||
*/
|
||||
OpenGLTexture managed_texture_;
|
||||
|
||||
/**
|
||||
* @brief Pipeline used to draw to managed_texture_
|
||||
*/
|
||||
OpenGLShaderPtr managed_copy_pipeline_;
|
||||
|
||||
/**
|
||||
* @brief Drawing matrix (defaults to identity)
|
||||
*/
|
||||
@@ -213,8 +175,6 @@ private:
|
||||
|
||||
ViewerSafeMarginInfo safe_margin_;
|
||||
|
||||
bool enable_display_referred_signal_;
|
||||
|
||||
Node* gizmos_;
|
||||
|
||||
private slots:
|
||||
|
||||
Reference in New Issue
Block a user