ui: optimized widget signals for selecting clips/nodes

Decent performance optimization when working with the UI.
This commit is contained in:
itsmattkc
2020-08-01 02:12:20 +10:00
parent fb05594b50
commit 2afa5a42c7
25 changed files with 491 additions and 351 deletions
+2 -61
View File
@@ -29,7 +29,8 @@ NodePanel::NodePanel(QWidget *parent) :
node_view_ = new NodeView(this);
// Connect node view signals to this panel
connect(node_view_, SIGNAL(SelectionChanged(QList<Node*>)), this, SIGNAL(SelectionChanged(QList<Node*>)));
connect(node_view_, &NodeView::NodesSelected, this, &NodePanel::NodesSelected);
connect(node_view_, &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected);
// Set it as the main widget of this panel
SetWidgetWithPadding(node_view_);
@@ -38,64 +39,4 @@ NodePanel::NodePanel(QWidget *parent) :
Retranslate();
}
void NodePanel::SetGraph(NodeGraph *graph)
{
node_view_->SetGraph(graph);
}
void NodePanel::SelectAll()
{
node_view_->SelectAll();
}
void NodePanel::DeselectAll()
{
node_view_->DeselectAll();
}
void NodePanel::DeleteSelected()
{
node_view_->DeleteSelected();
}
void NodePanel::CutSelected()
{
node_view_->CopySelected(true);
}
void NodePanel::CopySelected()
{
node_view_->CopySelected(false);
}
void NodePanel::Paste()
{
node_view_->Paste();
}
void NodePanel::Duplicate()
{
node_view_->Duplicate();
}
void NodePanel::Select(const QList<Node *> &nodes)
{
node_view_->Select(nodes);
}
void NodePanel::SelectWithDependencies(const QList<Node *> &nodes)
{
node_view_->SelectWithDependencies(nodes);
}
void NodePanel::SelectBlocks(const QList<Block *> &nodes)
{
node_view_->SelectBlocks(nodes);
}
void NodePanel::Retranslate()
{
SetTitle(tr("Node Editor"));
}
OLIVE_NAMESPACE_EXIT
+59 -16
View File
@@ -35,34 +35,77 @@ class NodePanel : public PanelWidget
public:
NodePanel(QWidget* parent);
void SetGraph(NodeGraph* graph);
void SetGraph(NodeGraph *graph)
{
node_view_->SetGraph(graph);
}
virtual void SelectAll() override;
virtual void DeselectAll() override;
virtual void SelectAll() override
{
node_view_->SelectAll();
}
virtual void DeleteSelected() override;
virtual void DeselectAll() override
{
node_view_->DeselectAll();
}
virtual void CutSelected() override;
virtual void CopySelected() override;
virtual void DeleteSelected() override
{
node_view_->DeleteSelected();
}
virtual void Paste() override;
virtual void CutSelected() override
{
node_view_->CopySelected(true);
}
virtual void Duplicate() override;
virtual void CopySelected() override
{
node_view_->CopySelected(false);
}
virtual void Paste() override
{
node_view_->Paste();
}
virtual void Duplicate() override
{
node_view_->Duplicate();
}
public slots:
void Select(const QList<Node*>& nodes);
void SelectWithDependencies(const QList<Node*>& nodes);
void Select(const QList<Node*>& nodes)
{
node_view_->Select(nodes);
}
void SelectBlocks(const QList<Block*>& nodes);
void SelectWithDependencies(const QList<Node*>& nodes)
{
node_view_->SelectWithDependencies(nodes);
}
void SelectBlocks(const QList<Block*>& nodes)
{
node_view_->SelectBlocks(nodes);
}
void DeselectBlocks(const QList<Block*>& nodes)
{
node_view_->DeselectBlocks(nodes);
}
signals:
/**
* @brief Wrapper for NodeView::SelectionChanged()
*/
void SelectionChanged(QList<Node*> selected_nodes);
void NodesSelected(const QList<Node*>& nodes);
void NodesDeselected(const QList<Node*>& nodes);
private:
virtual void Retranslate() override;
virtual void Retranslate() override
{
SetTitle(tr("Node Editor"));
}
NodeView* node_view_;
+13 -6
View File
@@ -30,15 +30,22 @@ ParamPanel::ParamPanel(QWidget* parent) :
NodeParamView* view = new NodeParamView();
connect(view, &NodeParamView::InputDoubleClicked, this, &ParamPanel::CreateCurvePanel);
connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode);
connect(view, &NodeParamView::FoundGizmos, this, &ParamPanel::FoundGizmos);
//connect(view, &NodeParamView::FoundGizmos, this, &ParamPanel::FoundGizmos);
SetTimeBasedWidget(view);
Retranslate();
}
void ParamPanel::SetNodes(QList<Node *> nodes)
void ParamPanel::SelectNodes(const QList<Node *> &nodes)
{
static_cast<NodeParamView*>(GetTimeBasedWidget())->SetNodes(nodes);
static_cast<NodeParamView*>(GetTimeBasedWidget())->SelectNodes(nodes);
Retranslate();
}
void ParamPanel::DeselectNodes(const QList<Node *> &nodes)
{
static_cast<NodeParamView*>(GetTimeBasedWidget())->DeselectNodes(nodes);
Retranslate();
}
@@ -62,10 +69,10 @@ void ParamPanel::Retranslate()
NodeParamView* view = static_cast<NodeParamView*>(GetTimeBasedWidget());
if (view->nodes().isEmpty()) {
if (view->GetItemMap().isEmpty()) {
SetSubtitle(tr("(none)"));
} else if (view->nodes().size() == 1) {
SetSubtitle(view->nodes().first()->Name());
} else if (view->GetItemMap().size() == 1) {
SetSubtitle(view->GetItemMap().firstKey()->Name());
} else {
SetSubtitle(tr("(multiple)"));
}
+2 -1
View File
@@ -34,7 +34,8 @@ public:
ParamPanel(QWidget* parent);
public slots:
void SetNodes(QList<Node*> nodes);
void SelectNodes(const QList<Node*>& nodes);
void DeselectNodes(const QList<Node*>& nodes);
virtual void SetTimestamp(const int64_t& timestamp) override;
+1 -7
View File
@@ -25,17 +25,11 @@ OLIVE_NAMESPACE_ENTER
NodeTablePanel::NodeTablePanel(QWidget* parent) :
TimeBasedPanel(QStringLiteral("NodeTablePanel"), parent)
{
view_ = new NodeTableWidget();
SetTimeBasedWidget(view_);
SetTimeBasedWidget(new NodeTableWidget());
Retranslate();
}
void NodeTablePanel::SetNodes(const QList<Node *> &nodes)
{
view_->SetNodes(nodes);
}
void NodeTablePanel::Retranslate()
{
SetTitle(tr("Table View"));
+9 -2
View File
@@ -33,12 +33,19 @@ public:
NodeTablePanel(QWidget* parent);
public slots:
void SetNodes(const QList<Node*>& nodes);
void SelectNodes(const QList<Node*>& nodes)
{
static_cast<NodeTableWidget*>(GetTimeBasedWidget())->SelectNodes(nodes);
}
void DeselectNodes(const QList<Node*>& nodes)
{
static_cast<NodeTableWidget*>(GetTimeBasedWidget())->DeselectNodes(nodes);
}
private:
virtual void Retranslate() override;
NodeTableWidget* view_;
};
OLIVE_NAMESPACE_EXIT
+2 -1
View File
@@ -33,7 +33,8 @@ TimelinePanel::TimelinePanel(QWidget *parent) :
Retranslate();
connect(tw, &TimelineWidget::SelectionChanged, this, &TimelinePanel::SelectionChanged);
connect(tw, &TimelineWidget::BlocksSelected, this, &TimelinePanel::BlocksSelected);
connect(tw, &TimelineWidget::BlocksDeselected, this, &TimelinePanel::BlocksDeselected);
}
void TimelinePanel::Clear()
+3 -1
View File
@@ -91,7 +91,9 @@ protected:
virtual void Retranslate() override;
signals:
void SelectionChanged(const QList<Block*>& selected_blocks);
void BlocksSelected(const QList<Block*>& selected_blocks);
void BlocksDeselected(const QList<Block*>& deselected_blocks);
};
@@ -74,6 +74,19 @@ void KeyframeViewBase::DeleteSelected()
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void KeyframeViewBase::RemoveKeyframesOfNode(Node *n)
{
QList<NodeInput*> inputs = n->GetInputsIncludingArrays();
foreach (NodeInput* i, inputs) {
foreach (const NodeInput::KeyframeTrack& track, i->keyframe_tracks()) {
foreach (NodeKeyframePtr key, track) {
RemoveKeyframe(key);
}
}
}
}
void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key)
{
KeyframeAboutToBeRemoved(key.get());
@@ -40,6 +40,8 @@ public:
void DeleteSelected();
void RemoveKeyframesOfNode(Node* n);
public slots:
void RemoveKeyframe(NodeKeyframePtr key);
+28 -44
View File
@@ -122,52 +122,41 @@ NodeParamView::NodeParamView(QWidget *parent) :
SetMaximumScale(TimelineViewBase::kMaximumScale);
}
void NodeParamView::SetNodes(QList<Node *> nodes)
void NodeParamView::SelectNodes(const QList<Node *> &nodes)
{
// If we already have item widgets, delete them all now
foreach (NodeParamViewItem* item, items_) {
emit ClosedNode(item->GetNode());
emit FoundGizmos(nullptr);
item->deleteLater();
foreach (Node* n, nodes) {
NodeParamViewItem* item = new NodeParamViewItem(n);
// Insert the widget before the stretch
param_layout_->insertWidget(param_layout_->count() - 1, item);
connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged);
connect(item, &NodeParamViewItem::InputDoubleClicked, this, &NodeParamView::InputDoubleClicked);
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
items_.insert(n, item);
}
items_.clear();
// Reset keyframe view
keyframe_view_->Clear();
UpdateItemTime(GetTimestamp());
// Set the internal list to the one we've received
nodes_ = nodes;
// Re-arrange keyframes
QMetaObject::invokeMethod(this, "PlaceKeyframesOnView", Qt::QueuedConnection);
}
if (!nodes_.isEmpty()) {
// For each node, create a widget
bool found_gizmos = false;
void NodeParamView::DeselectNodes(const QList<Node *> &nodes)
{
// Remove item from map and delete the widget
foreach (Node* n, nodes) {
// Remove all keyframes from this node
keyframe_view_->RemoveKeyframesOfNode(n);
foreach (Node* node, nodes_) {
NodeParamViewItem* item = new NodeParamViewItem(node);
// Insert the widget before the stretch
param_layout_->insertWidget(param_layout_->count() - 1, item);
connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged);
connect(item, &NodeParamViewItem::InputDoubleClicked, this, &NodeParamView::InputDoubleClicked);
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
items_.append(item);
emit OpenedNode(node);
if (!found_gizmos && node->HasGizmos()) {
emit FoundGizmos(node);
found_gizmos = true;
}
}
UpdateItemTime(GetTimestamp());
QMetaObject::invokeMethod(this, "PlaceKeyframesOnView", Qt::QueuedConnection);
delete items_.take(n);
}
// Re-arrange keyframes
QMetaObject::invokeMethod(this, "PlaceKeyframesOnView", Qt::QueuedConnection);
}
void NodeParamView::resizeEvent(QResizeEvent *event)
@@ -212,11 +201,6 @@ void NodeParamView::ConnectedNodeChanged(ViewerOutput *n)
}
}
const QList<Node *> &NodeParamView::nodes()
{
return nodes_;
}
Node *NodeParamView::GetTimeTarget() const
{
return keyframe_view_->GetTimeTarget();
+8 -11
View File
@@ -37,8 +37,13 @@ class NodeParamView : public TimeBasedWidget
public:
NodeParamView(QWidget* parent = nullptr);
void SetNodes(QList<Node*> nodes);
const QList<Node*>& nodes();
void SelectNodes(const QList<Node*>& nodes);
void DeselectNodes(const QList<Node*>& nodes);
const QMap<Node*, NodeParamViewItem*>& GetItemMap() const
{
return items_;
}
Node* GetTimeTarget() const;
@@ -49,12 +54,6 @@ signals:
void RequestSelectNode(const QList<Node*>& target);
void OpenedNode(Node* n);
void ClosedNode(Node* n);
void FoundGizmos(Node* n);
protected:
virtual void resizeEvent(QResizeEvent *event) override;
@@ -71,9 +70,7 @@ private:
KeyframeView* keyframe_view_;
QList<Node*> nodes_;
QList<NodeParamViewItem*> items_;
QMap<Node*, NodeParamViewItem*> items_;
QScrollBar* vertical_scrollbar_;
+129 -18
View File
@@ -29,8 +29,7 @@
OLIVE_NAMESPACE_ENTER
NodeTableView::NodeTableView(QWidget* parent) :
QTreeWidget(parent),
last_set_node_(nullptr)
QTreeWidget(parent)
{
setColumnCount(3);
setHeaderLabels({tr("Type"),
@@ -41,14 +40,135 @@ NodeTableView::NodeTableView(QWidget* parent) :
tr("A/W")});
}
void NodeTableView::SelectNodes(const QList<Node *> &nodes)
{
foreach (Node* n, nodes) {
QTreeWidgetItem* top_item = new QTreeWidgetItem();
top_item->setText(0, n->Name());
top_item->setFirstColumnSpanned(true);
this->addTopLevelItem(top_item);
top_level_item_map_.insert(n, top_item);
}
SetTime(last_time_);
}
void NodeTableView::DeselectNodes(const QList<Node *> &nodes)
{
foreach (Node* n, nodes) {
delete top_level_item_map_.take(n);
}
}
void NodeTableView::SetTime(const rational &time)
{
last_time_ = time;
NodeTableTraverser traverser;
QMap<Node*, QTreeWidgetItem*>::const_iterator i;
for (i=top_level_item_map_.constBegin(); i!=top_level_item_map_.constEnd(); i++) {
Node* node = i.key();
QTreeWidgetItem* item = i.value();
// Generate a value database for this node at this time
NodeValueDatabase db = traverser.GenerateDatabase(node, TimeRange(time, time));
// Delete any children of this item that aren't in this database
for (int j=0; j<item->childCount(); j++) {
if (!db.contains(item->child(j)->data(0, Qt::UserRole).toString())) {
delete item->takeChild(j);
j--;
}
}
// Update all inputs
NodeValueDatabase::const_iterator l;
for (l=db.begin(); l!=db.end(); l++) {
const NodeValueTable& table = l.value();
NodeInput* input = node->GetInputWithID(l.key());
if (!input) {
// Filters out table entries that aren't inputs (like "global")
continue;
}
QTreeWidgetItem* input_item = nullptr;
for (int j=0; j<item->childCount(); j++) {
QTreeWidgetItem* compare = item->child(j);
if (compare->data(0, Qt::UserRole).toString() == input->id()) {
input_item = compare;
break;
}
}
if (!input_item) {
input_item = new QTreeWidgetItem();
input_item->setText(0, input->name());
input_item->setData(0, Qt::UserRole, input->id());
input_item->setFirstColumnSpanned(true);
item->addChild(input_item);
}
// Create children if necessary
while (input_item->childCount() < table.Count()) {
input_item->addChild(new QTreeWidgetItem());
}
// Remove children if necessary
while (input_item->childCount() > table.Count()) {
delete input_item->takeChild(input_item->childCount() - 1);
}
for (int j=0;j<table.Count();j++) {
const NodeValue& value = table.at(table.Count() - 1 - j);
// Create item
QTreeWidgetItem* sub_item = input_item->child(j);
// Set data type name
sub_item->setText(0, NodeParam::GetPrettyDataTypeName(value.type()));
// Determine source
QString source_name;
if (value.source()) {
source_name = value.source()->Name();
} else {
source_name = tr("(unknown)");
}
sub_item->setText(1, source_name);
switch (value.type()) {
case NodeParam::kTexture:
{
// NodeTableTraverser puts video params in here
VideoParams p = value.data().value<VideoParams>();
int channel_count = PixelFormat::ChannelCount(p.format());
for (int k=0;k<channel_count;k++) {
this->setItemWidget(sub_item, 2 + k, new QCheckBox());
}
break;
}
default:
{
QVector<QVariant> split_values = input->split_normal_value_into_track_values(value.data());
for (int k=0;k<split_values.size();k++) {
sub_item->setText(2 + k, NodeInput::ValueToString(value.type(), split_values.at(k)));
}
}
}
}
}
}
}
/*
void NodeTableView::SetNode(Node *n, const rational &time)
{
if (last_set_node_ != n) {
// Clear everything if the node has changed
clear();
}
last_set_node_ = n;
NodeTableTraverser traverser;
NodeValueDatabase db = traverser.GenerateDatabase(n, TimeRange(time, time));
@@ -141,15 +261,6 @@ void NodeTableView::SetNode(Node *n, const rational &time)
}
}
}
void NodeTableView::SetMultipleNodeMessage()
{
this->clear();
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, tr("Multiple nodes selected"));
item->setFirstColumnSpanned(true);
this->addTopLevelItem(item);
}
*/
OLIVE_NAMESPACE_EXIT
+7 -3
View File
@@ -32,12 +32,16 @@ class NodeTableView : public QTreeWidget
public:
NodeTableView(QWidget* parent = nullptr);
void SetNode(Node* n, const rational& time);
void SelectNodes(const QList<Node*>& nodes);
void SetMultipleNodeMessage();
void DeselectNodes(const QList<Node*>& nodes);
void SetTime(const rational& time);
private:
Node* last_set_node_;
QMap<Node*, QTreeWidgetItem*> top_level_item_map_;
rational last_time_;
};
+1 -35
View File
@@ -25,8 +25,7 @@
OLIVE_NAMESPACE_ENTER
NodeTableWidget::NodeTableWidget(QWidget* parent) :
TimeBasedWidget(parent),
node_(nullptr)
TimeBasedWidget(parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setSpacing(0);
@@ -36,37 +35,4 @@ NodeTableWidget::NodeTableWidget(QWidget* parent) :
layout->addWidget(view_);
}
void NodeTableWidget::SetNodes(const QList<Node *> &nodes)
{
node_ = nullptr;
if (nodes.isEmpty()) {
view_->clear();
} else if (nodes.size() == 1) {
node_ = nodes.first();
ViewerOutput* viewer = node_->FindOutputNode<ViewerOutput>();
if (viewer) {
qDebug() << "Found timebase";
SetTimebase(viewer->video_params().time_base());
}
UpdateView();
} else {
view_->SetMultipleNodeMessage();
}
}
void NodeTableWidget::TimeChangedEvent(const int64_t &)
{
UpdateView();
}
void NodeTableWidget::UpdateView()
{
if (node_) {
view_->SetNode(node_, GetTime());
}
}
OLIVE_NAMESPACE_EXIT
+17 -5
View File
@@ -31,18 +31,30 @@ class NodeTableWidget : public TimeBasedWidget
public:
NodeTableWidget(QWidget* parent = nullptr);
void SetNodes(const QList<Node*>& nodes);
void SelectNodes(const QList<Node*>& nodes)
{
view_->SelectNodes(nodes);
}
void DeselectNodes(const QList<Node*>& nodes)
{
view_->DeselectNodes(nodes);
}
protected:
virtual void TimeChangedEvent(const int64_t& ts) override;
virtual void TimeChangedEvent(const int64_t& ts) override
{
UpdateView();
}
private:
void UpdateView();
void UpdateView()
{
view_->SetTime(GetTime());
}
NodeTableView* view_;
Node* node_;
};
OLIVE_NAMESPACE_EXIT
+84 -39
View File
@@ -144,7 +144,8 @@ void NodeView::SelectAll()
scene_.SelectAll();
ReconnectSelectionChangedSignal();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::DeselectAll()
@@ -155,7 +156,8 @@ void NodeView::DeselectAll()
scene_.DeselectAll();
ReconnectSelectionChangedSignal();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::Select(const QList<Node *> &nodes)
@@ -176,7 +178,8 @@ void NodeView::Select(const QList<Node *> &nodes)
item->setSelected(true);
}
ReconnectSelectionChangedSignal();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::SelectWithDependencies(QList<Node *> nodes)
@@ -195,10 +198,13 @@ void NodeView::SelectWithDependencies(QList<Node *> nodes)
void NodeView::SelectBlocks(const QList<Block *> &blocks)
{
if (selected_blocks_ == blocks) {
return;
}
selected_blocks_.append(blocks);
SelectBlocksInternal();
}
void NodeView::DeselectBlocks(const QList<Block *> &blocks)
{
// Remove temporary associations
foreach (Block* b, selected_blocks_) {
if (!blocks.contains(b)) {
@@ -206,35 +212,12 @@ void NodeView::SelectBlocks(const QList<Block *> &blocks)
}
}
selected_blocks_ = blocks;
// Block scene signals while our selection is changing a lot
scene_.blockSignals(true);
if (filter_mode_ == kFilterShowSelectedBlocks) {
UpdateBlockFilter();
}
QList<Node*> nodes;
nodes.reserve(blocks.size());
// Remove blocks from selected array
foreach (Block* b, blocks) {
nodes.append(b);
nodes.append(b->GetDependencies());
selected_blocks_.removeOne(b);
}
SelectWithDependencies(nodes);
// Stop blocking signals and send a change signal now that all of our processing is done
scene_.blockSignals(false);
SceneSelectionChangedSlot();
if (!blocks.isEmpty()) {
NodeViewItem* item = scene_.NodeToUIObject(blocks.first());
if (item) {
centerOn(item);
}
}
SelectBlocksInternal();
}
void NodeView::CopySelected(bool cut)
@@ -478,7 +461,44 @@ void NodeView::wheelEvent(QWheelEvent *event)
void NodeView::SceneSelectionChangedSlot()
{
emit SelectionChanged(scene_.GetSelectedNodes());
QList<Node*> current_selection = scene_.GetSelectedNodes();
QList<Node*> selected;
QList<Node*> deselected;
// Determine which nodes are newly selected
if (selected_nodes_.isEmpty()) {
// All nodes in the current selection have just been selected
selected = current_selection;
} else {
foreach (Node* n, current_selection) {
if (!selected_nodes_.contains(n)) {
selected.append(n);
}
}
}
// Determine which nodes are newly deselected
if (current_selection.isEmpty()) {
// All nodes that were selected have been deselected
deselected = selected_nodes_;
} else {
foreach (Node* n, selected_nodes_) {
if (!current_selection.contains(n)) {
deselected.append(n);
}
}
}
selected_nodes_ = current_selection;
if (!selected.isEmpty()) {
emit NodesSelected(selected);
}
if (!deselected.isEmpty()) {
emit NodesDeselected(deselected);
}
}
void NodeView::ShowContextMenu(const QPoint &pos)
@@ -803,12 +823,6 @@ void NodeView::ConnectSelectionChangedSignal()
connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
}
void NodeView::ReconnectSelectionChangedSignal()
{
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::DisconnectSelectionChangedSignal()
{
disconnect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
@@ -913,6 +927,37 @@ void NodeView::DisassociateNode(Node *n, bool remove_from_map)
disconnect(n, &Node::destroyed, this, &NodeView::AssociatedNodeDestroyed);
}
void NodeView::SelectBlocksInternal()
{
// Block scene signals while our selection is changing a lot
scene_.blockSignals(true);
if (filter_mode_ == kFilterShowSelectedBlocks) {
UpdateBlockFilter();
}
QList<Node*> nodes;
nodes.reserve(selected_blocks_.size());
foreach (Block* b, selected_blocks_) {
nodes.append(b);
nodes.append(b->GetDependencies());
}
SelectWithDependencies(nodes);
// Stop blocking signals and send a change signal now that all of our processing is done
scene_.blockSignals(false);
SceneSelectionChangedSlot();
if (!selected_blocks_.isEmpty()) {
NodeViewItem* item = scene_.NodeToUIObject(selected_blocks_.first());
if (item) {
centerOn(item);
}
}
}
void NodeView::ValidateFilter()
{
// Force auto-positioning
+13 -7
View File
@@ -61,18 +61,19 @@ public:
void Select(const QList<Node*>& nodes);
void SelectWithDependencies(QList<Node *> nodes);
void SelectBlocks(const QList<Block*>& blocks);
void CopySelected(bool cut);
void Paste();
void Duplicate();
void SelectBlocks(const QList<Block*>& blocks);
void DeselectBlocks(const QList<Block*>& blocks);
signals:
/**
* @brief Signal emitted when the selected nodes have changed
*/
void SelectionChanged(QList<Node*> selected_nodes);
void NodesSelected(const QList<Node*>& nodes);
void NodesDeselected(const QList<Node*>& nodes);
protected:
virtual void keyPressEvent(QKeyEvent *event) override;
@@ -83,6 +84,8 @@ protected:
virtual void wheelEvent(QWheelEvent* event) override;
//virtual void scrollContentsBy(int dx, int dy) override;
private:
void PlaceNode(NodeViewItem* n, const QPointF& pos);
@@ -97,7 +100,6 @@ private:
void MoveAttachedNodesToCursor(const QPoint &p);
void ConnectSelectionChangedSignal();
void ReconnectSelectionChangedSignal();
void DisconnectSelectionChangedSignal();
void UpdateBlockFilter();
@@ -105,6 +107,8 @@ private:
void AssociateNodeWithSelectedBlocks(Node* n);
void DisassociateNode(Node* n, bool remove_from_map);
void SelectBlocksInternal();
NodeGraph* graph_;
struct AttachedItem {
@@ -119,6 +123,8 @@ private:
NodeViewScene scene_;
QList<Node*> selected_nodes_;
QList<Block*> selected_blocks_;
QHash<Node*, QList<Block*> > association_map_;
+67 -55
View File
@@ -129,7 +129,6 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
connect(view, &TimelineView::DragMoved, this, &TimelineWidget::ViewDragMoved);
connect(view, &TimelineView::DragLeft, this, &TimelineWidget::ViewDragLeft);
connect(view, &TimelineView::DragDropped, this, &TimelineWidget::ViewDragDropped);
ConnectViewSelectionSignal(view);
connect(tview->splitter(), &QSplitter::splitterMoved, this, &TimelineWidget::UpdateHorizontalSplitters);
@@ -163,21 +162,19 @@ TimelineWidget::~TimelineWidget()
void TimelineWidget::Clear()
{
foreach (TimelineAndTrackView* tview, views_) {
DisconnectViewSelectionSignal(tview->view());
}
QList<Block*> deselected_blocks;
QMap<Block*, TimelineViewBlockItem*>::const_iterator iterator;
for (iterator=block_items_.begin(); iterator!=block_items_.end(); iterator++) {
if (iterator.value()->isSelected()) {
deselected_blocks.append(iterator.key());
}
delete iterator.value();
}
block_items_.clear();
foreach (TimelineAndTrackView* tview, views_) {
ConnectViewSelectionSignal(tview->view());
}
emit SelectionChanged(QList<Block*>());
emit BlocksDeselected(deselected_blocks);
SetTimebase(0);
}
@@ -379,24 +376,34 @@ rational TimelineWidget::GetToolTipTimebase() const
void TimelineWidget::SelectAll()
{
foreach (TimelineAndTrackView* view, views_) {
DisconnectViewSelectionSignal(view->view());
view->view()->SelectAll();
ConnectViewSelectionSignal(view->view());
QList<Block*> blocks_selected;
QMap<Block*, TimelineViewBlockItem*>::const_iterator i;
for (i=block_items_.constBegin(); i!=block_items_.end(); i++) {
if (!i.value()->isSelected()) {
i.value()->setSelected(true);
blocks_selected.append(i.key());
}
}
ViewSelectionChanged();
emit BlocksSelected(blocks_selected);
}
void TimelineWidget::DeselectAll()
{
foreach (TimelineAndTrackView* view, views_) {
DisconnectViewSelectionSignal(view->view());
view->view()->DeselectAll();
ConnectViewSelectionSignal(view->view());
QList<Block*> blocks_deselected;
QMap<Block*, TimelineViewBlockItem*>::const_iterator i;
for (i=block_items_.constBegin(); i!=block_items_.end(); i++) {
if (i.value()->isSelected()) {
i.value()->setSelected(false);
blocks_deselected.append(i.key());
}
}
emit SelectionChanged(QList<Block*>());
emit BlocksDeselected(blocks_deselected);
}
void TimelineWidget::RippleToIn()
@@ -803,16 +810,6 @@ TrackOutput *TimelineWidget::GetTrackFromReference(const TrackReference &ref)
return GetConnectedNode()->track_list(ref.type())->GetTrackAt(ref.index());
}
void TimelineWidget::ConnectViewSelectionSignal(TimelineView *view)
{
connect(view, &TimelineView::SelectionChanged, this, &TimelineWidget::ViewSelectionChanged);
}
void TimelineWidget::DisconnectViewSelectionSignal(TimelineView *view)
{
disconnect(view, &TimelineView::SelectionChanged, this, &TimelineWidget::ViewSelectionChanged);
}
int TimelineWidget::GetTrackY(const TrackReference &ref)
{
return views_.at(ref.type())->view()->GetTrackY(ref.index());
@@ -983,22 +980,6 @@ void TimelineWidget::TrackIndexChanged()
}
}
void TimelineWidget::ViewSelectionChanged()
{
if (rubberband_.isVisible()) {
return;
}
QList<TimelineViewBlockItem*> selected_items = GetSelectedBlocks();
QList<Block*> selected_blocks;
foreach (TimelineViewBlockItem* item, selected_items) {
selected_blocks.append(item->block());
}
emit SelectionChanged(selected_blocks);
}
void TimelineWidget::BlockRefreshed()
{
TimelineViewRect* rect = block_items_.value(static_cast<Block*>(sender()));
@@ -1393,6 +1374,14 @@ void TimelineWidget::StartRubberBandSelect(bool enable_selecting, bool select_li
drag_origin_ = QCursor::pos();
rubberband_.show();
// We don't touch any blocks that are already selected. If you want these to be deselected by
// default, call DeselectAll() befoer calling StartRubberBandSelect()
foreach (TimelineViewBlockItem* block, block_items_) {
if (block->isSelected()) {
rubberband_already_selected_.append(block);
}
}
MoveRubberBandSelect(enable_selecting, select_links);
}
@@ -1408,10 +1397,11 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
QList<QGraphicsItem*> new_selected_list;
// Determine all items in the rubberband
foreach (TimelineAndTrackView* tview, views_) {
// Map global mouse coordinates to viewport
TimelineView* view = tview->view();
// Map global mouse coordinates to viewport
QRect mapped_rect(view->viewport()->mapFromGlobal(drag_origin_),
view->viewport()->mapFromGlobal(rubberband_now));
@@ -1421,13 +1411,25 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
new_selected_list.append(rubberband_items);
}
// Filter out any items that were already selected
if (!rubberband_already_selected_.isEmpty()) {
for (int i=0; i<new_selected_list.size(); i++) {
if (rubberband_already_selected_.contains(new_selected_list.at(i))) {
new_selected_list.removeAt(i);
i--;
}
}
}
foreach (QGraphicsItem* item, rubberband_now_selected_) {
item->setSelected(false);
}
foreach (QGraphicsItem* item, new_selected_list) {
TimelineViewBlockItem* block_item = dynamic_cast<TimelineViewBlockItem*>(item);
if (!block_item || block_item->block()->type() == Block::kGap) {
// Cache limit because we append to this array in this loop and don't need to process those
int lim = new_selected_list.size();
for (int i=0;i<lim;i++) {
TimelineViewBlockItem* block_item = static_cast<TimelineViewBlockItem*>(new_selected_list.at(i));
if (block_item->block()->type() == Block::kGap) {
continue;
}
@@ -1436,18 +1438,22 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
continue;
}
// Since new_selected_list is filtered by rubberband_already_selected_, this should certainly
// be deselected by now
block_item->setSelected(true);
if (select_links) {
// Select the block's links
Block* b = block_item->block();
SetBlockLinksSelected(b, true);
// Add its links to the list
TimelineViewBlockItem* link_item;
foreach (Block* link, b->linked_clips()) {
if ((link_item = block_items_[link]) != nullptr) {
if (!new_selected_list.contains(link_item)) {
link_item->setSelected(true);
if (!new_selected_list.contains(link_item)
&& !rubberband_already_selected_.contains(link_item)) {
new_selected_list.append(link_item);
}
}
@@ -1458,13 +1464,19 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
rubberband_now_selected_ = new_selected_list;
}
void TimelineWidget::EndRubberBandSelect(bool enable_selecting, bool select_links)
void TimelineWidget::EndRubberBandSelect()
{
MoveRubberBandSelect(enable_selecting, select_links);
rubberband_.hide();
rubberband_now_selected_.clear();
ViewSelectionChanged();
// Emit any blocks that were newly selected
QList<Block*> selected_blocks;
foreach (QGraphicsItem* item, rubberband_now_selected_) {
selected_blocks.append(static_cast<TimelineViewBlockItem*>(item)->block());
}
emit BlocksSelected(selected_blocks);
rubberband_now_selected_.clear();
rubberband_already_selected_.clear();
}
struct SnapData {
+5 -8
View File
@@ -104,7 +104,9 @@ public:
void RestoreSplitterState(const QByteArray& state);
signals:
void SelectionChanged(const QList<Block*>& selected_blocks);
void BlocksSelected(const QList<Block*>& selected_blocks);
void BlocksDeselected(const QList<Block*>& deselected_blocks);
protected:
virtual void resizeEvent(QResizeEvent *event) override;
@@ -474,8 +476,9 @@ private:
void StartRubberBandSelect(bool enable_selecting, bool select_links);
void MoveRubberBandSelect(bool enable_selecting, bool select_links);
void EndRubberBandSelect(bool enable_selecting, bool select_links);
void EndRubberBandSelect();
QRubberBand rubberband_;
QList<QGraphicsItem*> rubberband_already_selected_;
QList<QGraphicsItem*> rubberband_now_selected_;
Tool* GetActiveTool();
@@ -496,10 +499,6 @@ private:
TrackOutput* GetTrackFromReference(const TrackReference& ref);
void ConnectViewSelectionSignal(TimelineView* view);
void DisconnectViewSelectionSignal(TimelineView* view);
QList<TimelineAndTrackView*> views_;
TimeSlider* timecode_label_;
@@ -539,8 +538,6 @@ private slots:
void RemoveTrack(TrackOutput* track);
void TrackIndexChanged();
void ViewSelectionChanged();
/**
* @brief Slot for when a Block node changes its parameters and the graphics need to update
*
+19 -1
View File
@@ -78,16 +78,23 @@ void TimelineWidget::PointerTool::MousePress(TimelineViewMouseEvent *event)
// If this item is already selected, no further selection needs to be made
if (clicked_item_->isSelected()) {
// Collect item deselections
QList<Block*> deselected_blocks;
// If shift is held, deselect it
if (event->GetModifiers() & Qt::ShiftModifier) {
clicked_item_->setSelected(false);
deselected_blocks.append(clicked_item_->block());
// If not holding alt, deselect all links as well
if (!(event->GetModifiers() & Qt::AltModifier)) {
parent()->SetBlockLinksSelected(clicked_item_->block(), false);
deselected_blocks.append(clicked_item_->block()->linked_clips().toList());
}
}
emit parent()->BlocksDeselected(deselected_blocks);
return;
}
}
@@ -98,18 +105,29 @@ void TimelineWidget::PointerTool::MousePress(TimelineViewMouseEvent *event)
}
if (selectable_item) {
// Collect item selections
QList<Block*> selected_blocks;
// Select this item
clicked_item_->setSelected(true);
selected_blocks.append(clicked_item_->block());
// If not holding alt, select all links as well
if (!(event->GetModifiers() & Qt::AltModifier)) {
parent()->SetBlockLinksSelected(clicked_item_->block(), true);
selected_blocks.append(clicked_item_->block()->linked_clips().toList());
}
emit parent()->BlocksSelected(selected_blocks);
} else if (event->GetButton() == Qt::LeftButton) {
// Start rubberband drag
parent()->StartRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier));
rubberband_selecting_ = true;
}
}
@@ -150,7 +168,7 @@ void TimelineWidget::PointerTool::MouseRelease(TimelineViewMouseEvent *event)
{
if (rubberband_selecting_) {
// Finish rubberband select
parent()->EndRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier));
parent()->EndRubberBandSelect();
rubberband_selecting_ = false;
return;
}
+1 -1
View File
@@ -51,7 +51,7 @@ void TimelineWidget::ZoomTool::MouseRelease(TimelineViewMouseEvent *event)
// Zoom into the rubberband selection
QRect screen_coords = parent()->rubberband_.geometry();
parent()->EndRubberBandSelect(false, false);
parent()->EndRubberBandSelect();
TimelineView* reference_view = parent()->views_.first()->view();
QPointF scene_topleft = reference_view->mapToScene(reference_view->mapFrom(parent(), screen_coords.topLeft()));
@@ -47,26 +47,6 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) :
setBackgroundRole(QPalette::Window);
setContextMenuPolicy(Qt::CustomContextMenu);
viewport()->setMouseTracking(true);
connect(scene(), &QGraphicsScene::selectionChanged, this, &TimelineView::SelectionChanged);
}
void TimelineView::SelectAll()
{
QList<QGraphicsItem*> all_items = items();
foreach (QGraphicsItem* i, all_items) {
i->setSelected(true);
}
}
void TimelineView::DeselectAll()
{
QList<QGraphicsItem*> all_items = items();
foreach (QGraphicsItem* i, all_items) {
i->setSelected(false);
}
}
void TimelineView::mousePressEvent(QMouseEvent *event)
@@ -49,10 +49,6 @@ public:
TimelineView(Qt::Alignment vertical_alignment = Qt::AlignTop,
QWidget* parent = nullptr);
void SelectAll();
void DeselectAll();
int GetTrackY(int track_index) const;
int GetTrackHeight(int track_index) const;
@@ -74,8 +70,6 @@ signals:
void DragLeft(QDragLeaveEvent* event);
void DragDropped(TimelineViewMouseEvent* event);
void SelectionChanged();
protected:
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
+6 -3
View File
@@ -82,8 +82,10 @@ MainWindow::MainWindow(QWidget *parent) :
audio_monitor_panel_ = PanelManager::instance()->CreatePanel<AudioMonitorPanel>(this);
// Make connections to sequence viewer
connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes);
connect(node_panel_, &NodePanel::SelectionChanged, table_panel_, &NodeTablePanel::SetNodes);
connect(node_panel_, &NodePanel::NodesSelected, param_panel_, &ParamPanel::SelectNodes);
connect(node_panel_, &NodePanel::NodesDeselected, param_panel_, &ParamPanel::DeselectNodes);
connect(node_panel_, &NodePanel::NodesSelected, table_panel_, &NodeTablePanel::SelectNodes);
connect(node_panel_, &NodePanel::NodesDeselected, table_panel_, &NodeTablePanel::DeselectNodes);
connect(param_panel_, &ParamPanel::RequestSelectNode, node_panel_, &NodePanel::Select);
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp);
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp);
@@ -480,7 +482,8 @@ TimelinePanel* MainWindow::AppendTimelinePanel()
connect(panel, &TimelinePanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp);
connect(panel, &TimelinePanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp);
connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp);
connect(panel, &TimelinePanel::SelectionChanged, node_panel_, &NodePanel::SelectBlocks);
connect(panel, &TimelinePanel::BlocksSelected, node_panel_, &NodePanel::SelectBlocks);
connect(panel, &TimelinePanel::BlocksDeselected, node_panel_, &NodePanel::DeselectBlocks);
connect(param_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp);
connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp);