markers: reimplemented copy/paste

This commit is contained in:
itsmattkc
2022-05-01 22:33:58 -07:00
parent 6a0b5856c9
commit f7396de121
26 changed files with 452 additions and 424 deletions
@@ -30,7 +30,7 @@
namespace olive {
KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*> &keys, const rational &timebase, QWidget *parent) :
KeyframePropertiesDialog::KeyframePropertiesDialog(const std::vector<NodeKeyframe*> &keys, const rational &timebase, QWidget *parent) :
QDialog(parent),
keys_(keys),
timebase_(timebase)
@@ -91,7 +91,7 @@ KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*>
bool all_same_bezier_out_x = true;
bool all_same_bezier_out_y = true;
for (int i=0;i<keys_.size();i++) {
for (size_t i=0;i<keys_.size();i++) {
if (i > 0) {
NodeKeyframe* prev_key = keys_.at(i-1);
NodeKeyframe* this_key = keys_.at(i);
@@ -126,7 +126,7 @@ KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*>
// Determine if any keyframes are on the same track (in which case we can't set the time)
if (can_set_time) {
for (int j=0;j<keys_.size();j++) {
for (size_t j=0;j<keys_.size();j++) {
if (i != j
&& keys_.at(j)->track() == keys_.at(i)->track()) {
can_set_time = false;
@@ -147,7 +147,7 @@ KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*>
}
if (all_same_time) {
time_slider_->SetValue(keys_.first()->time());
time_slider_->SetValue(keys_.front()->time());
} else {
time_slider_->SetTristate();
}
@@ -169,7 +169,7 @@ KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*>
if (all_same_type) {
// If all keyframes are the same type, set it here
for (int i=0;i<type_select_->count();i++) {
if (type_select_->itemData(i).toInt() == keys_.first()->type()) {
if (type_select_->itemData(i).toInt() == keys_.front()->type()) {
type_select_->setCurrentIndex(i);
// Ensure UI updates for this index
@@ -179,10 +179,10 @@ KeyframePropertiesDialog::KeyframePropertiesDialog(const QVector<NodeKeyframe*>
}
}
SetUpBezierSlider(bezier_in_x_slider_, all_same_bezier_in_x, keys_.first()->bezier_control_in().x());
SetUpBezierSlider(bezier_in_y_slider_, all_same_bezier_in_y, keys_.first()->bezier_control_in().y());
SetUpBezierSlider(bezier_out_x_slider_, all_same_bezier_out_x, keys_.first()->bezier_control_out().x());
SetUpBezierSlider(bezier_out_y_slider_, all_same_bezier_out_y, keys_.first()->bezier_control_out().y());
SetUpBezierSlider(bezier_in_x_slider_, all_same_bezier_in_x, keys_.front()->bezier_control_in().x());
SetUpBezierSlider(bezier_in_y_slider_, all_same_bezier_in_y, keys_.front()->bezier_control_in().y());
SetUpBezierSlider(bezier_out_x_slider_, all_same_bezier_out_x, keys_.front()->bezier_control_out().x());
SetUpBezierSlider(bezier_out_y_slider_, all_same_bezier_out_y, keys_.front()->bezier_control_out().y());
row++;
@@ -35,7 +35,7 @@ class KeyframePropertiesDialog : public QDialog
{
Q_OBJECT
public:
KeyframePropertiesDialog(const QVector<NodeKeyframe*>& keys, const rational& timebase, QWidget* parent = nullptr);
KeyframePropertiesDialog(const std::vector<NodeKeyframe*>& keys, const rational& timebase, QWidget* parent = nullptr);
public slots:
virtual void accept() override;
@@ -43,7 +43,7 @@ public slots:
private:
void SetUpBezierSlider(FloatSlider *slider, bool all_same, double value);
const QVector<NodeKeyframe*>& keys_;
const std::vector<NodeKeyframe*>& keys_;
rational timebase_;
@@ -32,7 +32,7 @@ namespace olive {
#define super QDialog
MarkerPropertiesDialog::MarkerPropertiesDialog(const QVector<TimelineMarker *> &markers, const rational &timebase, QWidget *parent) :
MarkerPropertiesDialog::MarkerPropertiesDialog(const std::vector<TimelineMarker *> &markers, const rational &timebase, QWidget *parent) :
super(parent),
markers_(markers)
{
@@ -60,10 +60,10 @@ MarkerPropertiesDialog::MarkerPropertiesDialog(const QVector<TimelineMarker *> &
}
if (markers.size() == 1) {
in_slider_->SetValue(markers.first()->time_range().in());
in_slider_->SetValue(markers.front()->time_range().in());
in_slider_->SetDisplayType(RationalSlider::kTime);
in_slider_->SetTimebase(timebase);
out_slider_->SetValue(markers.first()->time_range().out());
out_slider_->SetValue(markers.front()->time_range().out());
out_slider_->SetDisplayType(RationalSlider::kTime);
out_slider_->SetTimebase(timebase);
} else {
@@ -83,8 +83,8 @@ MarkerPropertiesDialog::MarkerPropertiesDialog(const QVector<TimelineMarker *> &
color_menu_ = new ColorCodingComboBox();
layout->addWidget(color_menu_, row, 1);
color_menu_->SetColor(markers.first()->color());
for (int i=1; i<markers.size(); i++) {
color_menu_->SetColor(markers.front()->color());
for (size_t i=1; i<markers.size(); i++) {
if (markers.at(i)->color() != color_menu_->GetSelectedColor()) {
color_menu_->SetColor(-1);
break;
@@ -102,8 +102,8 @@ MarkerPropertiesDialog::MarkerPropertiesDialog(const QVector<TimelineMarker *> &
layout->addWidget(label_edit_, row, 1);
// Determine what the startup label text should be
label_edit_->setText(markers.first()->name());
for (int i=1; i<markers.size(); i++) {
label_edit_->setText(markers.front()->name());
for (size_t i=1; i<markers.size(); i++) {
if (markers.at(i)->name() != label_edit_->text()) {
label_edit_->clear();
label_edit_->setPlaceholderText(tr("(multiple)"));
@@ -141,7 +141,7 @@ void MarkerPropertiesDialog::accept()
}
if (markers_.size() == 1) {
command->add_child(new MarkerChangeTimeCommand(markers_.first(), TimeRange(in_slider_->GetValue(), out_slider_->GetValue())));
command->add_child(new MarkerChangeTimeCommand(markers_.front(), TimeRange(in_slider_->GetValue(), out_slider_->GetValue())));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
@@ -55,13 +55,13 @@ class MarkerPropertiesDialog : public QDialog
{
Q_OBJECT
public:
MarkerPropertiesDialog(const QVector<TimelineMarker*> &markers, const rational &timebase, QWidget *parent = nullptr);
MarkerPropertiesDialog(const std::vector<TimelineMarker*> &markers, const rational &timebase, QWidget *parent = nullptr);
public slots:
virtual void accept() override;
private:
QVector<TimelineMarker*> markers_;
std::vector<TimelineMarker*> markers_;
LineEditWithFocusSignal *label_edit_;
-2
View File
@@ -48,8 +48,6 @@ set(OLIVE_SOURCES
node/keyframe.h
node/node.cpp
node/node.h
node/nodecopypaste.cpp
node/nodecopypaste.h
node/param.cpp
node/param.h
node/splitvalue.h
-91
View File
@@ -1,91 +0,0 @@
/***
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 "nodecopypaste.h"
#include <QMessageBox>
#include "core.h"
#include "node/factory.h"
#include "widget/nodeview/nodeviewundo.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
void NodeCopyPasteService::CopyNodesToClipboard(QVector<Node *> nodes, void *userdata)
{
QString copy_str;
QXmlStreamWriter writer(&copy_str);
// For any groups, add children
for (int i=0; i<nodes.size(); i++) {
// If this is a group, add the child nodes too
if (NodeGroup *g = dynamic_cast<NodeGroup*>(nodes.at(i))) {
for (auto it=g->GetContextPositions().cbegin(); it!=g->GetContextPositions().cend(); it++) {
if (!nodes.contains(it.key())) {
nodes.append(it.key());
}
}
}
}
ProjectSerializer::SaveData data(nodes.first()->project(), QString(), nodes);
CopyNodesToClipboardCallback(nodes, &data, userdata);
ProjectSerializer::Save(&writer, data, type_);
Core::CopyStringToClipboard(copy_str);
}
void NodeCopyPasteService::PasteNodesFromClipboard(void *userdata)
{
QString clipboard = Core::PasteStringFromClipboard();
if (clipboard.isEmpty()) {
return;
}
QXmlStreamReader reader(clipboard);
Project temp;
ProjectSerializer::Result res = ProjectSerializer::Load(&temp, &reader, type_);
if (res.code() != ProjectSerializer::kSuccess) {
return;
}
QVector<Node*> pasted_nodes;
foreach (Node *n, temp.nodes()) {
if (!temp.default_nodes().contains(n)) {
// Move nodes out of Project
n->setParent(nullptr);
pasted_nodes.append(n);
}
}
if (pasted_nodes.isEmpty()) {
return;
}
PasteNodesToClipboardCallback(pasted_nodes, res.GetLoadData(), userdata);
}
}
-57
View File
@@ -1,57 +0,0 @@
/***
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 NODECOPYPASTEWIDGET_H
#define NODECOPYPASTEWIDGET_H
#include <QWidget>
#include <QUndoCommand>
#include "node/node.h"
#include "node/project/project.h"
#include "node/project/sequence/sequence.h"
#include "node/project/serializer/serializer.h"
namespace olive {
class NodeCopyPasteService
{
public:
NodeCopyPasteService(const QString &type) :
type_(type)
{}
protected:
void CopyNodesToClipboard(QVector<Node *> nodes, void* userdata = nullptr);
void PasteNodesFromClipboard(void* userdata = nullptr);
virtual void CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *data, void *userdata){}
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata){}
private:
QString type_;
};
}
#endif // NODECOPYPASTEWIDGET_H
@@ -118,6 +118,36 @@ ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamRe
return res;
}
ProjectSerializer::Result ProjectSerializer::Paste(const QString &type)
{
QString clipboard = Core::PasteStringFromClipboard();
if (clipboard.isEmpty()) {
return kNoData;
}
QXmlStreamReader reader(clipboard);
Project temp;
ProjectSerializer::Result res = ProjectSerializer::Load(&temp, &reader, type);
if (res.code() != ProjectSerializer::kSuccess) {
return res;
}
QVector<Node*> pasted_nodes;
foreach (Node *n, temp.nodes()) {
if (!temp.default_nodes().contains(n)) {
// Move nodes out of Project
n->setParent(nullptr);
pasted_nodes.append(n);
}
}
res.SetLoadedNodes(pasted_nodes);
return res;
}
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data, const QString &type)
{
QString temp_save = FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
@@ -187,6 +217,20 @@ ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer, cons
return kSuccess;
}
ProjectSerializer::Result ProjectSerializer::Copy(const SaveData &data, const QString &type)
{
QString copy_str;
QXmlStreamWriter writer(&copy_str);
ProjectSerializer::Result res = ProjectSerializer::Save(&writer, data, type);
if (res == kSuccess) {
Core::CopyStringToClipboard(copy_str);
}
return res;
}
bool ProjectSerializer::IsCancelled() const
{
return false;
@@ -228,4 +272,21 @@ ProjectSerializer::Result ProjectSerializer::LoadWithSerializerVersion(uint vers
}
}
void ProjectSerializer::SaveData::SetOnlySerializeNodesAndResolveGroups(QVector<Node *> nodes)
{
// For any groups, add children
for (int i=0; i<nodes.size(); i++) {
// If this is a group, add the child nodes too
if (NodeGroup *g = dynamic_cast<NodeGroup*>(nodes.at(i))) {
for (auto it=g->GetContextPositions().cbegin(); it!=g->GetContextPositions().cend(); it++) {
if (!nodes.contains(it.key())) {
nodes.append(it.key());
}
}
}
}
SetOnlySerializeNodes(nodes);
}
}
+19 -6
View File
@@ -50,7 +50,8 @@ public:
kUnknownVersion,
kFileError,
kXmlError,
kOverwriteError
kOverwriteError,
kNoData
};
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
@@ -62,6 +63,8 @@ public:
SerializedProperties properties;
std::vector<TimelineMarker*> markers;
};
class Result
@@ -84,6 +87,10 @@ public:
void SetLoadData(const LoadData &p) { load_data_ = p; }
const QVector<Node*> &GetLoadedNodes() const { return loaded_nodes_; }
void SetLoadedNodes(const QVector<Node*> &n) { loaded_nodes_ = n; }
private:
ResultCode code_;
@@ -91,17 +98,17 @@ public:
LoadData load_data_;
QVector<Node*> loaded_nodes_;
};
class SaveData
{
public:
SaveData(Project *project, const QString &filename, const QVector<Node*> &only = QVector<Node*>(), const SerializedProperties &p = SerializedProperties())
SaveData(Project *project, const QString &filename = QString())
{
project_ = project;
filename_ = filename;
only_serialize_nodes_ = only;
properties_ = p;
}
Project *GetProject() const
@@ -115,11 +122,13 @@ public:
}
const QVector<Node*> &GetOnlySerializeNodes() const { return only_serialize_nodes_; }
void SetOnlySerializeNodes(const QVector<Node*> &only) { only_serialize_nodes_ = only; }
void SetOnlySerializeNodesAndResolveGroups(QVector<Node*> only);
const std::vector<TimelineMarker*> &GetOnlySerializeMarkers() const { return only_serialize_markers_; }
void SetOnlySerializeMarkers(const std::vector<TimelineMarker*> &only) { only_serialize_markers_ = only; }
const SerializedProperties &GetProperties() const { return properties_; }
void SetProperties(const SerializedProperties &p) { properties_ = p; }
private:
@@ -131,6 +140,8 @@ public:
SerializedProperties properties_;
std::vector<TimelineMarker*> only_serialize_markers_;
};
static void Initialize();
@@ -139,9 +150,11 @@ public:
static Result Load(Project *project, const QString &filename, const QString &type);
static Result Load(Project *project, QXmlStreamReader *read_device, const QString &type);
static Result Paste(const QString &type);
static Result Save(const SaveData &data, const QString &type);
static Result Save(QXmlStreamWriter *write_device, const SaveData &data, const QString &type);
static Result Copy(const SaveData &data, const QString &type);
protected:
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const = 0;
+118 -75
View File
@@ -31,6 +31,8 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
QMap<quintptr, QMap<quintptr, Node::Position> > positions;
XMLNodeData xml_node_data;
LoadData load_data;
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("layout")) {
@@ -97,6 +99,18 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
}
}
} else if (reader->name() == QStringLiteral("markers")) {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("marker")) {
TimelineMarker *marker = new TimelineMarker();
LoadMarker(reader, marker);
load_data.markers.push_back(marker);
} else {
reader->skipCurrentElement();
}
}
} else if (reader->name() == QStringLiteral("positions")) {
while (XMLReadNextStartElement(reader)) {
@@ -194,8 +208,6 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
// Make connections
PostConnect(xml_node_data);
LoadData load_data;
// Resolve serialized properties (if any)
for (auto it=properties.cbegin(); it!=properties.cend(); it++) {
Node *node = xml_node_data.node_ptrs.value(it.key());
@@ -211,74 +223,94 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
{
Project *project = data.GetProject();
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
if (!data.GetOnlySerializeMarkers().empty()) {
writer->writeStartElement(QStringLiteral("nodes"));
writer->writeStartElement(QStringLiteral("markers"));
const QVector<Node*> &using_node_list = (data.GetOnlySerializeNodes().isEmpty()) ? project->nodes() : data.GetOnlySerializeNodes();
for (auto it=data.GetOnlySerializeMarkers().cbegin(); it!=data.GetOnlySerializeMarkers().cend(); it++) {
TimelineMarker *marker = *it;
foreach (Node* node, using_node_list) {
writer->writeStartElement(QStringLiteral("node"));
writer->writeStartElement(QStringLiteral("marker"));
if (node == project->root()) {
writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1"));
} else if (node == project->color_manager()) {
writer->writeAttribute(QStringLiteral("cm"), QStringLiteral("1"));
} else if (node == project->settings()) {
writer->writeAttribute(QStringLiteral("settings"), QStringLiteral("1"));
SaveMarker(writer, marker);
writer->writeEndElement(); // marker
}
writer->writeAttribute(QStringLiteral("id"), node->id());
writer->writeEndElement(); // markers
SaveNode(node, writer);
} else {
writer->writeEndElement(); // node
}
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
writer->writeEndElement(); // nodes
writer->writeStartElement(QStringLiteral("nodes"));
writer->writeStartElement(QStringLiteral("positions"));
const QVector<Node*> &using_node_list = (data.GetOnlySerializeNodes().isEmpty()) ? project->nodes() : data.GetOnlySerializeNodes();
foreach (Node* context, using_node_list) {
const Node::PositionMap &map = context->GetContextPositions();
foreach (Node* node, using_node_list) {
writer->writeStartElement(QStringLiteral("node"));
if (!map.isEmpty()) {
writer->writeStartElement(QStringLiteral("context"));
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
if (data.GetOnlySerializeNodes().isEmpty() || data.GetOnlySerializeNodes().contains(jt.key())) {
writer->writeStartElement(QStringLiteral("node"));
SavePosition(writer, jt.key(), jt.value());
writer->writeEndElement(); // node
}
if (node == project->root()) {
writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1"));
} else if (node == project->color_manager()) {
writer->writeAttribute(QStringLiteral("cm"), QStringLiteral("1"));
} else if (node == project->settings()) {
writer->writeAttribute(QStringLiteral("settings"), QStringLiteral("1"));
}
writer->writeEndElement(); // context
}
}
writer->writeAttribute(QStringLiteral("id"), node->id());
writer->writeEndElement(); // positions
SaveNode(node, writer);
writer->writeStartElement(QStringLiteral("properties"));
for (auto it=data.GetProperties().cbegin(); it!=data.GetProperties().cend(); it++) {
writer->writeStartElement(QStringLiteral("node"));
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
writer->writeTextElement(jt.key(), jt.value());
writer->writeEndElement(); // node
}
writer->writeEndElement(); // node
writer->writeEndElement(); // nodes
writer->writeStartElement(QStringLiteral("positions"));
foreach (Node* context, using_node_list) {
const Node::PositionMap &map = context->GetContextPositions();
if (!map.isEmpty()) {
writer->writeStartElement(QStringLiteral("context"));
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
if (data.GetOnlySerializeNodes().isEmpty() || data.GetOnlySerializeNodes().contains(jt.key())) {
writer->writeStartElement(QStringLiteral("node"));
SavePosition(writer, jt.key(), jt.value());
writer->writeEndElement(); // node
}
}
writer->writeEndElement(); // context
}
}
writer->writeEndElement(); // positions
writer->writeStartElement(QStringLiteral("properties"));
for (auto it=data.GetProperties().cbegin(); it!=data.GetProperties().cend(); it++) {
writer->writeStartElement(QStringLiteral("node"));
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
writer->writeTextElement(jt.key(), jt.value());
}
writer->writeEndElement(); // node
}
writer->writeEndElement(); // properties
// Save main window project layout
project->GetLayoutInfo().toXml(writer);
}
writer->writeEndElement(); // properties
// Save main window project layout
project->GetLayoutInfo().toXml(writer);
}
void ProjectSerializer220403::LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const
@@ -954,6 +986,36 @@ void ProjectSerializer220403::SaveTimelinePoints(QXmlStreamWriter *writer, Timel
writer->writeEndElement(); // markers
}
void ProjectSerializer220403::LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const
{
rational in, out;
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("name")) {
marker->set_name(attr.value().toString());
} else if (attr.name() == QStringLiteral("in")) {
in = rational::fromString(attr.value().toString());
} else if (attr.name() == QStringLiteral("out")) {
out = rational::fromString(attr.value().toString());
} else if (attr.name() == QStringLiteral("color")) {
marker->set_color(attr.value().toInt());
}
}
marker->set_time(TimeRange(in, out));
// This element has no inner text, so just skip it
reader->skipCurrentElement();
}
void ProjectSerializer220403::SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const
{
writer->writeAttribute(QStringLiteral("name"), marker->name());
writer->writeAttribute(QStringLiteral("in"), marker->time_range().in().toString());
writer->writeAttribute(QStringLiteral("out"), marker->time_range().out().toString());
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
}
void ProjectSerializer220403::LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const
{
rational range_in = workarea->in();
@@ -989,26 +1051,11 @@ void ProjectSerializer220403::LoadMarkerList(QXmlStreamReader *reader, TimelineM
{
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("marker")) {
QString name;
rational in, out;
int color = Config::Current()[QStringLiteral("MarkerColor")].toInt();
XMLAttributeLoop(reader, attr) {
if (attr.name() == QStringLiteral("name")) {
name = attr.value().toString();
} else if (attr.name() == QStringLiteral("in")) {
in = rational::fromString(attr.value().toString());
} else if (attr.name() == QStringLiteral("out")) {
out = rational::fromString(attr.value().toString());
} else if (attr.name() == QStringLiteral("color")) {
color = attr.value().toInt();
}
}
new TimelineMarker(color, TimeRange(in, out), name, markers);
TimelineMarker *marker = new TimelineMarker(markers);
LoadMarker(reader, marker);
} else {
reader->skipCurrentElement();
}
reader->skipCurrentElement();
}
}
@@ -1019,11 +1066,7 @@ void ProjectSerializer220403::SaveMarkerList(QXmlStreamWriter *writer, TimelineM
writer->writeStartElement(QStringLiteral("marker"));
writer->writeAttribute(QStringLiteral("name"), marker->name());
writer->writeAttribute(QStringLiteral("in"), marker->time_range().in().toString());
writer->writeAttribute(QStringLiteral("out"), marker->time_range().out().toString());
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
SaveMarker(writer, marker);
writer->writeEndElement(); // marker
}
@@ -100,6 +100,10 @@ private:
void SaveTimelinePoints(QXmlStreamWriter *writer, TimelinePoints *points) const;
void LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const;
void SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const;
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
void SaveWorkArea(QXmlStreamWriter *writer, TimelineWorkArea *workarea) const;
+3
View File
@@ -57,6 +57,9 @@ bool ProjectLoadTask::Run()
case ProjectSerializer::kXmlError:
SetError(tr("Failed to read XML document. File may be corrupt. Error was: %1").arg(result.GetDetails()));
break;
case ProjectSerializer::kNoData:
SetError(tr("Failed to find any data to parse."));
break;
// Errors that should never be thrown by a load
case ProjectSerializer::kOverwriteError:
+1
View File
@@ -66,6 +66,7 @@ bool ProjectSaveTask::Run()
case ProjectSerializer::kProjectTooNew:
case ProjectSerializer::kProjectTooOld:
case ProjectSerializer::kUnknownVersion:
case ProjectSerializer::kNoData:
SetError(tr("Unknown error."));
break;
}
+6
View File
@@ -28,6 +28,12 @@
namespace olive {
TimelineMarker::TimelineMarker(QObject *parent) :
color_(Config::Current()[QStringLiteral("MarkerColor")].toInt())
{
setParent(parent);
}
TimelineMarker::TimelineMarker(int color, const TimeRange &time, const QString &name, QObject *parent) :
time_(time),
name_(name),
+1
View File
@@ -35,6 +35,7 @@ class TimelineMarker : public QObject
{
Q_OBJECT
public:
TimelineMarker(QObject* parent = nullptr);
TimelineMarker(int color, const TimeRange& time, const QString& name = QString(), QObject* parent = nullptr);
const rational &time() const { return time_.in(); }
+6 -6
View File
@@ -406,7 +406,7 @@ void CurveView::FirstChanceMouseRelease(QMouseEvent *event)
void CurveView::KeyframeDragStart(QMouseEvent *event)
{
drag_keyframe_values_.resize(GetSelectedKeyframes().size());
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
NodeKeyframe *key = GetSelectedKeyframes().at(i);
drag_keyframe_values_[i] = key->value();
}
@@ -418,7 +418,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
{
if (event->modifiers() & Qt::ShiftModifier) {
// Lock to X axis only and set original values on all keys
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
NodeKeyframe *key = GetSelectedKeyframes().at(i);
key->set_value(drag_keyframe_values_.at(i));
}
@@ -429,7 +429,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
double scaled_diff = (mapToScene(event->pos()).y() - drag_start_.y()) / GetYScale();
// Validate movement - ensure no keyframe goes above its max point or below its min point
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
NodeKeyframe *key = GetSelectedKeyframes().at(i);
FloatSlider::DisplayType display = GetFloatDisplayTypeFromKeyframe(key);
@@ -453,13 +453,13 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
}
// Set values
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
NodeKeyframe *key = GetSelectedKeyframes().at(i);
FloatSlider::DisplayType display = GetFloatDisplayTypeFromKeyframe(key);
key->set_value(FloatSlider::TransformDisplayToValue(FloatSlider::TransformValueToDisplay(drag_keyframe_values_.at(i).toDouble(), display) - scaled_diff, display));
}
NodeKeyframe *tip_item = GetSelectedKeyframes().first();
NodeKeyframe *tip_item = GetSelectedKeyframes().front();
bool ok;
double num_value = tip_item->value().toDouble(&ok);
@@ -472,7 +472,7 @@ void CurveView::KeyframeDragMove(QMouseEvent *event, QString &tip)
void CurveView::KeyframeDragRelease(QMouseEvent *event, MultiUndoCommand *command)
{
for (int i=0; i<GetSelectedKeyframes().size(); i++) {
for (size_t i=0; i<GetSelectedKeyframes().size(); i++) {
NodeKeyframe *k = GetSelectedKeyframes().at(i);
if (!qFuzzyCompare(k->value().toDouble(), drag_keyframe_values_.at(i).toDouble())) {
command->add_child(new NodeParamSetKeyframeValueCommand(k, k->value(), drag_keyframe_values_.at(i)));
+7 -7
View File
@@ -251,16 +251,16 @@ void CurveWidget::ConnectInputInternal(Node *node, const QString &input, int ele
void CurveWidget::SelectionChanged()
{
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
const std::vector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
SetKeyframeButtonChecked(false);
SetKeyframeButtonEnabled(!selected.isEmpty());
SetKeyframeButtonEnabled(!selected.empty());
if (!selected.isEmpty()) {
if (!selected.empty()) {
bool all_same_type = true;
NodeKeyframe::Type type = selected.first()->type();
NodeKeyframe::Type type = selected.front()->type();
for (int i=1;i<selected.size();i++) {
for (size_t i=1;i<selected.size();i++) {
NodeKeyframe* prev_item = selected.at(i-1);
NodeKeyframe* this_item = selected.at(i);
@@ -287,8 +287,8 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
}
// Get selected items and do nothing if there are none
const QVector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
if (selected.isEmpty()) {
const std::vector<NodeKeyframe*> &selected = view_->GetSelectedKeyframes();
if (selected.empty()) {
return;
}
+5 -5
View File
@@ -462,11 +462,11 @@ void KeyframeView::ShowContextMenu()
QAction* bezier_key_action = nullptr;
QAction* hold_key_action = nullptr;
if (!GetSelectedKeyframes().isEmpty()) {
if (!GetSelectedKeyframes().empty()) {
bool all_keys_are_same_type = true;
NodeKeyframe::Type type = GetSelectedKeyframes().first()->type();
NodeKeyframe::Type type = GetSelectedKeyframes().front()->type();
for (int i=1;i<GetSelectedKeyframes().size();i++) {
for (size_t i=1;i<GetSelectedKeyframes().size();i++) {
NodeKeyframe* key_item = GetSelectedKeyframes().at(i);
NodeKeyframe* prev_item = GetSelectedKeyframes().at(i-1);
@@ -507,7 +507,7 @@ void KeyframeView::ShowContextMenu()
ContextMenuEvent(m);
if (!GetSelectedKeyframes().isEmpty()) {
if (!GetSelectedKeyframes().empty()) {
m.addSeparator();
QAction* properties_action = m.addAction(tr("P&roperties"));
@@ -542,7 +542,7 @@ void KeyframeView::ShowContextMenu()
void KeyframeView::ShowKeyframePropertiesDialog()
{
if (!GetSelectedKeyframes().isEmpty()) {
if (!GetSelectedKeyframes().empty()) {
KeyframePropertiesDialog kd(GetSelectedKeyframes(), timebase(), this);
kd.exec();
}
+1 -1
View File
@@ -58,7 +58,7 @@ public:
void Clear();
const QVector<NodeKeyframe*> &GetSelectedKeyframes() const
const std::vector<NodeKeyframe*> &GetSelectedKeyframes() const
{
return selection_manager_.GetSelectedObjects();
}
+51 -42
View File
@@ -32,6 +32,7 @@
#include "node/distort/transform/transformdistortnode.h"
#include "node/factory.h"
#include "node/group/group.h"
#include "node/project/serializer/serializer.h"
#include "node/traverser.h"
#include "ui/icons/icons.h"
#include "widget/menu/menushared.h"
@@ -45,7 +46,6 @@ const double NodeView::kMinimumScale = 0.1;
NodeView::NodeView(QWidget *parent) :
HandMovableView(parent),
NodeCopyPasteService(QStringLiteral("nodes")),
drop_edge_(nullptr),
create_edge_(nullptr),
create_edge_output_item_(nullptr),
@@ -204,7 +204,31 @@ void NodeView::CopySelected(bool cut)
return;
}
CopyNodesToClipboard(selected_nodes_);
QString copy_str;
QXmlStreamWriter writer(&copy_str);
ProjectSerializer::SaveData sdata(selected_nodes_.first()->project());
sdata.SetOnlySerializeNodesAndResolveGroups(selected_nodes_);
ProjectSerializer::SerializedProperties properties;
for (Node *n : selected_nodes_) {
NodeViewItem *item = GetAssumedItemForSelectedNode(n);
if (item) {
Node::Position pos = item->GetNodePositionData();
properties[n][QStringLiteral("x")] = QString::number(pos.position.x());
properties[n][QStringLiteral("y")] = QString::number(pos.position.y());
properties[n][QStringLiteral("expanded")] = QString::number(pos.expanded);
}
}
sdata.SetProperties(properties);
ProjectSerializer::Save(&writer, sdata, QStringLiteral("nodes"));
Core::CopyStringToClipboard(copy_str);
if (cut) {
DeleteSelected();
@@ -213,9 +237,31 @@ void NodeView::CopySelected(bool cut)
void NodeView::Paste()
{
if (!contexts_.isEmpty()) {
PasteNodesFromClipboard();
if (contexts_.isEmpty()) {
return;
}
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("nodes"));
if (res.GetLoadedNodes().isEmpty()) {
return;
}
Node::PositionMap map;
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
Node::Position pos;
const QMap<QString, QString> &node_props = it.value();
pos.position.setX(node_props.value(QStringLiteral("x")).toDouble());
pos.position.setY(node_props.value(QStringLiteral("y")).toDouble());
pos.expanded = node_props.value(QStringLiteral("expanded")).toDouble();
qDebug() << it.key() << pos.position;
map.insert(it.key(), pos);
}
PostPaste(res.GetLoadedNodes(), map);
}
void NodeView::Duplicate()
@@ -1007,43 +1053,6 @@ bool NodeView::eventFilter(QObject *object, QEvent *event)
return super::eventFilter(object, event);
}
void NodeView::CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *sdata, void *userdata)
{
ProjectSerializer::SerializedProperties properties;
for (Node *n : nodes) {
NodeViewItem *item = GetAssumedItemForSelectedNode(n);
if (item) {
Node::Position pos = item->GetNodePositionData();
properties[n][QStringLiteral("x")] = QString::number(pos.position.x());
properties[n][QStringLiteral("y")] = QString::number(pos.position.y());
properties[n][QStringLiteral("expanded")] = QString::number(pos.expanded);
}
}
sdata->SetProperties(properties);
}
void NodeView::PasteNodesToClipboardCallback(const QVector<Node *> &nodes, const ProjectSerializer::LoadData &ldata, void *userdata)
{
Node::PositionMap map;
for (auto it=ldata.properties.cbegin(); it!=ldata.properties.cend(); it++) {
Node::Position pos;
const QMap<QString, QString> &node_props = it.value();
pos.position.setX(node_props.value(QStringLiteral("x")).toDouble());
pos.position.setY(node_props.value(QStringLiteral("y")).toDouble());
pos.expanded = node_props.value(QStringLiteral("expanded")).toDouble();
map.insert(it.key(), pos);
}
PostPaste(nodes, map);
}
void NodeView::changeEvent(QEvent *e)
{
// Add translation code
@@ -1548,7 +1557,7 @@ void NodeView::PostPaste(const QVector<Node *> &new_nodes, const Node::PositionM
AttachedItem &ai = new_attached[i];
if (ai.item) {
ai.original_pos = first_item->pos() - ai.item->pos();
ai.original_pos = ai.item->pos() - first_item->pos();
}
}
}
+1 -5
View File
@@ -26,7 +26,6 @@
#include "core.h"
#include "node/graph.h"
#include "node/nodecopypaste.h"
#include "nodeviewedge.h"
#include "nodeviewcontext.h"
#include "nodeviewminimap.h"
@@ -42,7 +41,7 @@ namespace olive {
* This widget takes a NodeGraph object and constructs a QGraphicsScene representing its data, viewing and allowing
* the user to make modifications to it.
*/
class NodeView : public HandMovableView, public NodeCopyPasteService
class NodeView : public HandMovableView
{
Q_OBJECT
public:
@@ -139,9 +138,6 @@ protected:
virtual bool eventFilter(QObject *object, QEvent *event) override;
virtual void CopyNodesToClipboardCallback(const QVector<Node *> &nodes, ProjectSerializer::SaveData *data, void* userdata) override;
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &ldata, void *userdata) override;
virtual void changeEvent(QEvent *e) override;
private:
@@ -48,7 +48,7 @@ public:
void DeclareDrawnObject(T *object, const QRectF &pos)
{
drawn_objects_.append({object, pos});
drawn_objects_.push_back({object, pos});
}
bool Select(T *key)
@@ -56,7 +56,7 @@ public:
Q_ASSERT(key);
if (!IsSelected(key)) {
selected_.append(key);
selected_.push_back(key);
return true;
}
@@ -67,7 +67,13 @@ public:
{
Q_ASSERT(key);
return selected_.removeOne(key);
auto it = std::find(selected_.cbegin(), selected_.cend(), key);
if (it == selected_.cend()) {
return false;
} else {
selected_.erase(it);
return true;
}
}
void ClearSelection()
@@ -77,10 +83,10 @@ public:
bool IsSelected(T *key) const
{
return selected_.contains(key);
return std::find(selected_.cbegin(), selected_.cend(), key) != selected_.cend();
}
const QVector<T*> &GetSelectedObjects() const
const std::vector<T*> &GetSelectedObjects() const
{
return selected_;
}
@@ -142,7 +148,7 @@ public:
bool IsDragging() const
{
return !dragging_.isEmpty();
return !dragging_.empty();
}
void DragStart(T *initial_item, QMouseEvent *event)
@@ -150,7 +156,7 @@ public:
initial_drag_item_ = initial_item;
dragging_.resize(selected_.size());
for (int i=0; i<selected_.size(); i++) {
for (size_t i=0; i<selected_.size(); i++) {
T *obj = selected_.at(i);
dragging_[i] = obj->time();
@@ -164,7 +170,7 @@ public:
rational time_diff = view_->SceneToTimeNoGrid(view_->mapToScene(event->pos()).x() - drag_mouse_start_.x());
// Validate movement
for (int i=0; i<selected_.size(); i++) {
for (size_t i=0; i<selected_.size(); i++) {
rational proposed_time = dragging_.at(i) + time_diff;
T *sel = selected_.at(i);
@@ -199,7 +205,7 @@ public:
}
// Apply movement
for (int i=0; i<selected_.size(); i++) {
for (size_t i=0; i<selected_.size(); i++) {
selected_.at(i)->set_time(dragging_.at(i) + time_diff);
}
@@ -219,7 +225,7 @@ public:
{
QToolTip::hideText();
for (int i=0; i<selected_.size(); i++) {
for (size_t i=0; i<selected_.size(); i++) {
command->add_child(new SetTimeCommand(selected_.at(i), selected_.at(i)->time(), dragging_.at(i)));
}
@@ -314,11 +320,11 @@ private:
TimeBasedView *view_;
using DrawnObject = QPair<T*, QRectF>;
QVector<DrawnObject> drawn_objects_;
std::vector<DrawnObject> drawn_objects_;
QVector<T*> selected_;
std::vector<T*> selected_;
QVector<rational> dragging_;
std::vector<rational> dragging_;
T *initial_drag_item_;
@@ -328,7 +334,7 @@ private:
QRubberBand *rubberband_;
QPoint rubberband_start_;
QVector<T*> rubberband_preselected_;
std::vector<T*> rubberband_preselected_;
};
+64 -71
View File
@@ -31,6 +31,7 @@
#include "dialog/sequence/sequence.h"
#include "dialog/speedduration/speeddurationdialog.h"
#include "node/block/transition/transition.h"
#include "node/project/serializer/serializer.h"
#include "tool/add.h"
#include "tool/beam.h"
#include "tool/edit.h"
@@ -60,7 +61,6 @@ namespace olive {
TimelineWidget::TimelineWidget(QWidget *parent) :
super(true, true, parent),
NodeCopyPasteService(QStringLiteral("timeline")),
rubberband_(QRubberBand::Rectangle, this),
active_tool_(nullptr),
use_audio_time_units_(false),
@@ -312,66 +312,6 @@ void TimelineWidget::DisconnectNodeEvent(ViewerOutput *n)
}
}
void TimelineWidget::CopyNodesToClipboardCallback(const QVector<Node *> &nodes, ProjectSerializer::SaveData *sdata, 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);
rational earliest_in = RATIONAL_MAX;
ProjectSerializer::SerializedProperties properties;
foreach (Block* block, selected) {
earliest_in = qMin(earliest_in, block->in());
}
foreach (Block* block, selected) {
properties[block][QStringLiteral("in")] = (block->in() - earliest_in).toString();
properties[block][QStringLiteral("track")] = block->track()->ToReference().ToString();
}
sdata->SetProperties(properties);
}
void TimelineWidget::PasteNodesToClipboardCallback(const QVector<Node *> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata)
{
bool insert = *(bool*)userdata;
MultiUndoCommand *command = new MultiUndoCommand();
foreach (Node *n, nodes) {
command->add_child(new NodeAddCommand(GetConnectedNode()->project(), n));
}
rational paste_start = GetTime();
if (insert) {
rational paste_end = GetTime();
for (auto it=load_data.properties.cbegin(); it!=load_data.properties.cend(); it++) {
rational length = static_cast<Block*>(it.key())->length();
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
paste_end = qMax(paste_end, paste_start + in + length);
}
if (paste_end != paste_start) {
InsertGapsAt(paste_start, paste_end - paste_start, command);
}
}
for (auto it=load_data.properties.cbegin(); it!=load_data.properties.cend(); it++) {
Block *block = static_cast<Block*>(it.key());
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
Track::Reference track = Track::Reference::FromString(it.value()[QStringLiteral("track")]);
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
track.index(),
block,
paste_start + in));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void TimelineWidget::SelectAll()
{
QVector<Block*> newly_selected_blocks;
@@ -633,20 +573,17 @@ void TimelineWidget::CopySelected(bool cut)
return;
}
if (ruler()->hasFocus()) {
ruler()->CopySelected(cut);
if (ruler()->hasFocus() && ruler()->CopySelected(cut)) {
return;
}
QVector<Block*> selected = GetSelectedBlocks();
if (selected.isEmpty()) {
if (selected_blocks_.isEmpty()) {
return;
}
QVector<Node*> selected_nodes;
foreach (Block* block, selected) {
foreach (Block* block, selected_blocks_) {
selected_nodes.append(block);
QVector<Node*> deps = block->GetDependencies();
@@ -658,7 +595,25 @@ void TimelineWidget::CopySelected(bool cut)
}
}
CopyNodesToClipboard(selected_nodes, &selected);
ProjectSerializer::SaveData sdata(selected_nodes.first()->project());
sdata.SetOnlySerializeNodesAndResolveGroups(selected_nodes);
// Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere
rational earliest_in = RATIONAL_MAX;
ProjectSerializer::SerializedProperties properties;
foreach (Block* block, selected_blocks_) {
earliest_in = qMin(earliest_in, block->in());
}
foreach (Block* block, selected_blocks_) {
properties[block][QStringLiteral("in")] = (block->in() - earliest_in).toString();
properties[block][QStringLiteral("track")] = block->track()->ToReference().ToString();
}
sdata.SetProperties(properties);
ProjectSerializer::Copy(sdata, QStringLiteral("timeline"));
if (cut) {
DeleteSelected();
@@ -671,12 +626,50 @@ void TimelineWidget::Paste(bool insert)
return;
}
if (ruler()->underMouse()) {
ruler()->PasteMarkers(insert, GetTime());
if (ruler()->hasFocus() && ruler()->PasteMarkers(insert, GetTime())) {
return;
}
PasteNodesFromClipboard(&insert);
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("timeline"));
if (res.GetLoadedNodes().isEmpty()) {
return;
}
MultiUndoCommand *command = new MultiUndoCommand();
foreach (Node *n, res.GetLoadedNodes()) {
command->add_child(new NodeAddCommand(GetConnectedNode()->project(), n));
}
rational paste_start = GetTime();
if (insert) {
rational paste_end = GetTime();
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
rational length = static_cast<Block*>(it.key())->length();
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
paste_end = qMax(paste_end, paste_start + in + length);
}
if (paste_end != paste_start) {
InsertGapsAt(paste_start, paste_end - paste_start, command);
}
}
for (auto it=res.GetLoadData().properties.cbegin(); it!=res.GetLoadData().properties.cend(); it++) {
Block *block = static_cast<Block*>(it.key());
rational in = rational::fromString(it.value()[QStringLiteral("in")]);
Track::Reference track = Track::Reference::FromString(it.value()[QStringLiteral("track")]);
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
track.index(),
block,
paste_start + in));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void TimelineWidget::DeleteInToOut(bool ripple)
+1 -5
View File
@@ -27,7 +27,6 @@
#include "core.h"
#include "node/block/transition/transition.h"
#include "node/nodecopypaste.h"
#include "node/output/viewer/viewer.h"
#include "timeline/timelinecommon.h"
#include "timelineandtrackview.h"
@@ -45,7 +44,7 @@ namespace olive {
*
* Encapsulates TimelineViews, TimeRulers, and scrollbars for a complete widget to manipulate Timelines
*/
class TimelineWidget : public TimeBasedWidget, public NodeCopyPasteService, public SnapService
class TimelineWidget : public TimeBasedWidget, public SnapService
{
Q_OBJECT
public:
@@ -277,9 +276,6 @@ protected:
virtual void ConnectNodeEvent(ViewerOutput* n) override;
virtual void DisconnectNodeEvent(ViewerOutput* n) override;
virtual void CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *data, void *userdata) override;
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata) override;
private:
QVector<Timeline::EditToInfo> GetEditToInfo(const rational &playhead_time, Timeline::MovementMode mode);
+59 -12
View File
@@ -28,6 +28,7 @@
#include "common/qtutils.h"
#include "core.h"
#include "dialog/markerproperties/markerpropertiesdialog.h"
#include "node/project/serializer/serializer.h"
#include "widget/colorlabelmenu/colorlabelmenu.h"
#include "widget/menu/menushared.h"
#include "widget/timebased/timebasedwidget.h"
@@ -38,7 +39,6 @@ namespace olive {
SeekableWidget::SeekableWidget(QWidget* parent) :
super(parent),
NodeCopyPasteService(QStringLiteral("markers")),
timeline_points_(nullptr),
dragging_(false),
ignore_next_focus_out_(false),
@@ -91,21 +91,68 @@ void SeekableWidget::DeleteSelected()
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void SeekableWidget::CopySelected(bool cut)
bool SeekableWidget::CopySelected(bool cut)
{
qDebug() << "COPY IS STUB";
//CopyMarkersToClipboard(selection_manager_.GetSelectedObjects());
if (!selection_manager_.GetSelectedObjects().empty()) {
ProjectSerializer::SaveData sdata(Project::GetProjectFromObject(timeline_points_));
sdata.SetOnlySerializeMarkers(selection_manager_.GetSelectedObjects());
if (cut) {
DeleteSelected();
ProjectSerializer::Copy(sdata, QStringLiteral("markers"));
if (cut) {
DeleteSelected();
}
return true;
} else {
return false;
}
}
void SeekableWidget::PasteMarkers(bool insert, rational insert_time)
bool SeekableWidget::PasteMarkers(bool insert, rational insert_time)
{
//MultiUndoCommand *command = new MultiUndoCommand();
//PasteMarkersFromClipboard(timeline_points()->markers(), command, insert_time);
qDebug() << "PASTE IS STUB";
ProjectSerializer::Result res = ProjectSerializer::Paste(QStringLiteral("markers"));
if (res == ProjectSerializer::kSuccess) {
const std::vector<TimelineMarker*> &markers = res.GetLoadData().markers;
if (!markers.empty()) {
MultiUndoCommand *command = new MultiUndoCommand();
// Normalize markers to start at playhead
rational min = RATIONAL_MAX;
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
min = qMin(min, (*it)->time());
}
min -= GetTime();
// Avoid duplicates
bool loop;
do {
loop = false;
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
rational proposed_time = (*it)->time() - min;
if (timeline_points_->markers()->GetMarkerAtTime(proposed_time)) {
min -= timebase();
loop = true;
break;
}
}
} while (loop);
for (auto it=markers.cbegin(); it!=markers.cend(); it++) {
TimelineMarker *m = *it;
m->set_time(m->time() - min);
command->add_child(new MarkerAddCommand(timeline_points_->markers(), m));
}
Core::instance()->undo_stack()->push(command);
return true;
}
}
return false;
}
void SeekableWidget::mousePressEvent(QMouseEvent *event)
@@ -148,7 +195,7 @@ void SeekableWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
super::mouseDoubleClickEvent(event);
if (selection_manager_.GetObjectAtPoint(event->pos()) && !selection_manager_.GetSelectedObjects().isEmpty()) {
if (selection_manager_.GetObjectAtPoint(event->pos()) && !selection_manager_.GetSelectedObjects().empty()) {
ShowMarkerProperties();
}
}
@@ -315,7 +362,7 @@ void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y)
bool SeekableWidget::ShowContextMenu(const QPoint &p)
{
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().isEmpty()) {
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().empty()) {
// Show marker-specific menu
Menu m;
+3 -4
View File
@@ -25,7 +25,6 @@
#include <QScrollBar>
#include "common/rational.h"
#include "node/nodecopypaste.h"
#include "timeline/timelinepoints.h"
#include "widget/menu/menu.h"
#include "widget/snapservice/snapservice.h"
@@ -33,7 +32,7 @@
namespace olive {
class SeekableWidget : public TimeBasedView, public NodeCopyPasteService
class SeekableWidget : public TimeBasedView
{
Q_OBJECT
public:
@@ -53,9 +52,9 @@ public:
void DeleteSelected();
void CopySelected(bool cut);
bool CopySelected(bool cut);
void PasteMarkers(bool insert, rational insert_time);
bool PasteMarkers(bool insert, rational insert_time);
void DeselectAllMarkers();