From db92e5231fbec55ba4af7a3a394619aad3e6b1c2 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 02:53:54 +1100 Subject: [PATCH] most clip marker work completed #333 --- io/config.h | 2 +- io/loadthread.cpp | 18 ++++++++++++++++-- panels/project.cpp | 17 +++++++++++++---- panels/timeline.cpp | 33 ++++++++++++++++++++++++++++++--- project/clip.h | 5 +++++ project/marker.cpp | 17 +++++++++++++++++ project/marker.h | 5 +++++ project/undo.cpp | 28 +++++++++++++++++++--------- project/undo.h | 5 +++-- ui/timelineheader.cpp | 40 +++++++++++----------------------------- ui/timelinewidget.cpp | 29 +++++++++++++++++++++++++++++ 11 files changed, 149 insertions(+), 50 deletions(-) diff --git a/io/config.h b/io/config.h index 5e8c61f27..c01ee0ee3 100644 --- a/io/config.h +++ b/io/config.h @@ -3,7 +3,7 @@ #include -#define SAVE_VERSION 190120 // YYMMDD +#define SAVE_VERSION 190201 // YYMMDD #define MIN_SAVE_VERSION 190104 // lowest compatible project version #define TIMECODE_DROP 0 diff --git a/io/loadthread.cpp b/io/loadthread.cpp index adfc3a510..ae4bcca35 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -427,10 +427,24 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } } if (cancelled) return false; - } else if (stream.isStartElement() && (stream.name() == "effect" || stream.name() == "opening" || stream.name() == "closing")) { + } else if (stream.isStartElement() + && (stream.name() == "effect" + || stream.name() == "opening" + || stream.name() == "closing")) { // "opening" and "closing" are backwards compatibility code load_effect(stream, c); - } + } else if (stream.name() == "marker" && stream.isStartElement()) { + Marker m; + for (int j=0;jmarkers.append(m); + } } } if (cancelled) return false; diff --git a/panels/project.cpp b/panels/project.cpp index 4ec6ae81a..1bf591aee 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -915,6 +915,13 @@ void Project::load_project(bool autorecovery) { ld.exec(); } +void save_marker(QXmlStreamWriter& stream, const Marker& m) { + stream.writeStartElement("marker"); + stream.writeAttribute("frame", QString::number(m.frame)); + stream.writeAttribute("name", m.name); + stream.writeEndElement(); +} + void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) { for (int i=0;imarkers.size();k++) { + save_marker(stream, c->markers.at(k)); + } + stream.writeStartElement("linked"); // linked for (int k=0;klinked.size();k++) { stream.writeStartElement("link"); // link @@ -1063,10 +1075,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, } } for (int j=0;jmarkers.size();j++) { - stream.writeStartElement("marker"); - stream.writeAttribute("frame", QString::number(s->markers.at(j).frame)); - stream.writeAttribute("name", s->markers.at(j).name); - stream.writeEndElement(); + save_marker(stream, s->markers.at(j)); } stream.writeEndElement(); } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index b7cfe2b5f..a9860f5e9 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -1426,7 +1426,14 @@ bool Timeline::snap_to_timeline(long* l, bool use_playhead, bool use_markers, bo } else if (c->get_closing_transition() != nullptr && snap_to_point(c->timeline_out - c->get_closing_transition()->get_true_length(), l)) { return true; - } + } else { + // try to snap to clip markers + for (int j=0;jmarkers.size();j++) { + if (snap_to_point(c->markers.at(j).frame + c->timeline_in - c->clip_in, l)) { + return true; + } + } + } } } } @@ -1446,9 +1453,29 @@ void Timeline::set_marker() { marker_name = d.textValue(); } - if (add_marker) { - undo_stack.push(new AddMarkerAction(sequence, sequence->playhead, marker_name)); + ComboAction* ca = new ComboAction(); + + // see if any clips are selected, and if so add a marker to them + bool clip_mode = false; + for (int i=0;iclips.size();i++) { + Clip* c = sequence->clips.at(i); + if (c != nullptr + && is_clip_selected(c, true)) { + ca->append(new AddMarkerAction(false, + c, + sequence->playhead - c->timeline_in + c->clip_in, + marker_name)); + clip_mode = true; + } + } + + // if no clips are selected, we're adding a marker to the sequence + if (!clip_mode) { + ca->append(new AddMarkerAction(true, sequence, sequence->playhead, marker_name)); + } + + undo_stack.push(ca); } } diff --git a/project/clip.h b/project/clip.h index a2f284d80..488045cd1 100644 --- a/project/clip.h +++ b/project/clip.h @@ -5,6 +5,8 @@ #include #include +#include "marker.h" + #define SKIP_TYPE_DISCARD 0 #define SKIP_TYPE_SEEK 1 @@ -73,6 +75,9 @@ struct Clip bool maintain_audio_pitch; bool autoscale; + // markers + QVector markers; + // other variables (should be deep copied/duplicated in copy()) QList effects; QVector linked; diff --git a/project/marker.cpp b/project/marker.cpp index 1b5311b31..b92cdc961 100644 --- a/project/marker.cpp +++ b/project/marker.cpp @@ -1 +1,18 @@ #include "marker.h" + +void draw_marker(QPainter &p, int x, int y, int bottom, bool selected, bool flipped) { + const QPoint points[5] = { + QPoint(x, bottom), + QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE), + QPoint(x + MARKER_SIZE, y), + QPoint(x - MARKER_SIZE, y), + QPoint(x - MARKER_SIZE, bottom - MARKER_SIZE) + }; + p.setPen(Qt::black); + if (selected) { + p.setBrush(QColor(208, 255, 208)); + } else { + p.setBrush(QColor(128, 224, 128)); + } + p.drawPolygon(points, 5); +} diff --git a/project/marker.h b/project/marker.h index a58f85e48..8d1ef87b8 100644 --- a/project/marker.h +++ b/project/marker.h @@ -1,11 +1,16 @@ #ifndef MARKER_H #define MARKER_H +#define MARKER_SIZE 4 + #include +#include struct Marker { long frame; QString name; }; +void draw_marker(QPainter& p, int x, int y, int bottom, bool selected, bool flipped); + #endif // MARKER_H diff --git a/project/undo.cpp b/project/undo.cpp index 47b797c34..ce577f855 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -803,18 +803,23 @@ void SetAutoscaleAction::redo() { mainWindow->setWindowModified(true); } -AddMarkerAction::AddMarkerAction(Sequence* s, long t, QString n) : - seq(s), +AddMarkerAction::AddMarkerAction(bool is_sequence, void* s, long t, QString n) : + is_sequence_internal(is_sequence), + target(s), time(t), name(n), old_project_changed(mainWindow->isWindowModified()) {} void AddMarkerAction::undo() { + QVector& markers = is_sequence_internal ? + static_cast(target)->markers : + static_cast(target)->markers; + if (index == -1) { - seq->markers.removeLast(); + markers.removeLast(); } else { - seq->markers[index].name = old_name; + markers[index].name = old_name; } mainWindow->setWindowModified(old_project_changed); @@ -822,8 +827,13 @@ void AddMarkerAction::undo() { void AddMarkerAction::redo() { index = -1; - for (int i=0;imarkers.size();i++) { - if (seq->markers.at(i).frame == time) { + + QVector& markers = is_sequence_internal ? + static_cast(target)->markers : + static_cast(target)->markers; + + for (int i=0;imarkers.append(m); + markers.append(m); } else { - old_name = seq->markers.at(index).name; - seq->markers[index].name = name; + old_name = markers.at(index).name; + markers[index].name = name; } mainWindow->setWindowModified(true); diff --git a/project/undo.h b/project/undo.h index 9f94ee3a4..a2420fbdb 100644 --- a/project/undo.h +++ b/project/undo.h @@ -384,11 +384,12 @@ private: class AddMarkerAction : public QUndoCommand { public: - AddMarkerAction(Sequence* s, long t, QString n); + AddMarkerAction(bool is_sequence, void* s, long t, QString n); void undo(); void redo(); private: - Sequence* seq; + bool is_sequence_internal; + void* target; long time; QString name; QString old_name; diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 5746028e4..e37f16374 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -20,7 +20,6 @@ #define PLAYHEAD_SIZE 6 #define LINE_MIN_PADDING 50 #define SUBLINE_MIN_PADDING 50 // TODO play with this -#define MARKER_SIZE 4 // used only if center_timeline_timecodes is FALSE #define TEXT_PADDING_FROM_LINE 4 @@ -406,35 +405,18 @@ void TimelineHeader::paintEvent(QPaintEvent*) { // draw markers for (int i=0;iseq->markers.size();i++) { const Marker& m = viewer->seq->markers.at(i); + int marker_x = getHeaderScreenPointFromFrame(m.frame); - const QPoint points[5] = { - QPoint(marker_x, height()-1), - QPoint(marker_x + MARKER_SIZE, height() - MARKER_SIZE - 1), - QPoint(marker_x + MARKER_SIZE, yoff), - QPoint(marker_x - MARKER_SIZE, yoff), - QPoint(marker_x - MARKER_SIZE, height() - MARKER_SIZE - 1) - }; - /*const QPoint points[5] = { - QPoint(marker_x, height()-1), - QPoint(marker_x + MARKER_SIZE, height() - MARKER_SIZE - 1), - QPoint(marker_x + MARKER_SIZE, yoff), - QPoint(marker_x - MARKER_SIZE, yoff), - QPoint(marker_x - MARKER_SIZE, height() - MARKER_SIZE - 1) - };*/ - p.setPen(Qt::black); - bool selected = false; - for (int j=0;jghosts.size();i++) { const Ghost& g = panel_timeline->ghosts.at(i); + + // snap ghost's in point if (panel_timeline->trim_target == -1 || g.trim_in) { fm = g.old_in + frame_diff; if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { @@ -1251,6 +1253,8 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { break; } } + + // snap ghost's out point if (panel_timeline->trim_target == -1 || !g.trim_in) { fm = g.old_out + frame_diff; if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { @@ -1258,6 +1262,19 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { break; } } + + // if the ghost is attached to a clip, snap its markers too + if (panel_timeline->trim_target == -1 && g.clip >= 0) { + Clip* c = sequence->clips.at(g.clip); + for (int j=0;jmarkers.size();j++) { + long marker_real_time = c->markers.at(j).frame + c->timeline_in - c->clip_in; + fm = marker_real_time + frame_diff; + if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { + frame_diff = fm - marker_real_time; + break; + } + } + } } } @@ -2394,6 +2411,18 @@ void TimelineWidget::paintEvent(QPaintEvent*) { } } + // draw clip markers + for (int j=0;jmarkers.size();j++) { + const Marker& m = clip->markers.at(j); + + // convert marker time (in clip time) to sequence time + long marker_time = m.frame + clip->timeline_in - clip->clip_in; + int marker_x = panel_timeline->getTimelineScreenPointFromFrame(marker_time); + if (marker_x > clip_rect.x() && marker_x < clip_rect.right()) { + draw_marker(p, marker_x, clip_rect.bottom()-p.fontMetrics().height(), clip_rect.bottom(), false, false); + } + } + // draw clip transitions draw_transition(p, clip, clip_rect, text_rect, TA_OPENING_TRANSITION); draw_transition(p, clip, clip_rect, text_rect, TA_CLOSING_TRANSITION);