ported seekablewidget to timebasedview

Cuts down on a lot of code duplication and opens up usage of the new TimelineViewSelectionManager framework
This commit is contained in:
itsmattkc
2022-05-01 15:45:20 -07:00
parent f04ff5f1ff
commit cdcd83c09a
32 changed files with 425 additions and 1213 deletions
+2 -11
View File
@@ -80,18 +80,9 @@ NodeGraph *Node::parent() const
return static_cast<NodeGraph*>(QObject::parent());
}
Project* Node::project() const
Project *Node::project() const
{
QObject *t = this->parent();
while (t) {
if (Project *p = dynamic_cast<Project*>(t)) {
return p;
}
t = t->parent();
}
return nullptr;
return Project::GetProjectFromObject(this);
}
QString Node::ShortName() const
+14
View File
@@ -169,6 +169,20 @@ void Project::RegenerateUuid()
uuid_ = QUuid::createUuid();
}
Project *Project::GetProjectFromObject(const QObject *o)
{
QObject *t = o->parent();
while (t) {
if (Project *p = dynamic_cast<Project*>(t)) {
return p;
}
t = t->parent();
}
return nullptr;
}
void Project::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range)
{
Q_UNUSED(input)
+8
View File
@@ -109,6 +109,14 @@ public:
saved_url_ = url;
}
/**
* @brief Find project parent from object
*
* If an object is expected to be a child of a project, this function will traverse its parent
* tree until it finds it.
*/
static Project *GetProjectFromObject(const QObject *o);
signals:
void NameChanged();
@@ -20,6 +20,7 @@
#include "serializer210528.h"
#include "config/config.h"
#include "node/factory.h"
namespace olive {
@@ -604,7 +605,7 @@ void ProjectSerializer210528::LoadMarkerList(QXmlStreamReader *reader, TimelineM
}
}
markers->AddMarker(TimeRange(in, out), name);
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
}
reader->skipCurrentElement();
@@ -20,6 +20,7 @@
#include "serializer210907.h"
#include "config/config.h"
#include "node/factory.h"
namespace olive {
@@ -596,7 +597,7 @@ void ProjectSerializer210907::LoadMarkerList(QXmlStreamReader *reader, TimelineM
}
}
markers->AddMarker(TimeRange(in, out), name);
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
}
reader->skipCurrentElement();
@@ -20,6 +20,7 @@
#include "serializer211228.h"
#include "config/config.h"
#include "node/factory.h"
namespace olive {
@@ -646,7 +647,7 @@ void ProjectSerializer211228::LoadMarkerList(QXmlStreamReader *reader, TimelineM
}
}
markers->AddMarker(TimeRange(in, out), name);
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
}
reader->skipCurrentElement();
@@ -20,6 +20,7 @@
#include "serializer220403.h"
#include "config/config.h"
#include "node/factory.h"
namespace olive {
@@ -1001,7 +1002,7 @@ void ProjectSerializer220403::LoadMarkerList(QXmlStreamReader *reader, TimelineM
}
}
markers->AddMarker(TimeRange(in, out), name);
new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers);
}
reader->skipCurrentElement();
+128 -75
View File
@@ -23,21 +23,15 @@
#include "common/xmlutils.h"
#include "config/config.h"
#include "core.h"
#include "widget/marker/markerundo.h"
namespace olive {
TimelineMarker::TimelineMarker(const TimeRange &time, const QString &name, QObject *parent) :
TimelineMarker::TimelineMarker(int color, const TimeRange &time, const QString &name, QObject *parent) :
QObject(parent),
time_(time),
name_(name)
name_(name),
color_(color)
{
color_ = Config::Current()[QStringLiteral("MarkerColor")].toInt();
}
const TimeRange &TimelineMarker::time() const
{
return time_;
}
void TimelineMarker::set_time(const TimeRange &time)
@@ -46,35 +40,12 @@ void TimelineMarker::set_time(const TimeRange &time)
emit TimeChanged(time_);
}
void TimelineMarker::set_time_undo(TimeRange time) {
UndoCommand *command = new MarkerChangeTimeCommand(Core::instance()->GetActiveProject(), this, time);
Core::instance()->undo_stack()->push(command);
}
const QString &TimelineMarker::name() const
{
return name_;
}
void TimelineMarker::set_name(const QString &name)
{
name_ = name;
emit NameChanged(name_);
}
void TimelineMarker::set_name_undo(QString name)
{
UndoCommand *command = new MarkerChangeNameCommand(Core::instance()->GetActiveProject(), this, name);
Core::instance()->undo_stack()->push(command);
}
int TimelineMarker::color()
{
return color_;
}
void TimelineMarker::set_color(int c)
{
color_ = c;
@@ -82,51 +53,133 @@ void TimelineMarker::set_color(int c)
emit ColorChanged(color_);
}
bool TimelineMarker::active()
{
return active_;
}
void TimelineMarker::set_active(bool active)
{
active_ = active;
emit ActiveChanged(active_);
}
TimelineMarkerList::~TimelineMarkerList()
{
qDeleteAll(markers_);
}
TimelineMarker* TimelineMarkerList::AddMarker(const TimeRange &time, const QString &name, int color)
{
TimelineMarker* m = new TimelineMarker(time, name);
if (color >= 0) {
m->set_color(color);
}
markers_.append(m);
emit MarkerAdded(m);
return m;
}
void TimelineMarkerList::RemoveMarker(TimelineMarker *marker)
{
for (int i=0;i<markers_.size();i++) {
TimelineMarker* m = markers_.at(i);
if (m == marker) {
markers_.removeAt(i);
emit MarkerRemoved(m);
delete m;
break;
}
}
}
const QList<TimelineMarker*> &TimelineMarkerList::list() const
const std::vector<TimelineMarker*> &TimelineMarkerList::list() const
{
return markers_;
}
void TimelineMarkerList::childEvent(QChildEvent *e)
{
QObject::childEvent(e);
if (TimelineMarker *marker = dynamic_cast<TimelineMarker *>(e->child())) {
if (e->type() == QChildEvent::ChildAdded) {
markers_.push_back(marker);
} else if (e->type() == QChildEvent::ChildRemoved) {
auto it = std::find(markers_.begin(), markers_.end(), marker);
if (it != markers_.end()) {
markers_.erase(it);
}
}
}
}
MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list, const TimeRange &range, const QString &name, int color) :
marker_list_(marker_list)
{
added_marker_ = new TimelineMarker(color, range, name, &memory_manager_);
}
Project* MarkerAddCommand::GetRelevantProject() const
{
return Project::GetProjectFromObject(marker_list_);
}
void MarkerAddCommand::redo()
{
added_marker_->setParent(marker_list_);
}
void MarkerAddCommand::undo()
{
added_marker_->setParent(&memory_manager_);
}
MarkerRemoveCommand::MarkerRemoveCommand(TimelineMarker *marker) :
marker_(marker)
{
}
Project* MarkerRemoveCommand::GetRelevantProject() const
{
return Project::GetProjectFromObject(marker_list_);
}
void MarkerRemoveCommand::redo()
{
marker_list_ = marker_->parent();
marker_->setParent(&memory_manager_);
}
void MarkerRemoveCommand::undo()
{
marker_->setParent(marker_list_);
}
MarkerChangeColorCommand::MarkerChangeColorCommand(TimelineMarker *marker, int new_color) :
marker_(marker),
new_color_(new_color)
{
}
Project* MarkerChangeColorCommand::GetRelevantProject() const
{
return Project::GetProjectFromObject(marker_);
}
void MarkerChangeColorCommand::redo()
{
old_color_ = marker_->color();
marker_->set_color(new_color_);
}
void MarkerChangeColorCommand::undo()
{
marker_->set_color(old_color_);
}
MarkerChangeNameCommand::MarkerChangeNameCommand(TimelineMarker *marker, QString new_name) :
marker_(marker),
new_name_(new_name)
{
}
Project* MarkerChangeNameCommand::GetRelevantProject() const
{
return Project::GetProjectFromObject(marker_);
}
void MarkerChangeNameCommand::redo()
{
old_name_ = marker_->name();
marker_->set_name(new_name_);
}
void MarkerChangeNameCommand::undo()
{
marker_->set_name(old_name_);
}
MarkerChangeTimeCommand::MarkerChangeTimeCommand(TimelineMarker* marker, TimeRange time) :
marker_(marker),
new_time_(time)
{
}
Project* MarkerChangeTimeCommand::GetRelevantProject() const
{
return Project::GetProjectFromObject(marker_);
}
void MarkerChangeTimeCommand::redo()
{
old_time_ = marker_->time();
marker_->set_time(new_time_);
}
void MarkerChangeTimeCommand::undo()
{
marker_->set_time(old_time_);
}
}
+106 -26
View File
@@ -26,6 +26,7 @@
#include <QXmlStreamWriter>
#include "common/timerange.h"
#include "undo/undocommand.h"
namespace olive {
@@ -33,26 +34,17 @@ class TimelineMarker : public QObject
{
Q_OBJECT
public:
TimelineMarker(const TimeRange& time = TimeRange(), const QString& name = QString(), QObject* parent = nullptr);
TimelineMarker(int color, const TimeRange& time, const QString& name = QString(), QObject* parent = nullptr);
const TimeRange &time() const;
const TimeRange &time() const { return time_; }
void set_time(const TimeRange& time);
const QString& name() const;
const QString& name() const { return name_; }
void set_name(const QString& name);
int color();
int color() const { return color_; }
void set_color(int c);
bool active();
void set_active(bool active);
void Load(QXmlStreamReader* reader);
public slots:
void set_name_undo(QString name);
void set_time_undo(TimeRange time);
signals:
void TimeChanged(const TimeRange& time);
@@ -60,8 +52,6 @@ signals:
void ColorChanged(int c);
void ActiveChanged(bool active);
private:
TimeRange time_;
@@ -69,31 +59,121 @@ private:
int color_;
bool active_;
};
class TimelineMarkerList : public QObject
{
Q_OBJECT
public:
TimelineMarkerList() = default;
TimelineMarkerList(QObject *parent = nullptr) :
QObject(parent)
{
}
virtual ~TimelineMarkerList() override;
TimelineMarker* AddMarker(const TimeRange& time = TimeRange(), const QString& name = QString(), int color = -1);
void RemoveMarker(TimelineMarker* marker);
const QList<TimelineMarker *> &list() const;
const std::vector<TimelineMarker *> &list() const;
signals:
void MarkerAdded(TimelineMarker* marker);
void MarkerRemoved(TimelineMarker* marker);
protected:
virtual void childEvent(QChildEvent *e) override;
private:
QList<TimelineMarker*> markers_;
std::vector<TimelineMarker*> markers_;
};
class MarkerAddCommand : public UndoCommand {
public:
MarkerAddCommand(TimelineMarkerList* marker_list, const TimeRange& range, const QString& name, int color);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
TimelineMarkerList* marker_list_;
TimeRange range_;
QString name_;
int color_;
TimelineMarker* added_marker_;
QObject memory_manager_;
};
class MarkerRemoveCommand : public UndoCommand {
public:
MarkerRemoveCommand(TimelineMarker* marker);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
TimelineMarker* marker_;
QObject* marker_list_;
TimeRange range_;
QString name_;
int color_;
QObject memory_manager_;
};
class MarkerChangeColorCommand : public UndoCommand {
public:
MarkerChangeColorCommand(TimelineMarker* marker, int new_color);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
TimelineMarker* marker_;
int old_color_;
int new_color_;
};
class MarkerChangeNameCommand : public UndoCommand {
public:
MarkerChangeNameCommand(TimelineMarker* marker, QString name);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
TimelineMarker* marker_;
QString old_name_;
QString new_name_;
};
class MarkerChangeTimeCommand : public UndoCommand {
public:
MarkerChangeTimeCommand(TimelineMarker* marker, TimeRange time);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
TimelineMarker* marker_;
TimeRange old_time_;
TimeRange new_time_;
};
+11 -4
View File
@@ -24,24 +24,31 @@
namespace olive {
TimelinePoints::TimelinePoints(QObject *parent) :
QObject(parent)
{
markers_ = new TimelineMarkerList(this);
workarea_ = new TimelineWorkArea(this);
}
TimelineMarkerList *TimelinePoints::markers()
{
return &markers_;
return markers_;
}
const TimelineMarkerList *TimelinePoints::markers() const
{
return &markers_;
return markers_;
}
const TimelineWorkArea *TimelinePoints::workarea() const
{
return &workarea_;
return workarea_;
}
TimelineWorkArea *TimelinePoints::workarea()
{
return &workarea_;
return workarea_;
}
}
+5 -4
View File
@@ -29,10 +29,11 @@
namespace olive {
class TimelinePoints
class TimelinePoints : public QObject
{
Q_OBJECT
public:
TimelinePoints() = default;
TimelinePoints(QObject *parent = nullptr);
TimelineMarkerList* markers();
const TimelineMarkerList* markers() const;
@@ -41,9 +42,9 @@ public:
const TimelineWorkArea* workarea() const;
private:
TimelineMarkerList markers_;
TimelineMarkerList *markers_;
TimelineWorkArea workarea_;
TimelineWorkArea *workarea_;
};
-1
View File
@@ -29,7 +29,6 @@ add_subdirectory(focusablelineedit)
add_subdirectory(handmovableview)
add_subdirectory(keyframeview)
add_subdirectory(manageddisplay)
add_subdirectory(marker)
add_subdirectory(menu)
add_subdirectory(nodecombobox)
add_subdirectory(nodeparamview)
-26
View File
@@ -1,26 +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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/marker/marker.h
widget/marker/marker.cpp
widget/marker/markercopypaste.h
widget/marker/markercopypaste.cpp
widget/marker/markerundo.h
widget/marker/markerundo.cpp
PARENT_SCOPE
)
-263
View File
@@ -1,263 +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 "marker.h"
#include <QInputDialog>
#include <QPainter>
#include "config/config.h"
#include "common/qtutils.h"
#include "panel/panelmanager.h"
#include "panel/timeline/timeline.h"
#include "ui/colorcoding.h"
#include "widget/menu/menu.h"
#include "widget/menu/menushared.h"
#include "widget/timeruler/seekablewidget.h"
#include "widget/timelinewidget/timelinewidget.h"
namespace olive {
Marker::Marker(QWidget *parent) :
QWidget(parent),
active_(false),
drag_allowed_(false),
dragging_(false)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QFontMetrics fm = fontMetrics();
marker_height_ = fm.height();
marker_width_ = QtUtils::QFontMetricsWidth(fm, "H");
resize(marker_width_, marker_height_);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &Marker::customContextMenuRequested, this, &Marker::ShowContextMenu);
}
void Marker::SetActive(bool active)
{
active_ = active;
// Generaly the same functions delete both markers and timeline blocks. This helps ensure that
// markers and timeline blocks can never be selected at the same time
if (active) {
TimelinePanel *timeline = PanelManager::instance()->MostRecentlyFocused<TimelinePanel>();
if (timeline) {
timeline->timeline_widget()->DeselectAll();
}
}
update();
}
bool Marker::active()
{
return active_;
}
void Marker::paintEvent(QPaintEvent *event)
{
QFontMetrics fm = fontMetrics();
int y = marker_height_;
int half_width = marker_width_ / 2;
int x = half_width;
QPainter p(this);
if (active_) {
p.setPen(Qt::white);
} else {
p.setPen(Qt::black);
}
QColor color = ColorCoding::GetColor(marker_color_).toQColor();
p.setBrush(color);
p.setRenderHint(QPainter::Antialiasing);
int half_marker_height = marker_height_ / 3;
QPoint points[] = {
QPoint(x, y),
QPoint(x - half_width, y - half_marker_height),
QPoint(x - half_width, y - marker_height_),
QPoint(x + 1 + half_width, y - marker_height_),
QPoint(x + 1 + half_width, y - half_marker_height),
QPoint(x + 1, y),
};
p.drawPolygon(points, 6);
if (!name_.isEmpty()) {
resize(marker_width_ + fm.horizontalAdvance(name_) + fm.horizontalAdvance(" "), marker_height_);
// Draw background rectangle
color.setAlphaF(0.5);
p.fillRect(x, y, fm.horizontalAdvance(name_) + fm.horizontalAdvance(" ") * 2 + half_width, -marker_height_, color);
// Draw text
p.drawText(x + marker_width_, y - half_marker_height, name_);
} else {
resize(marker_width_, marker_height_);
}
// In case this is a clip marker, redraw the timeline to update the clip marker
TimelinePanel* timeline = PanelManager::instance()->MostRecentlyFocused<TimelinePanel>();
if (timeline) {
timeline->timeline_widget()->Refresh();
}
}
void Marker::mousePressEvent(QMouseEvent* e)
{
// Only select if clicking on the icon and not the label
if (e->pos().x() > marker_width_) {
return;
}
if (e->button() == Qt::LeftButton || e->button() == Qt::RightButton) {
SeekableParent()->SeekToScreenPoint(this->x() + 4);
if (!active_) {
if (e->modifiers() != Qt::ShiftModifier) {
SeekableParent()->DeselectAllMarkers();
}
emit ActiveChanged(true);
} else {
if (e->modifiers() == Qt::ShiftModifier) {
emit ActiveChanged(false);
}
}
update();
}
if (e->button() == Qt::LeftButton) {
click_position_ = e->globalPos();
marker_start_x_ = x();
drag_allowed_ = true;
}
}
void Marker::mouseMoveEvent(QMouseEvent* e)
{
if (drag_allowed_) {
dragging_ = true;
int new_position = marker_start_x_ + e->globalPos().x() - click_position_.x();
rational marker_time = SeekableParent()->ScreenToTime(new_position);
if (SeekableParent()->GetSnapService()) {
if (Core::instance()->snapping()) {
rational movement;
SeekableParent()->GetSnapService()->SnapPoint({marker_time}, &movement);
if (!movement.isNull()) {
marker_time += movement;
}
new_position = SeekableParent()->TimeToScene(marker_time);
}
}
if (new_position > -marker_width_ / 2 && new_position < SeekableParent()->width() - marker_width_ / 2) {
this->move(new_position-2, this->pos().y());
repaint();
}
}
}
void Marker::mouseReleaseEvent(QMouseEvent* e)
{
if (dragging_) {
rational time = SeekableParent()->SceneToTime(this->x() + 4);
time = time < 0.0 ? 0.0 : time;
emit TimeChanged(TimeRange(time, time));
dragging_ = false;
}
drag_allowed_ = false;
}
SeekableWidget* Marker::SeekableParent()
{
return dynamic_cast<SeekableWidget *>(parent());
}
void Marker::ShowContextMenu()
{
// Only show context menu if we clicked on the icon and not the label
QRect marker_icon(0, 0, marker_width_, marker_height_);
if (!marker_icon.contains(this->mapFromGlobal(QCursor::pos()))) {
return;
}
Menu m(this);
// Color menu
ColorLabelMenu color_coding_menu;
connect(&color_coding_menu, &ColorLabelMenu::ColorSelected, this, &Marker::ColorChanged);
m.addMenu(&color_coding_menu);
m.addSeparator();
MenuShared::instance()->AddItemsForEditMenu(&m, false);
m.addSeparator();
QAction rename;
rename.setText(tr("Rename"));
m.addAction(&rename);
connect(&rename, &QAction::triggered, this, &Marker::Rename);
m.exec(QCursor::pos());
}
void Marker::Rename()
{
bool ok;
QString marker_name = QInputDialog::getText(this, tr("Set Marker"), tr("Marker name:"), QLineEdit::Normal, name_, &ok);
if (ok) {
emit NameChanged(marker_name);
}
}
void Marker::SetColor(int c)
{
marker_color_ = c;
update();
}
void Marker::SetName(QString s)
{
name_ = s;
update();
}
void Marker::SetTime(TimeRange time)
{
move(SeekableParent()->TimeToScene(time.in())-2, y());
}
} // namespace olive
-92
View File
@@ -1,92 +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 MARKER_H
#define MARKER_H
#include <QWidget>
#include <QMouseEvent>
#include <QPushButton>
#include "common/define.h"
#include "common/timerange.h"
#include "widget/colorlabelmenu/colorlabelmenu.h"
namespace olive {
class SeekableWidget;
class Marker : public QWidget {
Q_OBJECT
public:
Marker(QWidget* parent = nullptr);
bool active();
void Rename();
SeekableWidget* SeekableParent();
public slots:
void SetColor(int c);
void SetActive(bool active);
void SetName(QString s);
void SetTime(TimeRange t);
protected:
void paintEvent(QPaintEvent* event) override;
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* event) override;
signals:
void ColorChanged(int c);
void markerSelected(Marker* marker);
void ActiveChanged(bool active);
void NameChanged(QString name);
void TimeChanged(TimeRange time);
private:
int marker_color_;
bool active_;
QString name_;
QPointF click_position_;
int marker_start_x_;
bool drag_allowed_;
bool dragging_;
int marker_height_;
int marker_width_;
private slots:
void ShowContextMenu();
};
} // namespace olive
#endif // MARKER_H
-136
View File
@@ -1,136 +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 "markercopypaste.h"
#include <QMessageBox>
#include "core.h"
#include "markerundo.h"
#include "widget/timebased/timebasedwidget.h"
namespace olive {
void MarkerCopyPasteService::CopyMarkersToClipboard(const QVector<TimelineMarker*>& markers, void* userdata)
{
QString copy_str;
QXmlStreamWriter writer(&copy_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;
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 = -1;
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 MarkerAddCommand(Core::instance()->GetActiveProject(),
list,
TimeRange(in + offset, out + offset),
name,
color));
}
}
}
}
}
if (reader.hasError()) {
// If this was NOT an internal error, we assume it's an XML error that the user needs to know about
QMessageBox::critical((QWidget*)Core::instance()->main_window(),
QCoreApplication::translate("MarkerCopyPasteWidget", "Error pasting markers"),
QCoreApplication::translate("MarkerCopyPasteWidget", "Failed to paste markers: %1").arg(reader.errorString()),
QMessageBox::Ok);
return;
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
} //namespace olive
-42
View File
@@ -1,42 +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 MARKERCOPYPASTEWIDGET_H
#define MARKERCOPYPASTEWIDGET_H
#include <QWidget>
#include <QUndoCommand>
#include "widget/marker/marker.h"
#include "node/project/serializer/serializer.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
-138
View File
@@ -1,138 +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 "markerundo.h"
namespace olive {
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),
color_(color)
{
}
Project* MarkerAddCommand::GetRelevantProject() const
{
return project_;
}
void MarkerAddCommand::redo()
{
added_marker_ = marker_list_->AddMarker(range_, name_, color_);
}
void MarkerAddCommand::undo()
{
marker_list_->RemoveMarker(added_marker_);
}
MarkerRemoveCommand::MarkerRemoveCommand(Project *project, TimelineMarker *marker, TimelineMarkerList *marker_list) :
project_(project),
marker_(marker),
marker_list_(marker_list),
range_(marker->time()),
name_(marker->name()),
color_(marker->color())
{
}
Project* MarkerRemoveCommand::GetRelevantProject() const
{
return project_;
}
void MarkerRemoveCommand::redo()
{
marker_list_->RemoveMarker(marker_);
}
void MarkerRemoveCommand::undo()
{
marker_list_->AddMarker(range_, name_, color_);
}
MarkerChangeColorCommand::MarkerChangeColorCommand(Project *project, TimelineMarker *marker, int new_color) :
project_(project),
marker_(marker),
old_color_(marker->color()),
new_color_(new_color)
{
}
Project* MarkerChangeColorCommand::GetRelevantProject() const
{
return project_;
}
void MarkerChangeColorCommand::redo()
{
marker_->set_color(new_color_);
}
void MarkerChangeColorCommand::undo()
{
marker_->set_color(old_color_);
}
MarkerChangeNameCommand::MarkerChangeNameCommand(Project *project, TimelineMarker *marker, QString new_name) :
project_(project),
marker_(marker),
old_name_(marker->name()),
new_name_(new_name)
{
}
Project* MarkerChangeNameCommand::GetRelevantProject() const
{
return project_;
}
void MarkerChangeNameCommand::redo()
{
marker_->set_name(new_name_);
}
void MarkerChangeNameCommand::undo()
{
marker_->set_name(old_name_);
}
MarkerChangeTimeCommand::MarkerChangeTimeCommand(Project* project, TimelineMarker* marker, TimeRange time) :
project_(project),
marker_(marker),
old_time_(marker->time()),
new_time_(time)
{
}
Project* MarkerChangeTimeCommand::GetRelevantProject() const
{
return project_;
}
void MarkerChangeTimeCommand::redo()
{
marker_->set_time(new_time_);
}
void MarkerChangeTimeCommand::undo()
{
marker_->set_time(old_time_);
}
}
-119
View File
@@ -1,119 +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 MARKERUNDO_H
#define MARKERUNDO_H
#include "undo/undocommand.h"
#include "timeline/timelinemarker.h"
namespace olive {
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);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
Project* project_;
TimelineMarker* marker_;
TimelineMarkerList* marker_list_;
TimeRange range_;
QString name_;
int color_;
};
class MarkerChangeColorCommand : public UndoCommand {
public:
MarkerChangeColorCommand(Project* project, TimelineMarker* marker, int new_color);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
Project* project_;
TimelineMarker* marker_;
int old_color_;
int new_color_;
};
class MarkerChangeNameCommand : public UndoCommand {
public:
MarkerChangeNameCommand(Project* project, TimelineMarker* marker, QString name);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
Project* project_;
TimelineMarker* marker_;
QString old_name_;
QString new_name_;
};
class MarkerChangeTimeCommand : public UndoCommand {
public:
MarkerChangeTimeCommand(Project* project, TimelineMarker* marker, TimeRange time);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override;
virtual void undo() override;
private:
Project* project_;
TimelineMarker* marker_;
TimeRange old_time_;
TimeRange new_time_;
};
}
#endif // TIMELINEUNDOTRACK_H
@@ -77,7 +77,7 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
if (points_
&& !timebase().isNull()
&& (points_->workarea()->enabled() || !points_->markers()->list().isEmpty())) {
&& (points_->workarea()->enabled() || !points_->markers()->list().empty())) {
QStyleOptionSlider opt;
initStyleOption(&opt);
@@ -110,7 +110,7 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
workarea_color);
}
if (!points_->markers()->list().isEmpty()) {
if (!points_->markers()->list().empty()) {
foreach (TimelineMarker* marker, points_->markers()->list()) {
QColor marker_color = ColorCoding::GetColor(marker->color()).toQColor();
int64_t in = qRound64(ratio * TimeToScene(marker->time().in()));
+3 -5
View File
@@ -43,6 +43,9 @@ public:
return snapped_;
}
const rational &GetTime() const { return playhead_; }
SnapService *GetSnapService() const { return snap_service_; }
void SetSnapService(SnapService* service);
const double& GetYScale() const;
@@ -85,11 +88,6 @@ protected:
virtual void ZoomIntoCursorPosition(QWheelEvent *event, double multiplier, const QPointF &cursor_pos) override;
const rational &GetPlayheadTime() const
{
return playhead_;
}
bool PlayheadPress(QMouseEvent* event);
bool PlayheadMove(QMouseEvent* event);
bool PlayheadRelease(QMouseEvent* event);
+15 -5
View File
@@ -27,7 +27,6 @@
#include "config/config.h"
#include "core.h"
#include "node/project/sequence/sequence.h"
#include "widget/marker/markerundo.h"
#include "widget/timelinewidget/undo/timelineundoworkarea.h"
namespace olive {
@@ -40,7 +39,7 @@ TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_statu
auto_set_timebase_(true)
{
ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this);
connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal);
ConnectTimelineView(ruler_, true);
scrollbar_ = new ResizableTimelineScrollBar(Qt::Horizontal, this);
connect(scrollbar_, &ResizableScrollBar::ResizeBegan, this, &TimeBasedWidget::ScrollBarResizeBegan);
@@ -593,14 +592,25 @@ void TimeBasedWidget::SetMarker()
QString marker_name;
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
marker_name = QInputDialog::getText(this, tr("Set Marker"), tr("Marker name:"), QLineEdit::Normal, QString(), &ok);
marker_name = QInputDialog::getText(this, tr("Add Marker"), tr("Name:"), QLineEdit::Normal, QString(), &ok);
} else {
ok = true;
}
if (ok) {
Core::instance()->undo_stack()->push(new MarkerAddCommand(GetConnectedNode()->project(),
GetConnectedNode()->GetTimelinePoints()->markers(), TimeRange(GetTime(), GetTime()), marker_name));
int color;
TimelineMarkerList *markers = GetConnectedNode()->GetTimelinePoints()->markers();
if (!markers->list().empty()) {
// Use last invoked color if applicable
color = markers->list().back()->color();
} else {
// Fallback to default color in preferences
color = Config::Current()[QStringLiteral("MarkerColor")].toInt();
}
Core::instance()->undo_stack()->push(new MarkerAddCommand(markers, TimeRange(GetTime(), GetTime()), marker_name, color));
}
}
+3 -12
View File
@@ -398,15 +398,6 @@ void TimelineWidget::DeselectAll()
SignalDeselectedAllBlocks();
}
bool TimelineWidget::MarkersActive()
{
if (ruler()->GetActiveTimelineMarkers().size() > 0) {
return true;
} else {
return false;
}
}
void TimelineWidget::RippleToIn()
{
RippleTo(Timeline::kTrimIn);
@@ -505,10 +496,11 @@ void TimelineWidget::ReplaceBlocksWithGaps(const QVector<Block *> &blocks,
void TimelineWidget::DeleteSelected(bool ripple)
{
if (MarkersActive()) {
if (ruler()->hasFocus()) {
ruler()->DeleteSelected();
return;
}
QVector<Block*> selected_list = GetSelectedBlocks();
QVector<Block*> blocks_to_delete;
@@ -641,11 +633,10 @@ void TimelineWidget::CopySelected(bool cut)
return;
}
if (MarkersActive()) {
if (ruler()->hasFocus()) {
ruler()->CopySelected(cut);
return;
}
QVector<Block*> selected = GetSelectedBlocks();
@@ -59,8 +59,6 @@ public:
void DeselectAll();
bool MarkersActive();
void RippleToIn();
void RippleToOut();
@@ -530,19 +530,19 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
}
// Draw markers
if (clip->connected_viewer() && !clip->connected_viewer()->GetLength().isNull()) {
qDebug() << "MARKERS ON CLIP STUB";
/*if (clip->connected_viewer() && !clip->connected_viewer()->GetLength().isNull()) {
if (clip->connected_viewer()->GetTimelinePoints()->markers()->list().size() > 0) {
QList<TimelineMarker *> marker_list = clip->connected_viewer()->GetTimelinePoints()->markers()->list();
std::vector<TimelineMarker *> marker_list = clip->connected_viewer()->GetTimelinePoints()->markers()->list();
int marker_width = QtUtils::QFontMetricsWidth(fm, "H");
clip_marker_positions_.clear();
// Only draw markers if the block UI is large enough to draw all the markers
if (marker_list.length() * marker_width < block_right - block_left) {
if (marker_list.size() * marker_width < block_right - block_left) {
QListIterator<TimelineMarker*> iterator(marker_list);
while(iterator.hasNext()) {
TimelineMarker *marker = iterator.next();
for (auto it=marker_list.cbegin(); it!=marker_list.cend(); it++) {
TimelineMarker *marker = *it;
// Make sure marker is within In/Out points of the clip
if (marker->time().in() >= clip->media_in() && marker->time().out() <= clip->media_in() + clip->length()) {
// Only draw names that we have room for
@@ -561,7 +561,7 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
}
}
}
}
}*/
}
// For transitions, show lines representing a transition
+40 -153
View File
@@ -26,17 +26,17 @@
#include "common/qtutils.h"
#include "core.h"
#include "widget/marker/markerundo.h"
#include "widget/timebased/timebasedwidget.h"
namespace olive {
#define super TimeBasedView
SeekableWidget::SeekableWidget(QWidget* parent) :
TimelineScaledWidget(parent),
super(parent),
timeline_points_(nullptr),
scroll_(0),
snap_service_(nullptr),
dragging_(false)
dragging_(false),
selection_manager_(this)
{
QFontMetrics fm = fontMetrics();
@@ -46,19 +46,18 @@ SeekableWidget::SeekableWidget(QWidget* parent) :
playhead_width_ = QtUtils::QFontMetricsWidth(fm, "H");
setContextMenuPolicy(Qt::CustomContextMenu);
setFocusPolicy(Qt::ClickFocus);
}
void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points)
{
if (timeline_points_) {
selection_manager_.ClearSelection();
disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
foreach(Marker* marker_widget, marker_map_.values()) {
marker_widget->deleteLater();
}
}
timeline_points_ = points;
@@ -68,47 +67,26 @@ void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points)
connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, &SeekableWidget::addMarker);
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, &SeekableWidget::removeMarker);
}
if (timeline_points() && !timeline_points()->markers()->list().isEmpty()) {
foreach (TimelineMarker *marker, timeline_points()->markers()->list()) {
if (!marker_map_.keys().contains(marker)) {
addMarker(marker);
}
}
}
updateMarkerPositions();
update();
viewport()->update();
}
void SeekableWidget::SetSnapService(SnapService *service)
void SeekableWidget::DeleteSelected()
{
snap_service_ = service;
}
void SeekableWidget::DeleteSelected() {
MultiUndoCommand* command = new MultiUndoCommand();
foreach (TimelineMarker *marker, GetActiveTimelineMarkers()) {
command->add_child(new MarkerRemoveCommand(Core::instance()->GetActiveProject(), marker, timeline_points_->markers()));
foreach (TimelineMarker *marker, selection_manager_.GetSelectedObjects()) {
command->add_child(new MarkerRemoveCommand(marker));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
const int &SeekableWidget::GetScroll() const
{
return scroll_;
}
void SeekableWidget::CopySelected(bool cut)
{
CopyMarkersToClipboard(GetActiveTimelineMarkers());
qDebug() << "COPY IS STUB";
//CopyMarkersToClipboard(selection_manager_.GetSelectedObjects());
if (cut) {
DeleteSelected();
@@ -117,14 +95,15 @@ void SeekableWidget::CopySelected(bool cut)
void SeekableWidget::PasteMarkers(bool insert, rational insert_time)
{
MultiUndoCommand *command = new MultiUndoCommand();
PasteMarkersFromClipboard(timeline_points()->markers(), command, insert_time);
//MultiUndoCommand *command = new MultiUndoCommand();
//PasteMarkersFromClipboard(timeline_points()->markers(), command, insert_time);
qDebug() << "PASTE IS STUB";
}
void SeekableWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
SeekToScreenPoint(event->pos().x());
SeekToScenePoint(mapToScene(event->pos()).x());
dragging_ = true;
DeselectAllMarkers();
@@ -134,7 +113,7 @@ void SeekableWidget::mousePressEvent(QMouseEvent *event)
void SeekableWidget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
SeekToScreenPoint(event->pos().x());
SeekToScenePoint(mapToScene(event->pos()).x());
}
}
@@ -142,18 +121,19 @@ void SeekableWidget::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
if (snap_service_) {
snap_service_->HideSnaps();
if (GetSnapService()) {
GetSnapService()->HideSnaps();
}
dragging_ = false;
}
void SeekableWidget::ScaleChangedEvent(const double &)
void SeekableWidget::focusOutEvent(QFocusEvent *event)
{
updateMarkerPositions();
super::focusOutEvent(event);
update();
// Deselect everything when we lose focus
DeselectAllMarkers();
}
TimelinePoints *SeekableWidget::timeline_points() const
@@ -161,131 +141,38 @@ TimelinePoints *SeekableWidget::timeline_points() const
return timeline_points_;
}
void SeekableWidget::SetTime(const rational &r)
{
time_ = r;
updateMarkerPositions();
update();
}
void SeekableWidget::SetScroll(int s)
{
scroll_ = s;
updateMarkerPositions();
update();
}
QVector<TimelineMarker *> SeekableWidget::GetActiveTimelineMarkers() {
QVector<TimelineMarker*> active_timelineMarkers;
foreach (TimelineMarker *marker, timeline_points()->markers()->list()) {
if (marker->active()) {
active_timelineMarkers.append(marker);
}
}
return active_timelineMarkers;
}
void SeekableWidget::DeselectAllMarkers()
{
if (timebase().isNull()) {
return;
}
if (!timeline_points()) {
return;
}
foreach(TimelineMarker* marker, timeline_points()->markers()->list()) {
marker->set_active(false);
}
}
selection_manager_.ClearSelection();
void SeekableWidget::addMarker(TimelineMarker* marker)
{
if (!marker_map_.contains(marker)) {
Marker *marker_widget = new Marker(this);
marker_map_.insert(marker, marker_widget);
/*
Markers are stored as TimelineMarkers and represented in the UI as Markers. As a single
TimelineMarker can be represented in various views it is necessary to make sure all instances
of the TimelineMarker's (UI) Markers are kept in sync. To do this, whenever a Marker is updated
in some way, it signals that change to the relevant TimelineMarker which in turn broadcasts
that update out to all the relevant Markers.
*/
connect(marker_widget, &Marker::ColorChanged, this, &SeekableWidget::SetMarkerColor);
connect(marker, &TimelineMarker::ColorChanged, marker_widget, &Marker::SetColor);
connect(marker_widget, &Marker::ActiveChanged, marker, &TimelineMarker::set_active);
connect(marker, &TimelineMarker::ActiveChanged, marker_widget, &Marker::SetActive);
connect(marker_widget, &Marker::NameChanged, marker, &TimelineMarker::set_name_undo);
connect(marker, &TimelineMarker::NameChanged, marker_widget, &Marker::SetName);
connect(marker_widget, &Marker::TimeChanged, marker, &TimelineMarker::set_time_undo);
connect(marker, &TimelineMarker::TimeChanged, marker_widget, &Marker::SetTime);
marker_widget->move(TimeToScreen(marker->time().in())-2, text_height_);
marker_widget->SetColor(marker->color());
marker_widget->SetName(marker->name());
marker_widget->show();
}
}
void SeekableWidget::removeMarker(TimelineMarker *marker)
{
marker_map_.value(marker)->deleteLater();
marker_map_.take(marker);
viewport()->update();
}
void SeekableWidget::SetMarkerColor(int c)
{
MultiUndoCommand *command = new MultiUndoCommand();
foreach(TimelineMarker* marker, GetActiveTimelineMarkers()) {
command->add_child(new MarkerChangeColorCommand(Core::instance()->GetActiveProject(), marker, c));
foreach(TimelineMarker* marker, selection_manager_.GetSelectedObjects()) {
command->add_child(new MarkerChangeColorCommand(marker, c));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void SeekableWidget::updateMarkerPositions()
{
foreach (TimelineMarker* marker, marker_map_.keys()) {
Marker *m = marker_map_.value(marker);
m->move(TimeToScreen(marker->time().in())-2, text_height_);
}
}
int SeekableWidget::TimeToScreen(const rational &time) const
{
return qFloor(TimeToScene(time)) - scroll_;
}
rational SeekableWidget::ScreenToTime(int x) const
{
return qMax(rational(0), SceneToTime(x + scroll_));
}
void SeekableWidget::SeekToScreenPoint(int screen)
void SeekableWidget::SeekToScenePoint(qreal scene)
{
if (timebase().isNull()) {
return;
}
rational playhead_time = ScreenToTime(screen);
rational playhead_time = SceneToTime(scene);
if (Core::instance()->snapping() && snap_service_) {
if (Core::instance()->snapping() && GetSnapService()) {
rational movement;
snap_service_->SnapPoint({playhead_time},
&movement,
SnapService::kSnapAll & ~SnapService::kSnapToPlayhead);
GetSnapService()->SnapPoint({playhead_time},
&movement,
SnapService::kSnapAll & ~SnapService::kSnapToPlayhead);
playhead_time += movement;
}
@@ -305,20 +192,20 @@ void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom)
// Draw in/out workarea
if (timeline_points()->workarea()->enabled()) {
int workarea_left = qMax(0, TimeToScreen(timeline_points()->workarea()->in()));
int workarea_left = qMax(0.0, TimeToScene(timeline_points()->workarea()->in()));
int workarea_right;
if (timeline_points()->workarea()->out() == TimelineWorkArea::kResetOut) {
workarea_right = width();
} else {
workarea_right = qMin(width(), TimeToScreen(timeline_points()->workarea()->out()));
workarea_right = qMin(qreal(width()), TimeToScene(timeline_points()->workarea()->out()));
}
p->fillRect(workarea_left, 0, workarea_right - workarea_left, height(), palette().highlight());
}
// Draw markers
if (marker_bottom > 0 && !timeline_points()->markers()->list().isEmpty()) {
if (marker_bottom > 0 && !timeline_points()->markers()->list().empty()) {
int marker_top = marker_bottom - text_height_;
@@ -327,8 +214,8 @@ void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom)
p->setBrush(Qt::green);
foreach (TimelineMarker* marker, timeline_points()->markers()->list()) {
int marker_left = TimeToScreen(marker->time().in());
int marker_right = TimeToScreen(marker->time().out());
int marker_left = TimeToScene(marker->time().in());
int marker_right = TimeToScene(marker->time().out());
if (marker_left >= width() || marker_right < 0) {
continue;
+17 -44
View File
@@ -22,35 +22,29 @@
#define SEEKABLEWIDGET_H
#include <QHBoxLayout>
#include <QScrollBar>
#include "common/rational.h"
#include "timeline/timelinepoints.h"
#include "widget/snapservice/snapservice.h"
#include "widget/timebased/timescaledobject.h"
#include "widget/marker/marker.h"
#include "widget/marker/markercopypaste.h"
#include "widget/timebased/timebasedviewselectionmanager.h"
//#include "widget/marker/markercopypaste.h"
namespace olive {
class SeekableWidget : public TimelineScaledWidget, public MarkerCopyPasteService
class SeekableWidget : public TimeBasedView//, public MarkerCopyPasteService
{
Q_OBJECT
public:
SeekableWidget(QWidget *parent = nullptr);
const rational& GetTime() const
int GetScroll() const
{
return time_;
return horizontalScrollBar()->value();
}
const int& GetScroll() const;
void ConnectTimelinePoints(TimelinePoints* points);
void SetSnapService(SnapService* service);
SnapService* GetSnapService() { return snap_service_; };
bool IsDraggingPlayhead() const
{
return dragging_;
@@ -62,35 +56,28 @@ public:
void PasteMarkers(bool insert, rational insert_time);
QVector<TimelineMarker*> GetActiveTimelineMarkers();
void DeselectAllMarkers();
void SeekToScreenPoint(int screen);
int TimeToScreen(const rational& time) const;
rational ScreenToTime(int x) const;
void SeekToScenePoint(qreal scene);
public slots:
void SetTime(const rational &r);
void SetScroll(int s);
void addMarker(TimelineMarker* marker);
void removeMarker(TimelineMarker* marker);
void updateMarkerPositions();
void SetScroll(int i)
{
horizontalScrollBar()->setValue(i);
}
void SetMarkerColor(int c);
protected:
/*void SetMarkerTime();
void SetMarkerName();*/
protected:
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void ScaleChangedEvent(const double&) override;
virtual void focusOutEvent(QFocusEvent *event) override;
void DrawTimelinePoints(QPainter *p, int marker_bottom = 0);
@@ -106,30 +93,16 @@ protected:
return playhead_width_;
}
signals:
/**
* @brief Signal emitted whenever the time changes on this ruler, either by user or programmatically
*/
void TimeChanged(const rational &time);
private:
rational time_;
TimelinePoints* timeline_points_;
int scroll_;
int text_height_;
int playhead_width_;
SnapService* snap_service_;
bool dragging_;
QMap<TimelineMarker*, Marker*> marker_map_;
QMap<TimelineMarker*, Marker*> active_markers_map_;
TimeBasedViewSelectionManager<TimelineMarker> selection_manager_;
};
+37 -28
View File
@@ -58,6 +58,17 @@ TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* pare
// Connect context menu
connect(this, &TimeRuler::customContextMenuRequested, this, &TimeRuler::ShowContextMenu);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//horizontalScrollBar()->setVisible(false);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setBackgroundRole(QPalette::Window);
setFrameShape(QFrame::NoFrame);
// NOTE: One day it might be preferable to use AlignBottom because the lines are anchored to
// the bottom of the widget. However, for now this makes sense since we just ported this
// from a QWidget's paintEvent.
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void TimeRuler::SetPlaybackCache(PlaybackCache *cache)
@@ -83,15 +94,13 @@ void TimeRuler::SetPlaybackCache(PlaybackCache *cache)
update();
}
void TimeRuler::paintEvent(QPaintEvent *)
void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
{
// Nothing to paint if the timebase is invalid
if (timebase().isNull()) {
return;
}
QPainter p(this);
// Draw timeline points if connected
if (timeline_points()) {
int marker_bottom = height() - text_height();
@@ -104,7 +113,7 @@ void TimeRuler::paintEvent(QPaintEvent *)
marker_bottom -= cache_status_height_;
}
DrawTimelinePoints(&p, marker_bottom);
DrawTimelinePoints(p, marker_bottom);
}
double width_of_frame = timebase_dbl() * GetScale();
@@ -173,11 +182,11 @@ void TimeRuler::paintEvent(QPaintEvent *)
}
// Set line color to main text color
p.setBrush(Qt::NoBrush);
p.setPen(palette().text().color());
p->setBrush(Qt::NoBrush);
p->setPen(palette().text().color());
// Calculate line dimensions
QFontMetrics fm = p.fontMetrics();
QFontMetrics fm = p->fontMetrics();
int line_bottom = height();
if (show_cache_status_) {
@@ -197,8 +206,8 @@ void TimeRuler::paintEvent(QPaintEvent *)
// FIXME: Hardcoded number
const int kAverageTextWidth = 200;
for (int i=-kAverageTextWidth;i<width()+kAverageTextWidth;i++) {
double screen_pt = static_cast<double>(i + GetScroll());
for (int i=GetScroll()-kAverageTextWidth;i<GetScroll()+width()+kAverageTextWidth;i++) {
double screen_pt = static_cast<double>(i);
if (long_interval > -1) {
int this_long_unit = qFloor(screen_pt/long_interval);
@@ -208,7 +217,7 @@ void TimeRuler::paintEvent(QPaintEvent *)
if (text_visible_) {
QRect text_rect;
Qt::Alignment text_align;
QString timecode_str = Timecode::time_to_timecode(ScreenToTime(i), timebase(), Core::instance()->GetTimecodeDisplay());
QString timecode_str = Timecode::time_to_timecode(SceneToTime(i), timebase(), Core::instance()->GetTimecodeDisplay());
int timecode_width = QtUtils::QFontMetricsWidth(fm, timecode_str);
int timecode_left;
@@ -226,9 +235,9 @@ void TimeRuler::paintEvent(QPaintEvent *)
}
if (timecode_left > last_text_draw) {
p.drawText(text_rect,
static_cast<int>(text_align),
timecode_str);
p->drawText(text_rect,
static_cast<int>(text_align),
timecode_str);
last_text_draw = timecode_left + timecode_width;
@@ -238,7 +247,7 @@ void TimeRuler::paintEvent(QPaintEvent *)
}
}
p.drawLine(i, line_y, i, line_bottom);
p->drawLine(i, line_y, i, line_bottom);
last_long_unit = this_long_unit;
}
}
@@ -246,7 +255,7 @@ void TimeRuler::paintEvent(QPaintEvent *)
if (short_interval > -1) {
int this_short_unit = qFloor(screen_pt/short_interval);
if (this_short_unit != last_short_unit) {
p.drawLine(i, short_y, i, line_bottom);
p->drawLine(i, short_y, i, line_bottom);
last_short_unit = this_short_unit;
}
}
@@ -257,40 +266,40 @@ void TimeRuler::paintEvent(QPaintEvent *)
// FIXME: Hardcoded to get video length, if we ever need audio length, this will have to change
rational len = playback_cache_->viewer_parent()->GetVideoLength();
int cache_screen_length = qMin(TimeToScreen(len), width());
int cache_screen_length = qMin(TimeToScene(len), qreal(width()));
if (cache_screen_length > 0) {
int cache_y = height() - cache_status_height_;
p.fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green);
p->fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green);
foreach (const TimeRange& range, playback_cache_->GetInvalidatedRanges(len)) {
int range_left = TimeToScreen(range.in());
int range_left = TimeToScene(range.in());
if (range_left >= width()) {
continue;
}
int range_right = TimeToScreen(range.out());
int range_right = TimeToScene(range.out());
if (range_right < 0) {
continue;
}
int adjusted_left = qMax(0, range_left);
p.fillRect(adjusted_left,
cache_y,
qMin(width(), range_right) - adjusted_left,
cache_status_height_,
Qt::red);
p->fillRect(adjusted_left,
cache_y,
qMin(width(), range_right) - adjusted_left,
cache_status_height_,
Qt::red);
}
}
}
// Draw the playhead if it's on screen at the moment
int playhead_pos = TimeToScreen(GetTime());
p.setPen(Qt::NoPen);
p.setBrush(PLAYHEAD_COLOR);
DrawPlayhead(&p, playhead_pos, line_bottom);
int playhead_pos = TimeToScene(GetTime());
p->setPen(Qt::NoPen);
p->setBrush(PLAYHEAD_COLOR);
DrawPlayhead(p, playhead_pos, line_bottom);
}
void TimeRuler::TimebaseChangedEvent(const rational &tb)
+1 -1
View File
@@ -41,7 +41,7 @@ public:
void SetPlaybackCache(PlaybackCache* cache);
protected:
virtual void paintEvent(QPaintEvent* e) override;
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
virtual void TimebaseChangedEvent(const rational& tb) override;
+15 -10
View File
@@ -38,6 +38,13 @@ AudioWaveformView::AudioWaveformView(QWidget *parent) :
{
setAutoFillBackground(true);
setBackgroundRole(QPalette::Base);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// NOTE: At some point it might make sense for this to be AlignCenter since the waveform
// originates from the center. But we're leaving it top/left for now since it was just
// ported from a QWidget's paintEvent.
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void AudioWaveformView::SetViewer(AudioPlaybackCache *playback)
@@ -60,9 +67,9 @@ void AudioWaveformView::SetViewer(AudioPlaybackCache *playback)
}
}
void AudioWaveformView::paintEvent(QPaintEvent *event)
void AudioWaveformView::drawForeground(QPainter *p, const QRectF &rect)
{
super::paintEvent(event);
super::drawForeground(p, rect);
if (!playback_) {
return;
@@ -74,20 +81,18 @@ void AudioWaveformView::paintEvent(QPaintEvent *event)
return;
}
QPainter p(this);
// Draw in/out points
DrawTimelinePoints(&p);
DrawTimelinePoints(p);
// Draw waveform
p.setPen(QColor(64, 255, 160)); // FIXME: Hardcoded color
AudioVisualWaveform::DrawWaveform(&p, rect(), GetScale(), playback_->visual(), SceneToTime(GetScroll()));
p->setPen(QColor(64, 255, 160)); // FIXME: Hardcoded color
AudioVisualWaveform::DrawWaveform(p, rect.toRect(), GetScale(), playback_->visual(), SceneToTime(GetScroll()));
// Draw playhead
p.setPen(PLAYHEAD_COLOR);
p->setPen(PLAYHEAD_COLOR);
int playhead_x = TimeToScreen(GetTime());
p.drawLine(playhead_x, 0, playhead_x, height());
int playhead_x = TimeToScene(GetTime());
p->drawLine(playhead_x, 0, playhead_x, height());
}
}
+1 -1
View File
@@ -39,7 +39,7 @@ public:
void SetViewer(AudioPlaybackCache *playback);
protected:
virtual void paintEvent(QPaintEvent* event) override;
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
private:
QThreadPool pool_;
+1 -1
View File
@@ -97,6 +97,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
// Create waveform view when audio is connected and video isn't
waveform_view_ = new AudioWaveformView();
ConnectTimelineView(waveform_view_, true);
PassWheelEventsToScrollBar(waveform_view_);
stack_->addWidget(waveform_view_);
@@ -125,7 +126,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
SetScale(48.0);
// Ensures that seeking on the waveform view updates the time as expected
connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::SetTimeAndSignal);
connect(waveform_view_, &AudioWaveformView::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(&playback_backup_timer_, &QTimer::timeout, this, &ViewerWidget::PlaybackTimerUpdate);