Make markers copy/paste-able
This commit is contained in:
@@ -78,19 +78,24 @@ void TimelineMarker::set_active(bool active)
|
||||
emit ActiveChanged(active_);
|
||||
}
|
||||
|
||||
void TimelineMarker::Save(QXmlStreamWriter* writer) const
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("name"), name_);
|
||||
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(color_));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("in"), time_.in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), time_.out().toString());
|
||||
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
|
||||
void TimelineMarkerList::Save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
foreach (TimelineMarker* marker, markers_) {
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("name"), marker->name());
|
||||
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time().out().toString());
|
||||
|
||||
writer->writeEndElement(); // marker
|
||||
marker->Save(writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
bool active();
|
||||
void set_active(bool active);
|
||||
|
||||
void Load(QXmlStreamReader* reader);
|
||||
void Save(QXmlStreamWriter* writer) const;
|
||||
|
||||
signals:
|
||||
void TimeChanged(const TimeRange& time);
|
||||
|
||||
|
||||
@@ -18,5 +18,7 @@ set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/marker/marker.h
|
||||
widget/marker/marker.cpp
|
||||
widget/marker/markercopypaste.h
|
||||
widget/marker/markercopypaste.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/***
|
||||
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 "markercopypaste.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "widget/timebased/timebasedwidget.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
void MarkerCopyPasteService::CopyMarkersToClipboard(const QVector<TimelineMarker*>& markers, void* userdata)
|
||||
{
|
||||
QString copy_str;
|
||||
|
||||
QXmlStreamWriter writer(©_str);
|
||||
writer.setAutoFormatting(true);
|
||||
|
||||
writer.writeStartDocument();
|
||||
writer.writeStartElement(QStringLiteral("olive"));
|
||||
|
||||
writer.writeTextElement(QStringLiteral("version"), QString::number(Core::kProjectVersion));
|
||||
|
||||
writer.writeStartElement(QStringLiteral("markers"));
|
||||
|
||||
// Get earliest marker for offset
|
||||
rational min_start = RATIONAL_MAX;
|
||||
foreach (TimelineMarker* marker, markers) {
|
||||
if (marker->time().in() < min_start) {
|
||||
min_start = marker->time().in();
|
||||
}
|
||||
}
|
||||
|
||||
foreach(TimelineMarker * marker, markers) {
|
||||
// Cache marker in/out points
|
||||
rational in = marker->time().in();
|
||||
rational out = marker->time().out();
|
||||
|
||||
// Temporarily set in/out to be relative to the earliest selected marker
|
||||
marker->set_time(TimeRange(in - min_start, marker->time().out() - min_start));
|
||||
marker->Save(&writer);
|
||||
|
||||
// Reset in/out
|
||||
marker->set_time(TimeRange(in, out));
|
||||
}
|
||||
|
||||
|
||||
writer.writeEndElement(); // markers
|
||||
writer.writeEndElement(); // olive
|
||||
writer.writeEndDocument();
|
||||
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
}
|
||||
|
||||
void MarkerCopyPasteService::PasteMarkersFromClipboard(TimelineMarkerList* list, MultiUndoCommand* command,
|
||||
rational offset) {
|
||||
QString clipboard = Core::PasteStringFromClipboard();
|
||||
|
||||
if (clipboard.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(clipboard);
|
||||
uint data_version = 0;
|
||||
|
||||
QVector<TimelineMarker*> pasted_markers;
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("olive")) {
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("version")) {
|
||||
data_version = reader.readElementText().toUInt();
|
||||
} else if (reader.name() == QStringLiteral("markers")) {
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (data_version == 0) {
|
||||
return;
|
||||
}
|
||||
QString name;
|
||||
int color;
|
||||
rational in, out;
|
||||
|
||||
XMLAttributeLoop((&reader), attr) {
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
name = attr.value().toString();
|
||||
}
|
||||
|
||||
if (attr.name() == QStringLiteral("color")) {
|
||||
color = attr.value().toInt();
|
||||
}
|
||||
|
||||
if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
}
|
||||
|
||||
if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
command->add_child(new TimeBasedWidget::MarkerAddCommand(Core::instance()->GetActiveProject(),
|
||||
list,
|
||||
TimeRange(in + offset, out + offset),
|
||||
name,
|
||||
color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
} //namespace olive
|
||||
@@ -0,0 +1,40 @@
|
||||
/***
|
||||
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 MARKERCOPYPASTEWIDGET_H
|
||||
#define MARKERCOPYPASTEWIDGET_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
|
||||
#include "widget/marker/marker.h"
|
||||
#include "timeline/timelinemarker.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class MarkerCopyPasteService
|
||||
{
|
||||
public:
|
||||
MarkerCopyPasteService() = default;
|
||||
|
||||
protected:
|
||||
void CopyMarkersToClipboard(const QVector<TimelineMarker*> &markers, void* userdata = nullptr);
|
||||
|
||||
void PasteMarkersFromClipboard(TimelineMarkerList* list, MultiUndoCommand *command, rational offset);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MARKERCOPYPASTEWIDGET_H
|
||||
@@ -665,11 +665,12 @@ void TimeBasedWidget::DeleteSelected()
|
||||
}
|
||||
}
|
||||
|
||||
TimeBasedWidget::MarkerAddCommand::MarkerAddCommand(Project *project, TimelineMarkerList *marker_list, const TimeRange &range, const QString &name) :
|
||||
TimeBasedWidget::MarkerAddCommand::MarkerAddCommand(Project *project, TimelineMarkerList *marker_list, const TimeRange &range, const QString &name, int color) :
|
||||
project_(project),
|
||||
marker_list_(marker_list),
|
||||
range_(range),
|
||||
name_(name)
|
||||
name_(name),
|
||||
color_(color)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -680,7 +681,7 @@ Project *TimeBasedWidget::MarkerAddCommand::GetRelevantProject() const
|
||||
|
||||
void TimeBasedWidget::MarkerAddCommand::redo()
|
||||
{
|
||||
added_marker_ = marker_list_->AddMarker(range_, name_);
|
||||
added_marker_ = marker_list_->AddMarker(range_, name_, color_);
|
||||
}
|
||||
|
||||
void TimeBasedWidget::MarkerAddCommand::undo()
|
||||
|
||||
@@ -55,6 +55,27 @@ public:
|
||||
virtual bool eventFilter(QObject* object, QEvent* event) override;
|
||||
|
||||
// Temp file location
|
||||
|
||||
class MarkerAddCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerAddCommand(Project* project, TimelineMarkerList* marker_list, const TimeRange& range, const QString& name, int color = -1);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Project* project_;
|
||||
TimelineMarkerList* marker_list_;
|
||||
TimeRange range_;
|
||||
QString name_;
|
||||
int color_;
|
||||
|
||||
TimelineMarker* added_marker_;
|
||||
};
|
||||
|
||||
class MarkerRemoveCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerRemoveCommand(Project* project, TimelineMarker* marker, TimelineMarkerList* marker_list);
|
||||
@@ -163,26 +184,7 @@ signals:
|
||||
void ConnectedNodeChanged(ViewerOutput* old, ViewerOutput* now);
|
||||
|
||||
private:
|
||||
class MarkerAddCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
MarkerAddCommand(Project* project, TimelineMarkerList* marker_list, const TimeRange& range, const QString& name);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Project* project_;
|
||||
TimelineMarkerList* marker_list_;
|
||||
TimeRange range_;
|
||||
QString name_;
|
||||
|
||||
TimelineMarker* added_marker_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set either in or out point to the current playhead
|
||||
|
||||
@@ -378,6 +378,15 @@ void TimelineWidget::DeselectAll()
|
||||
SignalDeselectedAllBlocks();
|
||||
}
|
||||
|
||||
bool TimelineWidget::MarkersActive()
|
||||
{
|
||||
if (ruler()->GetActiveTimelineMarkers().size() > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::RippleToIn()
|
||||
{
|
||||
RippleTo(Timeline::kTrimIn);
|
||||
@@ -475,7 +484,7 @@ void TimelineWidget::ReplaceBlocksWithGaps(const QVector<Block *> &blocks,
|
||||
|
||||
void TimelineWidget::DeleteSelected(bool ripple)
|
||||
{
|
||||
if (ruler()->GetActiveTimelineMarkers().size() > 0) {
|
||||
if (MarkersActive()) {
|
||||
ruler()->DeleteSelected();
|
||||
return;
|
||||
}
|
||||
@@ -598,6 +607,12 @@ void TimelineWidget::CopySelected(bool cut)
|
||||
return;
|
||||
}
|
||||
|
||||
if (MarkersActive()) {
|
||||
ruler()->CopySelected(cut);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QVector<Block*> selected = GetSelectedBlocks();
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
@@ -631,6 +646,11 @@ void TimelineWidget::Paste(bool insert)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ruler()->underMouse()) {
|
||||
ruler()->PasteMarkers(insert, GetTime());
|
||||
return;
|
||||
}
|
||||
|
||||
MultiUndoCommand* command = new MultiUndoCommand();
|
||||
|
||||
QVector<BlockPasteData> paste_data;
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
|
||||
void DeselectAll();
|
||||
|
||||
bool MarkersActive();
|
||||
|
||||
void RippleToIn();
|
||||
|
||||
void RippleToOut();
|
||||
|
||||
@@ -106,6 +106,21 @@ const int &SeekableWidget::GetScroll() const
|
||||
return scroll_;
|
||||
}
|
||||
|
||||
void SeekableWidget::CopySelected(bool cut)
|
||||
{
|
||||
CopyMarkersToClipboard(GetActiveTimelineMarkers());
|
||||
|
||||
if (cut) {
|
||||
DeleteSelected();
|
||||
}
|
||||
}
|
||||
|
||||
void SeekableWidget::PasteMarkers(bool insert, rational insert_time)
|
||||
{
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
PasteMarkersFromClipboard(timeline_points()->markers(), command, insert_time);
|
||||
}
|
||||
|
||||
void SeekableWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
|
||||
@@ -28,10 +28,11 @@
|
||||
#include "widget/snapservice/snapservice.h"
|
||||
#include "widget/timebased/timescaledobject.h"
|
||||
#include "widget/marker/marker.h"
|
||||
#include "widget/marker/markercopypaste.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class SeekableWidget : public TimelineScaledWidget
|
||||
class SeekableWidget : public TimelineScaledWidget, public MarkerCopyPasteService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -55,6 +56,10 @@ public:
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
void CopySelected(bool cut);
|
||||
|
||||
void PasteMarkers(bool insert, rational insert_time);
|
||||
|
||||
QVector<TimelineMarker*> GetActiveTimelineMarkers();
|
||||
|
||||
void DeselectAllMarkers();
|
||||
|
||||
Reference in New Issue
Block a user