From cdcd83c09a8429d81372b916a13628b3c1d5679b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 1 May 2022 15:45:20 -0700 Subject: [PATCH] ported seekablewidget to timebasedview Cuts down on a lot of code duplication and opens up usage of the new TimelineViewSelectionManager framework --- app/node/node.cpp | 13 +- app/node/project/project.cpp | 14 + app/node/project/project.h | 8 + .../project/serializer/serializer210528.cpp | 3 +- .../project/serializer/serializer210907.cpp | 3 +- .../project/serializer/serializer211228.cpp | 3 +- .../project/serializer/serializer220403.cpp | 3 +- app/timeline/timelinemarker.cpp | 203 +++++++++----- app/timeline/timelinemarker.h | 132 +++++++-- app/timeline/timelinepoints.cpp | 15 +- app/timeline/timelinepoints.h | 9 +- app/widget/CMakeLists.txt | 1 - app/widget/marker/CMakeLists.txt | 26 -- app/widget/marker/marker.cpp | 263 ------------------ app/widget/marker/marker.h | 92 ------ app/widget/marker/markercopypaste.cpp | 136 --------- app/widget/marker/markercopypaste.h | 42 --- app/widget/marker/markerundo.cpp | 138 --------- app/widget/marker/markerundo.h | 119 -------- .../resizabletimelinescrollbar.cpp | 4 +- app/widget/timebased/timebasedview.h | 8 +- app/widget/timebased/timebasedwidget.cpp | 20 +- app/widget/timelinewidget/timelinewidget.cpp | 15 +- app/widget/timelinewidget/timelinewidget.h | 2 - .../timelinewidget/view/timelineview.cpp | 16 +- app/widget/timeruler/seekablewidget.cpp | 193 +++---------- app/widget/timeruler/seekablewidget.h | 61 ++-- app/widget/timeruler/timeruler.cpp | 65 +++-- app/widget/timeruler/timeruler.h | 2 +- app/widget/viewer/audiowaveformview.cpp | 25 +- app/widget/viewer/audiowaveformview.h | 2 +- app/widget/viewer/viewer.cpp | 2 +- 32 files changed, 425 insertions(+), 1213 deletions(-) delete mode 100644 app/widget/marker/CMakeLists.txt delete mode 100644 app/widget/marker/marker.cpp delete mode 100644 app/widget/marker/marker.h delete mode 100644 app/widget/marker/markercopypaste.cpp delete mode 100644 app/widget/marker/markercopypaste.h delete mode 100644 app/widget/marker/markerundo.cpp delete mode 100644 app/widget/marker/markerundo.h diff --git a/app/node/node.cpp b/app/node/node.cpp index 6e02dc68e..4a0c60b03 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -80,18 +80,9 @@ NodeGraph *Node::parent() const return static_cast(QObject::parent()); } -Project* Node::project() const +Project *Node::project() const { - QObject *t = this->parent(); - - while (t) { - if (Project *p = dynamic_cast(t)) { - return p; - } - t = t->parent(); - } - - return nullptr; + return Project::GetProjectFromObject(this); } QString Node::ShortName() const diff --git a/app/node/project/project.cpp b/app/node/project/project.cpp index d8923c9cd..c4340b177 100644 --- a/app/node/project/project.cpp +++ b/app/node/project/project.cpp @@ -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(t)) { + return p; + } + t = t->parent(); + } + + return nullptr; +} + void Project::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range) { Q_UNUSED(input) diff --git a/app/node/project/project.h b/app/node/project/project.h index 2fccff6d3..1119e26fc 100644 --- a/app/node/project/project.h +++ b/app/node/project/project.h @@ -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(); diff --git a/app/node/project/serializer/serializer210528.cpp b/app/node/project/serializer/serializer210528.cpp index 73ca85a4e..baf53e442 100644 --- a/app/node/project/serializer/serializer210528.cpp +++ b/app/node/project/serializer/serializer210528.cpp @@ -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(); diff --git a/app/node/project/serializer/serializer210907.cpp b/app/node/project/serializer/serializer210907.cpp index cd23aaea9..96b69f214 100644 --- a/app/node/project/serializer/serializer210907.cpp +++ b/app/node/project/serializer/serializer210907.cpp @@ -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(); diff --git a/app/node/project/serializer/serializer211228.cpp b/app/node/project/serializer/serializer211228.cpp index 2faea0a0d..139fd2438 100644 --- a/app/node/project/serializer/serializer211228.cpp +++ b/app/node/project/serializer/serializer211228.cpp @@ -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(); diff --git a/app/node/project/serializer/serializer220403.cpp b/app/node/project/serializer/serializer220403.cpp index b5d8d85b7..31d3ea726 100644 --- a/app/node/project/serializer/serializer220403.cpp +++ b/app/node/project/serializer/serializer220403.cpp @@ -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(); diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index e75a625ba..2251ab3a3 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -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 &TimelineMarkerList::list() const +const std::vector &TimelineMarkerList::list() const { return markers_; } +void TimelineMarkerList::childEvent(QChildEvent *e) +{ + QObject::childEvent(e); + + if (TimelineMarker *marker = dynamic_cast(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_); +} + } diff --git a/app/timeline/timelinemarker.h b/app/timeline/timelinemarker.h index e33afce04..61822859c 100644 --- a/app/timeline/timelinemarker.h +++ b/app/timeline/timelinemarker.h @@ -26,6 +26,7 @@ #include #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 &list() const; + const std::vector &list() const; signals: void MarkerAdded(TimelineMarker* marker); void MarkerRemoved(TimelineMarker* marker); +protected: + virtual void childEvent(QChildEvent *e) override; + private: - QList markers_; + std::vector 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_; }; diff --git a/app/timeline/timelinepoints.cpp b/app/timeline/timelinepoints.cpp index 4329c42b4..61ed3633d 100644 --- a/app/timeline/timelinepoints.cpp +++ b/app/timeline/timelinepoints.cpp @@ -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_; } } diff --git a/app/timeline/timelinepoints.h b/app/timeline/timelinepoints.h index 14527608d..62290bef4 100644 --- a/app/timeline/timelinepoints.h +++ b/app/timeline/timelinepoints.h @@ -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_; }; diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 10c8ce38f..9faf9c462 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -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) diff --git a/app/widget/marker/CMakeLists.txt b/app/widget/marker/CMakeLists.txt deleted file mode 100644 index 73922308e..000000000 --- a/app/widget/marker/CMakeLists.txt +++ /dev/null @@ -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 . - -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 -) diff --git a/app/widget/marker/marker.cpp b/app/widget/marker/marker.cpp deleted file mode 100644 index eb058a3f2..000000000 --- a/app/widget/marker/marker.cpp +++ /dev/null @@ -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 . - -***/ - -#include "marker.h" - -#include -#include - -#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(); - 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(); - 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(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 diff --git a/app/widget/marker/marker.h b/app/widget/marker/marker.h deleted file mode 100644 index 972dbb05a..000000000 --- a/app/widget/marker/marker.h +++ /dev/null @@ -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 . - -***/ - -#ifndef MARKER_H -#define MARKER_H - -#include -#include -#include - -#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 diff --git a/app/widget/marker/markercopypaste.cpp b/app/widget/marker/markercopypaste.cpp deleted file mode 100644 index f5352907e..000000000 --- a/app/widget/marker/markercopypaste.cpp +++ /dev/null @@ -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 . -***/ - -#include "markercopypaste.h" - -#include - -#include "core.h" -#include "markerundo.h" -#include "widget/timebased/timebasedwidget.h" - -namespace olive { - -void MarkerCopyPasteService::CopyMarkersToClipboard(const QVector& 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; - - 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 diff --git a/app/widget/marker/markercopypaste.h b/app/widget/marker/markercopypaste.h deleted file mode 100644 index e0715fb40..000000000 --- a/app/widget/marker/markercopypaste.h +++ /dev/null @@ -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 . -***/ - -#ifndef MARKERCOPYPASTEWIDGET_H -#define MARKERCOPYPASTEWIDGET_H - -#include -#include - -#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 &markers, void* userdata = nullptr); - - void PasteMarkersFromClipboard(TimelineMarkerList* list, MultiUndoCommand *command, rational offset); -}; - -} - -#endif // MARKERCOPYPASTEWIDGET_H diff --git a/app/widget/marker/markerundo.cpp b/app/widget/marker/markerundo.cpp deleted file mode 100644 index e75a0a68e..000000000 --- a/app/widget/marker/markerundo.cpp +++ /dev/null @@ -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 . -***/ - -#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_); -} - -} diff --git a/app/widget/marker/markerundo.h b/app/widget/marker/markerundo.h deleted file mode 100644 index d5ef865bc..000000000 --- a/app/widget/marker/markerundo.h +++ /dev/null @@ -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 . -***/ - -#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 diff --git a/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp index e45b3d1fc..59d50d0f1 100644 --- a/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp +++ b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp @@ -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())); diff --git a/app/widget/timebased/timebasedview.h b/app/widget/timebased/timebasedview.h index a51728afb..4bca7f9da 100644 --- a/app/widget/timebased/timebasedview.h +++ b/app/widget/timebased/timebasedview.h @@ -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); diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 23da400ce..b28398b45 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -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)); } } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index c5a89bc2c..0cb52f29a 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -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 &blocks, void TimelineWidget::DeleteSelected(bool ripple) { - if (MarkersActive()) { + if (ruler()->hasFocus()) { ruler()->DeleteSelected(); return; } + QVector selected_list = GetSelectedBlocks(); QVector blocks_to_delete; @@ -641,11 +633,10 @@ void TimelineWidget::CopySelected(bool cut) return; } - if (MarkersActive()) { + if (ruler()->hasFocus()) { ruler()->CopySelected(cut); return; } - QVector selected = GetSelectedBlocks(); diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 18ac70365..e96b657a4 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -59,8 +59,6 @@ public: void DeselectAll(); - bool MarkersActive(); - void RippleToIn(); void RippleToOut(); diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 2bd1b5a31..d8b8a28c2 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -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 marker_list = clip->connected_viewer()->GetTimelinePoints()->markers()->list(); - + std::vector 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 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 diff --git a/app/widget/timeruler/seekablewidget.cpp b/app/widget/timeruler/seekablewidget.cpp index 1e46da75e..467a9f649 100644 --- a/app/widget/timeruler/seekablewidget.cpp +++ b/app/widget/timeruler/seekablewidget.cpp @@ -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(&SeekableWidget::update)); disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&SeekableWidget::update)); disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&SeekableWidget::update)); disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&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(&SeekableWidget::update)); connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&SeekableWidget::update)); connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&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 SeekableWidget::GetActiveTimelineMarkers() { - QVector 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; diff --git a/app/widget/timeruler/seekablewidget.h b/app/widget/timeruler/seekablewidget.h index cbbcf939f..56d6f2660 100644 --- a/app/widget/timeruler/seekablewidget.h +++ b/app/widget/timeruler/seekablewidget.h @@ -22,35 +22,29 @@ #define SEEKABLEWIDGET_H #include +#include #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 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 marker_map_; - - QMap active_markers_map_; + TimeBasedViewSelectionManager selection_manager_; }; diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index db887fe7e..ff2b3281d 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -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(i + GetScroll()); + for (int i=GetScroll()-kAverageTextWidth;i(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(text_align), - timecode_str); + p->drawText(text_rect, + static_cast(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) diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 496117238..3a475d398 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -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; diff --git a/app/widget/viewer/audiowaveformview.cpp b/app/widget/viewer/audiowaveformview.cpp index 198cff332..59f1dc4f6 100644 --- a/app/widget/viewer/audiowaveformview.cpp +++ b/app/widget/viewer/audiowaveformview.cpp @@ -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()); } } diff --git a/app/widget/viewer/audiowaveformview.h b/app/widget/viewer/audiowaveformview.h index b89e56224..92f34d80e 100644 --- a/app/widget/viewer/audiowaveformview.h +++ b/app/widget/viewer/audiowaveformview.h @@ -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_; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index d589b409f..e5eae2440 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -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);