Merge branch 'master' of https://github.com/olive-editor/olive
This commit is contained in:
@@ -114,10 +114,12 @@ qint64 AudioOutputDeviceProxy::ReverseAwareRead(char *data, qint64 maxlen)
|
||||
|
||||
if (playback_speed_ < 0) {
|
||||
// If we're reversing, we'll seek back by maxlen bytes before we read
|
||||
new_pos = device_->pos() - maxlen;
|
||||
qint64 len_adjusted_by_channels = maxlen / params_.channel_count();
|
||||
|
||||
new_pos = device_->pos() - len_adjusted_by_channels;
|
||||
|
||||
if (new_pos < 0) {
|
||||
maxlen = device_->pos();
|
||||
maxlen = device_->pos() * params_.channel_count();
|
||||
|
||||
new_pos = 0;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ void Config::SetDefaults()
|
||||
SetEntryInternal(QStringLiteral("UseGradients"), NodeValue::kBoolean, true);
|
||||
SetEntryInternal(QStringLiteral("AutoMergeTracks"), NodeValue::kBoolean, true);
|
||||
SetEntryInternal(QStringLiteral("UseSliderLadders"), NodeValue::kBoolean, true);
|
||||
SetEntryInternal(QStringLiteral("ShowWelcomeDialog"), NodeValue::kBoolean, true);
|
||||
|
||||
SetEntryInternal(QStringLiteral("AutoCacheDelay"), NodeValue::kInt, 1000);
|
||||
|
||||
|
||||
+1
-1
@@ -316,7 +316,7 @@ void Core::SetSnapping(const bool &b)
|
||||
|
||||
void Core::DialogAboutShow()
|
||||
{
|
||||
AboutDialog a(main_window_);
|
||||
AboutDialog a(false, main_window_);
|
||||
a.exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ add_subdirectory(diskcache)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(footagerelink)
|
||||
add_subdirectory(keyframeproperties)
|
||||
add_subdirectory(nodeproperties)
|
||||
add_subdirectory(preferences)
|
||||
add_subdirectory(progress)
|
||||
add_subdirectory(rendercancel)
|
||||
|
||||
+65
-18
@@ -26,23 +26,33 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "config/config.h"
|
||||
#include "patreon.h"
|
||||
#include "scrollinglabel.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) :
|
||||
AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
|
||||
if (welcome_dialog) {
|
||||
setWindowTitle(tr("Welcome to %1").arg(QApplication::applicationName()));
|
||||
} else {
|
||||
setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
|
||||
}
|
||||
|
||||
QFontMetrics fm = fontMetrics();
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setMargin(fm.height());
|
||||
|
||||
layout->addWidget(new QLabel());
|
||||
QHBoxLayout *horiz_layout = new QHBoxLayout();
|
||||
horiz_layout->setMargin(fm.height());
|
||||
horiz_layout->setSpacing(fm.height()*2);
|
||||
|
||||
QLabel* icon = new QLabel(QStringLiteral("<html><img src=':/graphics/olive-splash.png'></html>"));
|
||||
icon->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(icon);
|
||||
horiz_layout->addWidget(icon);
|
||||
|
||||
// Construct About text
|
||||
QLabel* label =
|
||||
@@ -58,23 +68,36 @@ AboutDialog::AboutDialog(QWidget *parent) :
|
||||
"This software is licensed under the GNU GPL Version 3.")));
|
||||
|
||||
// Set text formatting
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
label->setWordWrap(true);
|
||||
label->setOpenExternalLinks(true);
|
||||
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
layout->addWidget(label);
|
||||
horiz_layout->addWidget(label);
|
||||
|
||||
layout->addLayout(horiz_layout);
|
||||
|
||||
// Patrons where possible
|
||||
layout->addWidget(new QLabel());
|
||||
|
||||
QString opening_statement;
|
||||
|
||||
if (welcome_dialog || patrons.isEmpty()) {
|
||||
opening_statement = tr("<b>Olive relies on support from the community to continue its development.</b>");
|
||||
} else {
|
||||
opening_statement = tr("Olive wouldn't be possible without the support of gracious donations from the following people.");
|
||||
}
|
||||
|
||||
QLabel* support_lbl = new QLabel(tr("<html>%1 "
|
||||
"If you like this project, please consider making a "
|
||||
"<a href='https://olivevideoeditor.org/donate.php'>one-time donation</a> or "
|
||||
"<a href='https://www.patreon.com/olivevideoeditor'>pledging monthly</a> to "
|
||||
"support its development.</html>").arg(opening_statement));
|
||||
support_lbl->setWordWrap(true);
|
||||
support_lbl->setAlignment(Qt::AlignCenter);
|
||||
support_lbl->setOpenExternalLinks(true);
|
||||
layout->addWidget(support_lbl);
|
||||
|
||||
// Patrons where necessary
|
||||
if (!patrons.isEmpty()) {
|
||||
layout->addWidget(new QLabel());
|
||||
|
||||
QLabel* support_lbl = new QLabel(tr("<html>Olive wouldn't be possible without the support of gracious "
|
||||
"donations from <a href='https://www.patreon.com/olivevideoeditor'>Patreon</a></html>:"));
|
||||
support_lbl->setWordWrap(true);
|
||||
support_lbl->setAlignment(Qt::AlignCenter);
|
||||
support_lbl->setOpenExternalLinks(true);
|
||||
layout->addWidget(support_lbl);
|
||||
|
||||
ScrollingLabel* scroll = new ScrollingLabel(patrons);
|
||||
scroll->StartAnimating();
|
||||
layout->addWidget(scroll);
|
||||
@@ -82,13 +105,37 @@ AboutDialog::AboutDialog(QWidget *parent) :
|
||||
|
||||
layout->addWidget(new QLabel());
|
||||
|
||||
QHBoxLayout *btn_layout = new QHBoxLayout();
|
||||
btn_layout->setMargin(0);
|
||||
btn_layout->setSpacing(0);
|
||||
|
||||
if (welcome_dialog) {
|
||||
dont_show_again_checkbox_ = new QCheckBox(tr("Don't show this message again"));
|
||||
btn_layout->addWidget(dont_show_again_checkbox_);
|
||||
} else {
|
||||
dont_show_again_checkbox_ = nullptr;
|
||||
}
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
|
||||
buttons->setCenterButtons(true);
|
||||
layout->addWidget(buttons);
|
||||
if (!welcome_dialog) {
|
||||
buttons->setCenterButtons(true);
|
||||
}
|
||||
btn_layout->addWidget(buttons);
|
||||
|
||||
layout->addLayout(btn_layout);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
|
||||
setFixedSize(sizeHint());
|
||||
}
|
||||
|
||||
void AboutDialog::accept()
|
||||
{
|
||||
if (dont_show_again_checkbox_ && dont_show_again_checkbox_->isChecked()) {
|
||||
Config::Current()[QStringLiteral("ShowWelcomeDialog")] = false;
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef ABOUTDIALOG_H
|
||||
#define ABOUTDIALOG_H
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
|
||||
#include "common/define.h"
|
||||
@@ -46,7 +47,14 @@ public:
|
||||
*
|
||||
* QWidget parent object. Usually this will be MainWindow.
|
||||
*/
|
||||
explicit AboutDialog(QWidget *parent = nullptr);
|
||||
explicit AboutDialog(bool welcome_dialog, QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
private:
|
||||
QCheckBox *dont_show_again_checkbox_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
const int ScrollingLabel::kMinLineHeight = 5;
|
||||
const int ScrollingLabel::kMinLineHeight = 10;
|
||||
|
||||
ScrollingLabel::ScrollingLabel(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 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/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
dialog/nodeproperties/nodepropertiesdialog.cpp
|
||||
dialog/nodeproperties/nodepropertiesdialog.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,74 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 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 "nodepropertiesdialog.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "core.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
NodePropertiesDialog::NodePropertiesDialog(Node *node, const rational &timebase, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
node_(node)
|
||||
{
|
||||
setWindowTitle(tr("Node Properties"));
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
QHBoxLayout *label_layout = new QHBoxLayout();
|
||||
label_layout->setMargin(0);
|
||||
layout->addLayout(label_layout);
|
||||
|
||||
label_layout->addWidget(new QLabel(tr("Name:")));
|
||||
|
||||
label_edit_ = new QLineEdit();
|
||||
label_edit_->setText(node->GetLabel());
|
||||
label_layout->addWidget(label_edit_);
|
||||
|
||||
NodeParamViewItem *item = new NodeParamViewItem(node);
|
||||
item->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
item->SetTimebase(timebase);
|
||||
item->setTitleBarWidget(new QWidget());
|
||||
layout->addWidget(item);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(btns, &QDialogButtonBox::accepted, this, &NodePropertiesDialog::accept);
|
||||
connect(btns, &QDialogButtonBox::rejected, this, &NodePropertiesDialog::reject);
|
||||
layout->addWidget(btns);
|
||||
}
|
||||
|
||||
void NodePropertiesDialog::accept()
|
||||
{
|
||||
if (label_edit_->text() != node_->GetLabel()) {
|
||||
NodeRenameCommand* rename_command = new NodeRenameCommand();
|
||||
rename_command->AddNode(node_, label_edit_->text());
|
||||
Core::instance()->undo_stack()->push(rename_command);
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 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 NODEPROPERTIESDIALOG_H
|
||||
#define NODEPROPERTIESDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "widget/nodeparamview/nodeparamviewitem.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class NodePropertiesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodePropertiesDialog(Node *node, const rational &timebase, QWidget *parent = nullptr);
|
||||
NodePropertiesDialog(const QVector<Node *> &node, const rational &timebase, QWidget *parent = nullptr) :
|
||||
NodePropertiesDialog(node.first(), timebase, parent)
|
||||
{
|
||||
}
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
private:
|
||||
Node *node_;
|
||||
|
||||
QLineEdit *label_edit_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEPROPERTIESDIALOG_H
|
||||
+1
-1
@@ -96,7 +96,7 @@ public:
|
||||
|
||||
qreal GetNodeContextHeight(Node *context);
|
||||
|
||||
using PositionMap = QMap<Node*, QPointF>;
|
||||
using PositionMap = QHash<Node*, QPointF>;
|
||||
|
||||
const PositionMap &GetNodesForContext(Node *context)
|
||||
{
|
||||
|
||||
@@ -70,7 +70,7 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector<Node *> &nodes, vo
|
||||
writer.writeEndElement(); // contexts
|
||||
|
||||
writer.writeStartElement(QStringLiteral("custom"));
|
||||
CopyNodesToClipboardInternal(&writer, userdata);
|
||||
CopyNodesToClipboardInternal(&writer, nodes, userdata);
|
||||
writer.writeEndElement(); // custom
|
||||
|
||||
writer.writeEndElement(); // olive
|
||||
@@ -229,7 +229,7 @@ QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph,
|
||||
return pasted_nodes;
|
||||
}
|
||||
|
||||
void NodeCopyPasteService::CopyNodesToClipboardInternal(QXmlStreamWriter*, void*)
|
||||
void NodeCopyPasteService::CopyNodesToClipboardInternal(QXmlStreamWriter*, const QVector<Node *> &, void*)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ protected:
|
||||
|
||||
QVector<Node*> PasteNodesFromClipboard(NodeGraph *graph, MultiUndoCommand *command, void* userdata = nullptr);
|
||||
|
||||
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata);
|
||||
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node*> &nodes, void* userdata);
|
||||
|
||||
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata);
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@ NodePanel::NodePanel(QWidget *parent) :
|
||||
QVBoxLayout *outer_layout = new QVBoxLayout(outer_widget);
|
||||
outer_layout->setMargin(0);
|
||||
|
||||
NodeViewToolBar *toolbar = new NodeViewToolBar();
|
||||
outer_layout->addWidget(toolbar);
|
||||
toolbar_ = new NodeViewToolBar();
|
||||
outer_layout->addWidget(toolbar_);
|
||||
|
||||
// Create NodeView widget
|
||||
node_view_ = new NodeView(this);
|
||||
outer_layout->addWidget(node_view_);
|
||||
|
||||
// Connect toolbar to NodeView
|
||||
connect(toolbar, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
|
||||
connect(toolbar, &NodeViewToolBar::AddNodeClicked, node_view_, &NodeView::ShowAddMenu);
|
||||
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
|
||||
connect(toolbar_, &NodeViewToolBar::AddNodeClicked, node_view_, &NodeView::ShowAddMenu);
|
||||
|
||||
// Set defaults
|
||||
toolbar->SetMiniMapEnabled(true);
|
||||
toolbar_->SetMiniMapEnabled(true);
|
||||
node_view_->SetMiniMapEnabled(true);
|
||||
|
||||
// Connect node view signals to this panel
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
void SetGraph(NodeGraph *graph, const QVector<Node*> &nodes)
|
||||
{
|
||||
node_view_->SetGraph(graph, nodes);
|
||||
toolbar_->setEnabled(graph);
|
||||
}
|
||||
|
||||
void ClearGraph()
|
||||
@@ -125,6 +126,8 @@ private:
|
||||
|
||||
NodeView* node_view_;
|
||||
|
||||
NodeViewToolBar *toolbar_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
|
||||
TimeRangeList ranges_we_validated;
|
||||
|
||||
// Calculate buffer size per channel
|
||||
qint64 buffer_size_per_channel = samples->sample_count() * params_.bytes_per_sample_per_channel();
|
||||
qint64 buffer_size_per_channel = samples ? samples->sample_count() * params_.bytes_per_sample_per_channel() : 0;
|
||||
|
||||
// Write each valid range to the segments
|
||||
foreach (const TimeRange& r, valid_ranges) {
|
||||
@@ -103,9 +103,6 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
|
||||
// Determine how many bytes need to be written
|
||||
qint64 total_write_length = params_.time_to_bytes_per_channel(this_write_out_point - this_write_in_point);
|
||||
|
||||
// Retrieve data buffer
|
||||
const char *a = reinterpret_cast<const char*>(samples->data(i));
|
||||
|
||||
// Determine how many bytes we actually have in the source buffer
|
||||
qint64 possible_write_length = qMin(qMax(qint64(0), buffer_size_per_channel - src_offset), total_write_length);
|
||||
|
||||
@@ -114,7 +111,9 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
|
||||
|
||||
// If we have source bytes to write, write them here
|
||||
if (possible_write_length > 0) {
|
||||
seg_file.write(a + src_offset, possible_write_length);
|
||||
// Assume `samples` is valid if we're here, or else `buffer_size_per_channel` and
|
||||
// therefore `possible_write_length` will be 0.
|
||||
seg_file.write(reinterpret_cast<const char*>(samples->data(i)) + src_offset, possible_write_length);
|
||||
}
|
||||
|
||||
if (possible_write_length < total_write_length) {
|
||||
|
||||
+6
-20
@@ -52,14 +52,14 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data,
|
||||
return CreateTexture(params, Texture::k2D, data, linesize);
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture *destination, bool clear_destination, const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix)
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture *destination, bool clear_destination, const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix)
|
||||
{
|
||||
BlitColorManagedInternal(color_processor, source, source_is_premultiplied, destination, destination->params(), clear_destination, matrix, crop_matrix);
|
||||
BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix);
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix)
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix)
|
||||
{
|
||||
BlitColorManagedInternal(color_processor, source, source_is_premultiplied, nullptr, params, clear_destination, matrix, crop_matrix);
|
||||
BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix);
|
||||
}
|
||||
|
||||
TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms)
|
||||
@@ -257,7 +257,7 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source,
|
||||
bool source_is_premultiplied, Texture *destination,
|
||||
AlphaAssociated source_alpha_association, Texture *destination,
|
||||
VideoParams params, bool clear_destination, const QMatrix4x4& matrix,
|
||||
const QMatrix4x4& crop_matrix)
|
||||
{
|
||||
@@ -271,21 +271,7 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source)));
|
||||
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix));
|
||||
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix.inverted()));
|
||||
|
||||
AlphaAssociated associated;
|
||||
if (source->channel_count() == VideoParams::kRGBAChannelCount) {
|
||||
if (source_is_premultiplied) {
|
||||
// De-assoc/re-assoc required for color management
|
||||
associated = kAlphaAssociated;
|
||||
} else {
|
||||
// Just assoc at the end
|
||||
associated = kAlphaUnassociated;
|
||||
}
|
||||
} else {
|
||||
// No assoc/deassoc required
|
||||
associated = kAlphaNone;
|
||||
}
|
||||
job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, associated));
|
||||
job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, source_alpha_association));
|
||||
|
||||
foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) {
|
||||
job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture)));
|
||||
|
||||
@@ -63,8 +63,14 @@ public:
|
||||
Blit(shader, job, nullptr, params, clear_destination);
|
||||
}
|
||||
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
enum AlphaAssociated {
|
||||
kAlphaNone,
|
||||
kAlphaUnassociated,
|
||||
kAlphaAssociated
|
||||
};
|
||||
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
|
||||
TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms);
|
||||
|
||||
@@ -120,16 +126,10 @@ private:
|
||||
|
||||
};
|
||||
|
||||
enum AlphaAssociated {
|
||||
kAlphaNone,
|
||||
kAlphaUnassociated,
|
||||
kAlphaAssociated
|
||||
};
|
||||
|
||||
bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx);
|
||||
|
||||
void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source,
|
||||
bool source_is_premultiplied,
|
||||
AlphaAssociated source_alpha_association,
|
||||
Texture* destination, VideoParams params, bool clear_destination,
|
||||
const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time
|
||||
|
||||
if (output_color_transform) {
|
||||
// Yes color transform, blit color managed
|
||||
render_ctx_->BlitColorManaged(output_color_transform, texture, true, blit_tex.get(), true, matrix);
|
||||
render_ctx_->BlitColorManaged(output_color_transform, texture, Renderer::kAlphaAssociated, blit_tex.get(), true, matrix);
|
||||
} else {
|
||||
// No color transform, just blit
|
||||
ShaderJob job;
|
||||
@@ -439,8 +439,18 @@ QVariant RenderProcessor::ProcessVideoFootage(const FootageJob &stream, const ra
|
||||
using_colorspace,
|
||||
color_manager->GetReferenceColorSpace());
|
||||
|
||||
Renderer::AlphaAssociated alpha_assoc;
|
||||
if (stream_data.channel_count() != VideoParams::kRGBAChannelCount
|
||||
|| stream_data.colorspace() == color_manager->GetReferenceColorSpace()) {
|
||||
alpha_assoc = Renderer::kAlphaNone;
|
||||
} else if (stream_data.premultiplied_alpha()) {
|
||||
alpha_assoc = Renderer::kAlphaAssociated;
|
||||
} else {
|
||||
alpha_assoc = Renderer::kAlphaUnassociated;
|
||||
}
|
||||
|
||||
render_ctx_->BlitColorManaged(processor, unmanaged_texture,
|
||||
stream_data.premultiplied_alpha(),
|
||||
alpha_assoc,
|
||||
value.get());
|
||||
|
||||
still_image_cache_->mutex()->lock();
|
||||
|
||||
@@ -353,42 +353,12 @@ void NodeView::CopySelected(bool cut)
|
||||
|
||||
void NodeView::Paste()
|
||||
{
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
|
||||
paste_command_ = new MultiUndoCommand();
|
||||
|
||||
QVector<Node*> pasted_nodes = PasteNodesFromClipboard(graph_, paste_command_);
|
||||
|
||||
if (!pasted_nodes.isEmpty()) {
|
||||
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, pasted_nodes));
|
||||
}
|
||||
|
||||
paste_command_->redo();
|
||||
PasteNodesInternal();
|
||||
}
|
||||
|
||||
void NodeView::Duplicate()
|
||||
{
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<Node*> selected = scene_.GetSelectedNodes();
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
paste_command_ = new MultiUndoCommand();
|
||||
|
||||
QVector<Node*> duplicated_nodes = Node::CopyDependencyGraph(selected, paste_command_);
|
||||
|
||||
if (!duplicated_nodes.isEmpty()) {
|
||||
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, duplicated_nodes));
|
||||
}
|
||||
|
||||
paste_command_->redo();
|
||||
PasteNodesInternal(scene_.GetSelectedNodes());
|
||||
}
|
||||
|
||||
void NodeView::SetColorLabel(int index)
|
||||
@@ -1005,6 +975,10 @@ void NodeView::ShowContextMenu(const QPoint &pos)
|
||||
|
||||
void NodeView::CreateNodeSlot(QAction *action)
|
||||
{
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* new_node = NodeFactory::CreateFromMenuAction(action);
|
||||
|
||||
if (new_node) {
|
||||
@@ -1067,6 +1041,13 @@ void NodeView::OpenSelectedNodeInViewer()
|
||||
|
||||
void NodeView::RemoveNode(Node *node)
|
||||
{
|
||||
for (const Node::OutputConnection &oc : node->output_connections()) {
|
||||
scene_.RemoveEdge(oc.first, oc.second);
|
||||
}
|
||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
||||
scene_.RemoveEdge(it->second, it->first);
|
||||
}
|
||||
positions_.remove(scene_.item_map().value(node));
|
||||
scene_.RemoveNode(node);
|
||||
}
|
||||
|
||||
@@ -1126,14 +1107,7 @@ void NodeView::RemoveNodePosition(Node *node, Node *relative)
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (const Node::OutputConnection &oc : node->output_connections()) {
|
||||
scene_.RemoveEdge(oc.first, oc.second);
|
||||
}
|
||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
||||
scene_.RemoveEdge(it->second, it->first);
|
||||
}
|
||||
positions_.remove(item);
|
||||
scene_.RemoveNode(node);
|
||||
RemoveNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,6 +1268,65 @@ bool NodeView::eventFilter(QObject *object, QEvent *event)
|
||||
return super::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node *> &nodes, void *userdata)
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("pos"));
|
||||
|
||||
for (Node *n : nodes) {
|
||||
NodeViewItem *item = scene_.item_map().value(n);
|
||||
QPointF pos = item->GetNodePosition();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(n)));
|
||||
writer->writeTextElement(QStringLiteral("x"), QString::number(pos.x()));
|
||||
writer->writeTextElement(QStringLiteral("y"), QString::number(pos.y()));
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // pos
|
||||
}
|
||||
|
||||
void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata)
|
||||
{
|
||||
NodeGraph::PositionMap *map = static_cast<NodeGraph::PositionMap *>(userdata);
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("pos")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
Node *n = nullptr;
|
||||
QPointF pos;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
n = xml_node_data.node_ptrs.value(attr.value().toULongLong());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("x")) {
|
||||
pos.setX(reader->readElementText().toDouble());
|
||||
} else if (reader->name() == QStringLiteral("y")) {
|
||||
pos.setY(reader->readElementText().toDouble());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (n) {
|
||||
map->insert(n, pos);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::ZoomFromKeyboard(double multiplier)
|
||||
{
|
||||
QPoint cursor_pos = mapFromGlobal(QCursor::pos());
|
||||
@@ -1596,6 +1629,53 @@ NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context)
|
||||
return item;
|
||||
}
|
||||
|
||||
void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
||||
{
|
||||
// If no graph, do nothing
|
||||
if (!graph_) {
|
||||
return;
|
||||
}
|
||||
|
||||
paste_command_ = new MultiUndoCommand();
|
||||
|
||||
// If duplicating nodes, duplicate, otherwise paste
|
||||
QVector<Node*> new_nodes;
|
||||
NodeGraph::PositionMap map;
|
||||
if (duplicate_nodes.isEmpty()) {
|
||||
new_nodes = PasteNodesFromClipboard(graph_, paste_command_, &map);
|
||||
|
||||
for (auto it=new_nodes.cbegin(); it!=new_nodes.cend(); it++) {
|
||||
for (Node *context : qAsConst(filter_nodes_)) {
|
||||
paste_command_->add_child(new NodeSetPositionCommand(*it, context, map.value(*it), false));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new_nodes = Node::CopyDependencyGraph(duplicate_nodes, paste_command_);
|
||||
|
||||
for (int i=0; i<duplicate_nodes.size(); i++) {
|
||||
Node *src = duplicate_nodes.at(i);
|
||||
Node *copy = new_nodes.at(i);
|
||||
|
||||
for (Node *context : qAsConst(filter_nodes_)) {
|
||||
QPointF p = scene_.item_map().value(src)->GetNodePosition();
|
||||
paste_command_->add_child(new NodeSetPositionCommand(copy, context, p, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no nodes were retrieved, do nothing
|
||||
if (new_nodes.isEmpty()) {
|
||||
delete paste_command_;
|
||||
paste_command_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach nodes to cursor
|
||||
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, new_nodes));
|
||||
|
||||
paste_command_->redo();
|
||||
}
|
||||
|
||||
NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector<Node *> &nodes) :
|
||||
view_(view),
|
||||
nodes_(nodes)
|
||||
|
||||
@@ -112,6 +112,9 @@ protected:
|
||||
|
||||
virtual bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node*> &nodes, void* userdata) override;
|
||||
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata) override;
|
||||
|
||||
private:
|
||||
void AttachNodesToCursor(const QVector<Node *> &nodes);
|
||||
|
||||
@@ -142,6 +145,8 @@ private:
|
||||
|
||||
NodeViewItem *UpdateNodeItem(Node *node, bool ignore_own_context = false);
|
||||
|
||||
void PasteNodesInternal(const QVector<Node*> &duplicate_nodes = QVector<Node *>());
|
||||
|
||||
class NodeViewAttachNodesToCursor : public UndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "common/define.h"
|
||||
#include "core.h"
|
||||
#include "dialog/nodeproperties/nodepropertiesdialog.h"
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "projectexplorerundo.h"
|
||||
#include "task/precache/precachetask.h"
|
||||
@@ -439,11 +440,12 @@ void ProjectExplorer::ShowItemPropertiesDialog()
|
||||
// FIXME: Support for multiple items
|
||||
if (dynamic_cast<Footage*>(sel)) {
|
||||
|
||||
Core::instance()->LabelNodes({static_cast<Footage*>(sel)});
|
||||
NodePropertiesDialog npd(sel, static_cast<Footage*>(sel)->GetVideoParams().time_base(), this);
|
||||
npd.exec();
|
||||
|
||||
} else if (dynamic_cast<Folder*>(sel)) {
|
||||
|
||||
Core::instance()->LabelNodes({static_cast<Folder*>(sel)});
|
||||
Core::instance()->LabelNodes(context_menu_items_);
|
||||
|
||||
} else if (dynamic_cast<Sequence*>(sel)) {
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ void ScopeBase::OnPaint()
|
||||
if (!managed_tex_ || !managed_tex_up_to_date_
|
||||
|| managed_tex_->params() != texture_->params()) {
|
||||
managed_tex_ = renderer()->CreateTexture(texture_->params());
|
||||
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
|
||||
renderer()->BlitColorManaged(color_service(), texture_, Renderer::kAlphaNone, managed_tex_.get());
|
||||
}
|
||||
|
||||
DrawScope(managed_tex_, pipeline_);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "core.h"
|
||||
#include "common/range.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "dialog/nodeproperties/nodepropertiesdialog.h"
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "tool/add.h"
|
||||
@@ -295,7 +296,7 @@ void TimelineWidget::DisconnectNodeEvent(ViewerOutput *n)
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata)
|
||||
void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node *> &nodes, void* userdata)
|
||||
{
|
||||
// Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere
|
||||
QVector<Block*>& selected = *static_cast<QVector<Block*>*>(userdata);
|
||||
@@ -992,7 +993,8 @@ void TimelineWidget::ShowContextMenu()
|
||||
nodes.append(i);
|
||||
}
|
||||
|
||||
Core::instance()->LabelNodes(nodes);
|
||||
NodePropertiesDialog npd(nodes, timebase(), this);
|
||||
npd.exec();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ protected:
|
||||
virtual void ConnectNodeEvent(ViewerOutput* n) override;
|
||||
virtual void DisconnectNodeEvent(ViewerOutput* n) override;
|
||||
|
||||
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) override;
|
||||
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node*> &nodes, void* userdata) override;
|
||||
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata) override;
|
||||
|
||||
struct BlockPasteData {
|
||||
|
||||
@@ -589,6 +589,10 @@ void TimelineView::ConnectTrackList(TrackList *list)
|
||||
|
||||
void TimelineView::SetBeamCursor(const TimelineCoordinate &coord)
|
||||
{
|
||||
if (!connected_track_list_) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool update_required = coord.GetTrack().type() == connected_track_list_->type()
|
||||
|| cursor_coord_.GetTrack().type() == connected_track_list_->type();
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ void ViewerDisplayWidget::OnPaint()
|
||||
texture_to_draw = deinterlace_texture_;
|
||||
}
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, Renderer::kAlphaNone, device_params, false,
|
||||
combined_matrix_flipped_, crop_matrix_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
|
||||
#include "dialog/about/about.h"
|
||||
#include "mainmenu.h"
|
||||
#include "mainstatusbar.h"
|
||||
|
||||
@@ -486,6 +487,14 @@ void MainWindow::ProjectPanelSelectionChanged(const QVector<Node *> &nodes)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::ShowWelcomeDialog()
|
||||
{
|
||||
if (Config::Current()[QStringLiteral("ShowWelcomeDialog")].toBool()) {
|
||||
AboutDialog ad(true, this);
|
||||
ad.exec();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
void MainWindow::ShowNouveauWarning()
|
||||
{
|
||||
@@ -844,6 +853,8 @@ void MainWindow::showEvent(QShowEvent *e)
|
||||
}
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "ShowWelcomeDialog", Qt::QueuedConnection);
|
||||
|
||||
first_show_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +196,8 @@ private slots:
|
||||
|
||||
void ProjectPanelSelectionChanged(const QVector<Node*> &nodes);
|
||||
|
||||
void ShowWelcomeDialog();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user