Merge branch 'master' into pr/1875
This commit is contained in:
@@ -233,7 +233,7 @@ ColorValuesTab::ColorValuesTab(bool with_legacy_option, QWidget *parent) :
|
||||
|
||||
if (with_legacy_option) {
|
||||
legacy_box_ = new QCheckBox(tr("Use legacy (8-bit) values"));
|
||||
legacy_box_->setChecked(Config::Current()[QStringLiteral("UseLegacyColorInInputTab")].toBool());
|
||||
legacy_box_->setChecked(OLIVE_CONFIG("UseLegacyColorInInputTab").toBool());
|
||||
connect(legacy_box_, &QCheckBox::clicked, this, &ColorValuesTab::LegacyChanged);
|
||||
layout->addWidget(legacy_box_, row, 0, 1, 2);
|
||||
row++;
|
||||
@@ -356,7 +356,7 @@ void ColorValuesTab::SliderChanged()
|
||||
|
||||
void ColorValuesTab::LegacyChanged(bool legacy)
|
||||
{
|
||||
Config::Current()[QStringLiteral("UseLegacyColorInInputTab")] = legacy;
|
||||
OLIVE_CONFIG("UseLegacyColorInInputTab") = legacy;
|
||||
|
||||
double legacy_multiplier = legacy ? kLegacyMultiplier : 1.0/kLegacyMultiplier;
|
||||
int decimal_places = legacy ? 0 : 5;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace olive {
|
||||
HandMovableView::HandMovableView(QWidget* parent) :
|
||||
super(parent),
|
||||
dragging_hand_(false),
|
||||
scroll_zooms_by_default_(Config::Current()[QStringLiteral("ScrollZooms")].toBool())
|
||||
scroll_zooms_by_default_(OLIVE_CONFIG("ScrollZooms").toBool())
|
||||
{
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged);
|
||||
}
|
||||
|
||||
@@ -155,10 +155,11 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) :
|
||||
SetScale(120);
|
||||
|
||||
// Pickup on widget focus changes
|
||||
connect(qApp,
|
||||
// DISABLED - we now just handle this with item/titlebar clicking (see ToggleSelect)
|
||||
/*connect(qApp,
|
||||
&QApplication::focusChanged,
|
||||
this,
|
||||
&NodeParamView::FocusChanged);
|
||||
&NodeParamView::FocusChanged);*/
|
||||
}
|
||||
|
||||
NodeParamView::~NodeParamView()
|
||||
@@ -297,12 +298,25 @@ void NodeParamView::ItemAboutToBeRemoved(NodeParamViewItem *item)
|
||||
}
|
||||
}
|
||||
|
||||
if (focused_node_ == item) {
|
||||
focused_node_ = nullptr;
|
||||
emit FocusedNodeChanged(nullptr);
|
||||
QVector<NodeParamViewItem *> copy = selected_nodes_;
|
||||
if (copy.removeOne(item)) {
|
||||
SetSelectedNodes(copy);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::ItemClicked()
|
||||
{
|
||||
ToggleSelect(static_cast<NodeParamViewItem*>(sender()));
|
||||
}
|
||||
|
||||
void NodeParamView::SelectNodeFromConnectedLink(Node *node)
|
||||
{
|
||||
NodeParamViewItem *item = static_cast<NodeParamViewItem *>(sender());
|
||||
|
||||
Node::ContextPair p = {node, item->GetContext()};
|
||||
SetSelectedNodes({p});
|
||||
}
|
||||
|
||||
void NodeParamView::SetContexts(const QVector<Node *> &contexts)
|
||||
{
|
||||
// Setting contexts is expensive, so we queue it here to prevent multiple calls in a short timespan
|
||||
@@ -371,41 +385,138 @@ Node *NodeParamView::GetTimeTarget() const
|
||||
return time_target_;
|
||||
}
|
||||
|
||||
void ReconnectOutputsIfNotDeletingNode(MultiUndoCommand *c, NodeViewDeleteCommand *dc, Node *output, Node *deleting, Node *context)
|
||||
{
|
||||
for (auto it=deleting->output_connections().cbegin(); it!=deleting->output_connections().cend(); it++) {
|
||||
const NodeInput &proposed_reconnect = it->second;
|
||||
|
||||
if (dc->ContainsNode(proposed_reconnect.node(), context)) {
|
||||
// Uh-oh we're deleting this node too, instead connect to its outputs
|
||||
ReconnectOutputsIfNotDeletingNode(c, dc, output, proposed_reconnect.node(), context);
|
||||
} else {
|
||||
c->add_child(new NodeEdgeAddCommand(output, it->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::DeleteSelected()
|
||||
{
|
||||
if (keyframe_view_ && keyframe_view_->hasFocus()) {
|
||||
keyframe_view_->DeleteSelected();
|
||||
} else if (focused_node_) {
|
||||
} else if (!selected_nodes_.isEmpty()) {
|
||||
MultiUndoCommand *c = new MultiUndoCommand();
|
||||
Node *n = focused_node_->GetNode();
|
||||
|
||||
// Create command to delete node from context and/or graph
|
||||
NodeViewDeleteCommand *dc = new NodeViewDeleteCommand();
|
||||
dc->AddNode(n, focused_node_->GetContext());
|
||||
c->add_child(dc);
|
||||
|
||||
// Copy any outputs that were connected
|
||||
if (n->GetEffectInput().IsValid()) {
|
||||
if (Node *out = n->GetEffectInput().GetConnectedOutput()) {
|
||||
for (auto it=n->output_connections().cbegin(); it!=n->output_connections().cend(); it++) {
|
||||
c->add_child(new NodeEdgeAddCommand(out, it->second));
|
||||
}
|
||||
}
|
||||
// Add all nodes
|
||||
foreach (NodeParamViewItem *item, selected_nodes_) {
|
||||
Node *n = item->GetNode();
|
||||
dc->AddNode(n, item->GetContext());
|
||||
}
|
||||
|
||||
// Make reconnections where possible
|
||||
foreach (NodeParamViewItem *item, selected_nodes_) {
|
||||
Node *n = item->GetNode();
|
||||
|
||||
Node *node_being_deleted = n;
|
||||
Node *connected_to_effect_input = n;
|
||||
|
||||
while (true) {
|
||||
if (node_being_deleted->GetEffectInput().IsValid()) {
|
||||
if ((connected_to_effect_input = node_being_deleted->GetEffectInput().GetConnectedOutput())) {
|
||||
if (dc->ContainsNode(connected_to_effect_input, item->GetContext())) {
|
||||
// Node's getting deleted, recurse
|
||||
node_being_deleted = connected_to_effect_input;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (connected_to_effect_input) {
|
||||
ReconnectOutputsIfNotDeletingNode(c, dc, connected_to_effect_input, n, item->GetContext());
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(c);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::SelectNodes(const QVector<Node *> &nodes)
|
||||
void NodeParamView::SetSelectedNodes(const QVector<NodeParamViewItem *> &nodes, bool handle_focused_node, bool emit_signal)
|
||||
{
|
||||
// Do nothing, this is a placeholder if we ever need this to do anything in the future
|
||||
if (handle_focused_node) {
|
||||
handle_focused_node = !focused_node_ || selected_nodes_.contains(focused_node_);
|
||||
}
|
||||
|
||||
foreach (NodeParamViewItem *n, selected_nodes_) {
|
||||
n->SetHighlighted(false);
|
||||
}
|
||||
|
||||
selected_nodes_ = nodes;
|
||||
|
||||
QVector<Node::ContextPair> p;
|
||||
if (emit_signal) {
|
||||
p.resize(selected_nodes_.size());
|
||||
}
|
||||
|
||||
for (int i=0; i<selected_nodes_.size(); i++) {
|
||||
NodeParamViewItem *n = selected_nodes_.at(i);
|
||||
n->SetHighlighted(true);
|
||||
|
||||
if (emit_signal) {
|
||||
p[i] = {n->GetNode(), n->GetContext()};
|
||||
}
|
||||
}
|
||||
|
||||
if (handle_focused_node) {
|
||||
focused_node_ = nullptr;
|
||||
|
||||
foreach (NodeParamViewItem *n, selected_nodes_) {
|
||||
if (n->GetNode()->HasGizmos()) {
|
||||
focused_node_ = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Node *n = focused_node_ ? focused_node_->GetNode() : nullptr;
|
||||
emit FocusedNodeChanged(n);
|
||||
}
|
||||
|
||||
if (emit_signal) {
|
||||
emit SelectedNodesChanged(p);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::DeselectNodes(const QVector<Node *> &nodes)
|
||||
void NodeParamView::SetSelectedNodes(const QVector<Node::ContextPair> &nodes, bool emit_signal)
|
||||
{
|
||||
// Do nothing, this is a placeholder if we ever need this to do anything in the future
|
||||
QVector<NodeParamViewItem*> items;
|
||||
|
||||
foreach (const Node::ContextPair &n, nodes) {
|
||||
for (auto it=context_items_.cbegin(); it!=context_items_.cend(); it++) {
|
||||
NodeParamViewContext *ctx = *it;
|
||||
|
||||
NodeParamViewItem *item = ctx->GetItem(n.node, n.context);
|
||||
|
||||
if (item) {
|
||||
items.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetSelectedNodes(items, true, emit_signal);
|
||||
|
||||
if (!selected_nodes_.empty()) {
|
||||
NodeParamViewItem *scrolled_to = selected_nodes_.front();
|
||||
param_scroll_area_->ensureWidgetVisible(scrolled_to, 0, 0);
|
||||
|
||||
QPoint viewport_pos = scrolled_to->mapTo(param_scroll_area_, scrolled_to->geometry().topLeft());
|
||||
|
||||
param_scroll_area_->verticalScrollBar()->setValue(viewport_pos.y());
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateItemTime(const rational &time)
|
||||
@@ -461,9 +572,10 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context)
|
||||
NodeParamViewItem* item = new NodeParamViewItem(n, IsGroupMode() ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context);
|
||||
|
||||
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal);
|
||||
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
|
||||
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::SelectNodeFromConnectedLink);
|
||||
connect(item, &NodeParamViewItem::PinToggled, this, &NodeParamView::PinNode);
|
||||
connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::InputCheckBoxChanged);
|
||||
connect(item, &NodeParamViewItem::Clicked, this, &NodeParamView::ItemClicked);
|
||||
|
||||
item->SetContext(ctx);
|
||||
item->SetTimeTarget(GetTimeTarget());
|
||||
@@ -474,9 +586,7 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context)
|
||||
|
||||
if (!focused_node_ && n->HasGizmos()) {
|
||||
// We'll focus this node now
|
||||
item->SetHighlighted(true);
|
||||
focused_node_ = item;
|
||||
emit FocusedNodeChanged(n);
|
||||
SetSelectedNodes({item});
|
||||
}
|
||||
|
||||
if (keyframe_view_) {
|
||||
@@ -561,6 +671,36 @@ NodeParamViewContext *NodeParamView::GetContextItemFromContext(Node *ctx)
|
||||
return context_items_.at(ctx_type);
|
||||
}
|
||||
|
||||
void NodeParamView::ToggleSelect(NodeParamViewItem *item)
|
||||
{
|
||||
QVector<NodeParamViewItem*> new_sel;
|
||||
|
||||
if (qApp->keyboardModifiers() & Qt::ShiftModifier) {
|
||||
new_sel = selected_nodes_;
|
||||
}
|
||||
|
||||
if (selected_nodes_.contains(item)) {
|
||||
// De-select this node
|
||||
if (qApp->keyboardModifiers() & Qt::ShiftModifier) {
|
||||
new_sel.removeOne(item);
|
||||
SetSelectedNodes(new_sel, true);
|
||||
}
|
||||
} else {
|
||||
new_sel.append(item);
|
||||
SetSelectedNodes(new_sel, false);
|
||||
|
||||
if (item->GetNode()->HasGizmos() || !new_sel.contains(focused_node_)) {
|
||||
if (item->GetNode()->HasGizmos()) {
|
||||
focused_node_ = item;
|
||||
} else {
|
||||
focused_node_ = nullptr;
|
||||
}
|
||||
|
||||
emit FocusedNodeChanged(focused_node_ ? focused_node_->GetNode() : nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateGlobalScrollBar()
|
||||
{
|
||||
if (keyframe_view_) {
|
||||
@@ -584,7 +724,7 @@ void NodeParamView::PinNode(bool pin)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::FocusChanged(QWidget* old, QWidget* now)
|
||||
/*void NodeParamView::FocusChanged(QWidget* old, QWidget* now)
|
||||
{
|
||||
Q_UNUSED(old)
|
||||
|
||||
@@ -592,39 +732,28 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now)
|
||||
|
||||
while (parent) {
|
||||
if (NodeParamViewItem* item = dynamic_cast<NodeParamViewItem*>(parent)) {
|
||||
if (item != focused_node_) {
|
||||
// Found a NodeParamViewItem that isn't already focused, see if it belongs to us
|
||||
bool ours = false;
|
||||
// Found a NodeParamViewItem that isn't already focused, see if it belongs to us
|
||||
bool ours = false;
|
||||
|
||||
do {
|
||||
parent = parent->parent();
|
||||
do {
|
||||
parent = parent->parent();
|
||||
|
||||
if (parent == this) {
|
||||
ours = true;
|
||||
break;
|
||||
}
|
||||
} while (parent);
|
||||
|
||||
if (ours) {
|
||||
// This item is ours,
|
||||
if (focused_node_) {
|
||||
// De-focus current node
|
||||
focused_node_->SetHighlighted(false);
|
||||
}
|
||||
|
||||
focused_node_ = item;
|
||||
|
||||
item->SetHighlighted(true);
|
||||
|
||||
emit FocusedNodeChanged(item->GetNode());
|
||||
if (parent == this) {
|
||||
ours = true;
|
||||
break;
|
||||
}
|
||||
} while (parent);
|
||||
|
||||
if (ours) {
|
||||
//ToggleSelect(item);
|
||||
Q_UNUSED(item)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent->parent();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void NodeParamView::KeyframeViewDragged(int x, int y)
|
||||
{
|
||||
|
||||
@@ -61,8 +61,8 @@ public:
|
||||
keyframe_view_->DeselectAll();
|
||||
}
|
||||
|
||||
void SelectNodes(const QVector<Node*> &nodes);
|
||||
void DeselectNodes(const QVector<Node*> &nodes);
|
||||
void SetSelectedNodes(const QVector<NodeParamViewItem *> &nodes, bool handle_focused_node = true, bool emit_signal = true);
|
||||
void SetSelectedNodes(const QVector<Node::ContextPair> &nodes, bool emit_signal = true);
|
||||
|
||||
const QVector<Node*> &GetContexts() const
|
||||
{
|
||||
@@ -75,10 +75,10 @@ public slots:
|
||||
void UpdateElementY();
|
||||
|
||||
signals:
|
||||
void RequestSelectNode(const QVector<Node*>& target);
|
||||
|
||||
void FocusedNodeChanged(Node* n);
|
||||
|
||||
void SelectedNodesChanged(const QVector<Node::ContextPair> &nodes);
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
@@ -118,6 +118,8 @@ private:
|
||||
return contexts_.size() == 1 && dynamic_cast<NodeGroup*>(contexts_.first());
|
||||
}
|
||||
|
||||
void ToggleSelect(NodeParamViewItem *item);
|
||||
|
||||
KeyframeView* keyframe_view_;
|
||||
|
||||
QVector<NodeParamViewContext*> context_items_;
|
||||
@@ -137,6 +139,7 @@ private:
|
||||
QVector<Node*> active_nodes_;
|
||||
|
||||
NodeParamViewItem* focused_node_;
|
||||
QVector<NodeParamViewItem*> selected_nodes_;
|
||||
|
||||
Node *time_target_;
|
||||
|
||||
@@ -150,7 +153,7 @@ private slots:
|
||||
|
||||
void PinNode(bool pin);
|
||||
|
||||
void FocusChanged(QWidget *old, QWidget *now);
|
||||
//void FocusChanged(QWidget *old, QWidget *now);
|
||||
|
||||
void KeyframeViewDragged(int x, int y);
|
||||
|
||||
@@ -168,6 +171,10 @@ private slots:
|
||||
|
||||
void ItemAboutToBeRemoved(NodeParamViewItem *item);
|
||||
|
||||
void ItemClicked();
|
||||
|
||||
void SelectNodeFromConnectedLink(Node *node);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu()
|
||||
void NodeParamViewConnectedLabel::ConnectionClicked()
|
||||
{
|
||||
if (connected_node_) {
|
||||
emit RequestSelectNode({connected_node_});
|
||||
emit RequestSelectNode(connected_node_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
void SetTime(const rational &time);
|
||||
|
||||
signals:
|
||||
void RequestSelectNode(const QVector<Node*>& node);
|
||||
void RequestSelectNode(Node *n);
|
||||
|
||||
private slots:
|
||||
void InputConnected(Node *output, const NodeInput &input);
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
signals:
|
||||
void RequestSetTime(const rational& time);
|
||||
|
||||
void RequestSelectNode(const QVector<Node*>& node);
|
||||
void RequestSelectNode(Node *node);
|
||||
|
||||
void ArrayExpandedChanged(bool e);
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
signals:
|
||||
void RequestSetTime(const rational& time);
|
||||
|
||||
void RequestSelectNode(const QVector<Node*>& node);
|
||||
void RequestSelectNode(Node *node);
|
||||
|
||||
void ArrayExpandedChanged(bool e);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ NodeParamViewItemBase::NodeParamViewItemBase(QWidget *parent) :
|
||||
// Connect title bar to this
|
||||
connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItemBase::SetExpanded);
|
||||
connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItemBase::PinToggled);
|
||||
connect(title_bar_, &NodeParamViewItemTitleBar::Clicked, this, &NodeParamViewItemBase::Clicked);
|
||||
|
||||
// Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar
|
||||
// size hints and will shrink as small as possible if the body is hidden)
|
||||
@@ -115,4 +116,11 @@ void NodeParamViewItemBase::moveEvent(QMoveEvent *event)
|
||||
emit Moved();
|
||||
}
|
||||
|
||||
void NodeParamViewItemBase::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
super::mousePressEvent(e);
|
||||
|
||||
emit Clicked();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ signals:
|
||||
|
||||
void Moved();
|
||||
|
||||
void Clicked();
|
||||
|
||||
protected:
|
||||
void SetBody(QWidget *body);
|
||||
|
||||
@@ -74,6 +76,8 @@ protected:
|
||||
|
||||
virtual void moveEvent(QMoveEvent *event) override;
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
protected slots:
|
||||
virtual void Retranslate(){}
|
||||
|
||||
|
||||
@@ -85,6 +85,13 @@ void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemTitleBar::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mousePressEvent(event);
|
||||
|
||||
emit Clicked();
|
||||
}
|
||||
|
||||
void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mouseDoubleClickEvent(event);
|
||||
|
||||
@@ -79,9 +79,12 @@ signals:
|
||||
|
||||
void EnabledCheckBoxClicked(bool e);
|
||||
|
||||
void Clicked();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -51,7 +51,8 @@ NodeView::NodeView(QWidget *parent) :
|
||||
create_edge_output_item_(nullptr),
|
||||
create_edge_input_item_(nullptr),
|
||||
overlay_view_(nullptr),
|
||||
scale_(1.0)
|
||||
scale_(1.0),
|
||||
dont_emit_selection_signals_(false)
|
||||
{
|
||||
setScene(&scene_);
|
||||
SetDefaultDragMode(RubberBandDrag);
|
||||
@@ -171,9 +172,11 @@ void NodeView::DeselectAll()
|
||||
// Just emit all the nodes that are currently selected as no longer selected
|
||||
emit NodesDeselected(selected_nodes_);
|
||||
selected_nodes_.clear();
|
||||
emit NodeSelectionChanged(selected_nodes_);
|
||||
emit NodeSelectionChangedWithContexts(QVector<Node::ContextPair>());
|
||||
}
|
||||
|
||||
void NodeView::Select(const QVector<Node *> &nodes, bool center_view_on_item)
|
||||
void NodeView::Select(const QVector<Node::ContextPair> &nodes, bool center_view_on_item)
|
||||
{
|
||||
// Optimization: rather than respond to every single item being selected, ignore the signal and
|
||||
// then handle them all at the end.
|
||||
@@ -184,18 +187,27 @@ void NodeView::Select(const QVector<Node *> &nodes, bool center_view_on_item)
|
||||
|
||||
scene_.DeselectAll();
|
||||
|
||||
foreach (NodeViewContext *context, scene_.context_map()) {
|
||||
context->Select(nodes);
|
||||
foreach (const Node::ContextPair &p, nodes) {
|
||||
NodeViewContext *ctx = scene_.context_map().value(p.context);
|
||||
if (ctx) {
|
||||
NodeViewItem *item = ctx->GetItemFromMap(p.node);
|
||||
if (item) {
|
||||
item->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Center on something
|
||||
if (center_view_on_item && !nodes.isEmpty()) {
|
||||
QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first()));
|
||||
QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first().node));
|
||||
}
|
||||
|
||||
ConnectSelectionChangedSignal();
|
||||
|
||||
// Don't signal when this function was likely triggered from another widget's signal anyway
|
||||
dont_emit_selection_signals_ = true;
|
||||
UpdateSelectionCache();
|
||||
dont_emit_selection_signals_ = false;
|
||||
}
|
||||
|
||||
void NodeView::CopySelected(bool cut)
|
||||
@@ -734,13 +746,18 @@ void NodeView::UpdateSelectionCache()
|
||||
QVector<Node*> selected;
|
||||
QVector<Node*> deselected;
|
||||
|
||||
QVector<Node::ContextPair> sel_with_ctx(current_selection.size());
|
||||
|
||||
// Determine which nodes are newly selected
|
||||
foreach (NodeViewItem* i, current_selection) {
|
||||
for (int j=0; j<current_selection.size(); j++) {
|
||||
NodeViewItem *i = current_selection.at(j);
|
||||
Node *n = i->GetNode();
|
||||
if (!selected_nodes_.contains(n)) {
|
||||
selected.append(n);
|
||||
selected_nodes_.append(n);
|
||||
}
|
||||
|
||||
sel_with_ctx[j] = {n, i->GetContext()};
|
||||
}
|
||||
|
||||
// Determine which nodes are newly deselected
|
||||
@@ -773,6 +790,11 @@ void NodeView::UpdateSelectionCache()
|
||||
if (!selected.isEmpty()) {
|
||||
emit NodesSelected(selected);
|
||||
}
|
||||
|
||||
if (!dont_emit_selection_signals_) {
|
||||
emit NodeSelectionChanged(selected_nodes_);
|
||||
emit NodeSelectionChangedWithContexts(sel_with_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::ShowContextMenu(const QPoint &pos)
|
||||
@@ -1344,6 +1366,8 @@ void NodeView::ShowNodeProperties()
|
||||
overlay_view_->setFocus();
|
||||
|
||||
emit NodesDeselected(selected_nodes_);
|
||||
emit NodeSelectionChanged(QVector<Node*>());
|
||||
emit NodeSelectionChangedWithContexts(QVector<Node::ContextPair>());
|
||||
overlay_view_->SelectAll();
|
||||
|
||||
emit NodeGroupOpened(group);
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void SelectAll();
|
||||
void DeselectAll();
|
||||
|
||||
void Select(const QVector<Node *> &nodes, bool center_view_on_item);
|
||||
void Select(const QVector<Node::ContextPair> &nodes, bool center_view_on_item);
|
||||
|
||||
void CopySelected(bool cut);
|
||||
void Paste();
|
||||
@@ -117,6 +117,9 @@ signals:
|
||||
|
||||
void NodesDeselected(const QVector<Node*>& nodes);
|
||||
|
||||
void NodeSelectionChanged(const QVector<Node*>& nodes);
|
||||
void NodeSelectionChangedWithContexts(const QVector<Node::ContextPair>& nodes);
|
||||
|
||||
void NodeGroupOpened(NodeGroup *group);
|
||||
void NodeGroupClosed();
|
||||
|
||||
@@ -218,6 +221,8 @@ private:
|
||||
|
||||
double scale_;
|
||||
|
||||
bool dont_emit_selection_signals_;
|
||||
|
||||
static const double kMinimumScale;
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -199,13 +199,12 @@ NodeViewDeleteCommand::NodeViewDeleteCommand()
|
||||
|
||||
void NodeViewDeleteCommand::AddNode(Node *node, Node *context)
|
||||
{
|
||||
foreach (const NodePair &pair, nodes_) {
|
||||
if (pair.first == node && pair.second == context) {
|
||||
return;
|
||||
}
|
||||
if (ContainsNode(node, context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nodes_.append(NodePair({node, context}));
|
||||
Node::ContextPair p = {node, context};
|
||||
nodes_.append(p);
|
||||
|
||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
||||
if (context->ContextContainsNode(it->second)) {
|
||||
@@ -231,10 +230,21 @@ void NodeViewDeleteCommand::AddEdge(Node *output, const NodeInput &input)
|
||||
edges_.append({output, input});
|
||||
}
|
||||
|
||||
bool NodeViewDeleteCommand::ContainsNode(Node *node, Node *context)
|
||||
{
|
||||
foreach (const Node::ContextPair &pair, nodes_) {
|
||||
if (pair.node == node && pair.context == context) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Project *NodeViewDeleteCommand::GetRelevantProject() const
|
||||
{
|
||||
if (!nodes_.isEmpty()) {
|
||||
return nodes_.first().first->project();
|
||||
return nodes_.first().node->project();
|
||||
}
|
||||
|
||||
if (!edges_.isEmpty()) {
|
||||
@@ -250,11 +260,11 @@ void NodeViewDeleteCommand::redo()
|
||||
Node::DisconnectEdge(edge.first, edge.second);
|
||||
}
|
||||
|
||||
foreach (const NodePair &pair, nodes_) {
|
||||
foreach (const Node::ContextPair &pair, nodes_) {
|
||||
RemovedNode rn;
|
||||
|
||||
rn.node = pair.first;
|
||||
rn.context = pair.second;
|
||||
rn.node = pair.node;
|
||||
rn.context = pair.context;
|
||||
rn.pos = rn.context->GetNodePositionInContext(rn.node);
|
||||
|
||||
rn.context->RemoveNodeFromContext(rn.node);
|
||||
|
||||
@@ -372,6 +372,8 @@ public:
|
||||
|
||||
void AddEdge(Node *output, const NodeInput &input);
|
||||
|
||||
bool ContainsNode(Node *node, Node *context);
|
||||
|
||||
virtual Project * GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
@@ -380,9 +382,7 @@ protected:
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
using NodePair = QPair<Node *, Node*>;
|
||||
|
||||
QVector<NodePair> nodes_;
|
||||
QVector<Node::ContextPair> nodes_;
|
||||
|
||||
QVector<Node::OutputConnection> edges_;
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex)));
|
||||
|
||||
renderer()->Blit(pipeline, job, VideoParams(width(), height(),
|
||||
static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt()),
|
||||
static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
VideoParams::kInternalChannelCount));
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex)));
|
||||
|
||||
renderer()->Blit(pipeline, job, VideoParams(width(), height(),
|
||||
static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt()),
|
||||
static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
VideoParams::kInternalChannelCount));
|
||||
|
||||
float waveform_dim_x = ceil((width() - 1.0) * waveform_scale);
|
||||
|
||||
@@ -139,7 +139,7 @@ bool NumericSliderBase::IsDragging() const
|
||||
|
||||
bool NumericSliderBase::UsingLadders() const
|
||||
{
|
||||
return ladder_element_count_ > 0 && Config::Current()[QStringLiteral("UseSliderLadders")].toBool();
|
||||
return ladder_element_count_ > 0 && OLIVE_CONFIG("UseSliderLadders").toBool();
|
||||
}
|
||||
|
||||
QVariant NumericSliderBase::AdjustValue(const QVariant &value) const
|
||||
|
||||
@@ -48,7 +48,7 @@ SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QString
|
||||
setFrameShape(QFrame::Box);
|
||||
setLineWidth(1);
|
||||
|
||||
if (!Config::Current()[QStringLiteral("UseSliderLadders")].toBool()) {
|
||||
if (!OLIVE_CONFIG("UseSliderLadders").toBool()) {
|
||||
nb_outer_values = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ void TimeBasedWidget::SetTime(const rational &time)
|
||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPlayhead", Qt::QueuedConnection);
|
||||
} else {
|
||||
// Otherwise, assume we jumped to this out of nowhere and must now autoscroll
|
||||
switch (static_cast<AutoScroll::Method>(Config::Current()["Autoscroll"].toInt())) {
|
||||
switch (static_cast<AutoScroll::Method>(OLIVE_CONFIG("Autoscroll").toInt())) {
|
||||
case AutoScroll::kNone:
|
||||
// Do nothing
|
||||
break;
|
||||
@@ -606,12 +606,12 @@ void TimeBasedWidget::SetMarker()
|
||||
color = closest->color();
|
||||
} else {
|
||||
// Fallback to default color in preferences
|
||||
color = Config::Current()[QStringLiteral("MarkerColor")].toInt();
|
||||
color = OLIVE_CONFIG("MarkerColor").toInt();
|
||||
}
|
||||
|
||||
TimelineMarker *marker = new TimelineMarker(color, TimeRange(GetTime(), GetTime()));
|
||||
|
||||
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
|
||||
if (OLIVE_CONFIG("SetNameWithMarker").toBool()) {
|
||||
MarkerPropertiesDialog mpd({marker}, timebase(), this);
|
||||
if (mpd.exec() != QDialog::Accepted) {
|
||||
delete marker;
|
||||
|
||||
@@ -1079,6 +1079,9 @@ void TimelineWidget::ShowContextMenu()
|
||||
}
|
||||
}
|
||||
|
||||
QAction* rename_action = menu.addAction(tr("Rename"));
|
||||
connect(rename_action, &QAction::triggered, this, &TimelineWidget::RenameSelectedBlocks);
|
||||
|
||||
QAction* properties_action = menu.addAction(tr("Properties"));
|
||||
connect(properties_action, &QAction::triggered, this, &TimelineWidget::ShowSpeedDurationDialogForSelectedClips);
|
||||
}
|
||||
@@ -1232,6 +1235,19 @@ void TimelineWidget::RevealInProject()
|
||||
emit RevealViewerInProject(item_to_reveal);
|
||||
}
|
||||
|
||||
void TimelineWidget::RenameSelectedBlocks()
|
||||
{
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
QVector<Node*> nodes(selected_blocks_.size());
|
||||
|
||||
for (int i=0; i<nodes.size(); i++) {
|
||||
nodes[i] = selected_blocks_[i];
|
||||
}
|
||||
|
||||
Core::instance()->LabelNodes(nodes);
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
|
||||
{
|
||||
ghost_items_.append(ghost);
|
||||
|
||||
@@ -414,6 +414,8 @@ private slots:
|
||||
|
||||
void RevealInProject();
|
||||
|
||||
void RenameSelectedBlocks();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const DraggedFootageData
|
||||
|
||||
if (footage_duration.isNull()) {
|
||||
// Fallback to still length if legngth was 0
|
||||
footage_duration = Config::Current()[QStringLiteral("DefaultStillLength")].value<rational>();
|
||||
footage_duration = OLIVE_CONFIG("DefaultStillLength").value<rational>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ void ImportTool::DropGhosts(bool insert)
|
||||
} else {
|
||||
// There's no active timeline here, ask the user what to do
|
||||
|
||||
DropWithoutSequenceBehavior behavior = static_cast<DropWithoutSequenceBehavior>(Config::Current()["DropWithoutSequenceBehavior"].toInt());
|
||||
DropWithoutSequenceBehavior behavior = static_cast<DropWithoutSequenceBehavior>(OLIVE_CONFIG("DropWithoutSequenceBehavior").toInt());
|
||||
|
||||
if (behavior == kDWSAsk) {
|
||||
QCheckBox* dont_ask_again_box = new QCheckBox(QCoreApplication::translate("ImportTool", "Don't ask me again"));
|
||||
@@ -312,7 +312,7 @@ void ImportTool::DropGhosts(bool insert)
|
||||
}
|
||||
|
||||
if (behavior != kDWSDisable && dont_ask_again_box->isChecked()) {
|
||||
Config::Current()["DropWithoutSequenceBehavior"] = behavior;
|
||||
OLIVE_CONFIG("DropWithoutSequenceBehavior") = behavior;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ private:
|
||||
class TimelineAddTrackCommand : public UndoCommand {
|
||||
public:
|
||||
TimelineAddTrackCommand(TrackList *timeline) :
|
||||
TimelineAddTrackCommand(timeline, Config::Current()[QStringLiteral("AutoMergeTracks")].toBool())
|
||||
TimelineAddTrackCommand(timeline, OLIVE_CONFIG("AutoMergeTracks").toBool())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ void TimelineView::wheelEvent(QWheelEvent *event)
|
||||
|
||||
QPoint angle_delta = event->angleDelta();
|
||||
|
||||
if (Config::Current()[QStringLiteral("InvertTimelineScrollAxes")].toBool() // Check if config is set to invert timeline axes
|
||||
if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool() // Check if config is set to invert timeline axes
|
||||
&& event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though
|
||||
angle_delta = QPoint(angle_delta.y(), angle_delta.x());
|
||||
}
|
||||
@@ -184,7 +184,7 @@ void TimelineView::wheelEvent(QWheelEvent *event)
|
||||
|
||||
Qt::Orientation orientation = event->orientation();
|
||||
|
||||
if (Config::Current()["InvertTimelineScrollAxes"].toBool()) {
|
||||
if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool()) {
|
||||
orientation = (orientation == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect)
|
||||
|
||||
Block *attached = Node::ValueToPtr<Block>(ghost->GetData(TimelineViewGhostItem::kAttachedBlock));
|
||||
|
||||
if (attached && Config::Current()[QStringLiteral("ShowClipWhileDragging")].toBool()) {
|
||||
if (attached && OLIVE_CONFIG("ShowClipWhileDragging").toBool()) {
|
||||
int adj_track = ghost->GetAdjustedTrack().index();
|
||||
qreal track_top = GetTrackY(adj_track);
|
||||
qreal track_height = GetTrackHeight(adj_track);
|
||||
|
||||
@@ -741,7 +741,7 @@ void ViewerWidget::PauseInternal()
|
||||
|
||||
void ViewerWidget::PushScrubbedAudio()
|
||||
{
|
||||
if (!IsPlaying() && GetConnectedNode() && Config::Current()[QStringLiteral("AudioScrubbing")].toBool()) {
|
||||
if (!IsPlaying() && GetConnectedNode() && OLIVE_CONFIG("AudioScrubbing").toBool()) {
|
||||
// Get audio src device from renderer
|
||||
const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters();
|
||||
|
||||
@@ -1129,9 +1129,9 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
|
||||
{
|
||||
QAction *stop_playback_on_last_frame = menu.addAction(tr("Stop Playback On Last Frame"));
|
||||
stop_playback_on_last_frame->setCheckable(true);
|
||||
stop_playback_on_last_frame->setChecked(Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool());
|
||||
stop_playback_on_last_frame->setChecked(OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool());
|
||||
connect(stop_playback_on_last_frame, &QAction::triggered, this, [](bool e){
|
||||
Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")] = e;
|
||||
OLIVE_CONFIG("StopPlaybackOnLastFrame") = e;
|
||||
});
|
||||
|
||||
menu.addSeparator();
|
||||
@@ -1180,7 +1180,7 @@ void ViewerWidget::Play(bool in_to_out_only)
|
||||
|
||||
recording_filename_ = audio_path.filePath(QStringLiteral("%1.%2").arg(
|
||||
QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss"),
|
||||
ExportFormat::GetExtension(static_cast<ExportFormat::Format>(Config::Current()[QStringLiteral("AudioRecordingFormat")].toInt())))
|
||||
ExportFormat::GetExtension(static_cast<ExportFormat::Format>(OLIVE_CONFIG("AudioRecordingFormat").toInt())))
|
||||
);
|
||||
|
||||
AudioParams ap(OLIVE_CONFIG("AudioRecordingSampleRate").toInt(), OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong(), static_cast<AudioParams::Format>(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt()));
|
||||
@@ -1304,7 +1304,7 @@ void ViewerWidget::PlaybackTimerUpdate()
|
||||
|
||||
// If we're stopping playback on the last frame rather than after it, subtract our max time
|
||||
// by one timebase unit
|
||||
if (Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool()) {
|
||||
if (OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool()) {
|
||||
max_time = qMax(min_time, max_time - timebase());
|
||||
}
|
||||
|
||||
@@ -1329,7 +1329,7 @@ void ViewerWidget::PlaybackTimerUpdate()
|
||||
// or restart playback
|
||||
end_of_line = true;
|
||||
|
||||
if (Config::Current()[QStringLiteral("Loop")].toBool() && !recording_) {
|
||||
if (OLIVE_CONFIG("Loop").toBool() && !recording_) {
|
||||
|
||||
// If we're looping, jump to the other side of the workarea and continue
|
||||
time_to_set = (tripped_time == min_time) ? max_time : min_time;
|
||||
|
||||
@@ -428,7 +428,7 @@ void ViewerDisplayWidget::OnPaint()
|
||||
// Draw texture through color transform
|
||||
int device_width = width() * devicePixelRatioF();
|
||||
int device_height = height() * devicePixelRatioF();
|
||||
VideoParams::Format device_format = static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt());
|
||||
VideoParams::Format device_format = static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt());
|
||||
VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount);
|
||||
|
||||
if (push_mode_ == kPushBlank) {
|
||||
@@ -488,7 +488,7 @@ void ViewerDisplayWidget::OnPaint()
|
||||
ColorTransformJob ctj;
|
||||
ctj.SetColorProcessor(color_service());
|
||||
ctj.SetInputTexture(texture_to_draw);
|
||||
ctj.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone);
|
||||
ctj.SetInputAlphaAssociation(OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? kAlphaAssociated : kAlphaNone);
|
||||
ctj.SetClearDestinationEnabled(false);
|
||||
ctj.SetTransformMatrix(combined_matrix_flipped_);
|
||||
ctj.SetCropMatrix(crop_matrix_);
|
||||
|
||||
Reference in New Issue
Block a user