From 0513749b9d606d085d0752c192788d9e68f796f1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 02:03:05 +1100 Subject: [PATCH 1/9] added maximize panel and full screen viewer menu items --- mainwindow.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++--- mainwindow.h | 7 ++++++- panels/panels.cpp | 4 ++-- panels/panels.h | 2 +- ui/viewerwidget.cpp | 22 ++++++++++++------- ui/viewerwidget.h | 1 + 6 files changed, 73 insertions(+), 14 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 042c52f7a..582a8049d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -736,6 +736,8 @@ void MainWindow::setup_menus() { full_screen->setProperty("id", "fullscreen"); full_screen->setCheckable(true); + view_menu->addAction(tr("Full Screen Viewer"), this, SLOT(full_screen_viewer()))->setProperty("id", "fullscreenviewer"); + // INITIALIZE PLAYBACK MENU QMenu* playback_menu = menuBar->addMenu(tr("&Playback")); @@ -799,7 +801,11 @@ void MainWindow::setup_menus() { window_sequenceviewer_action->setCheckable(true); window_sequenceviewer_action->setData(reinterpret_cast(panel_sequence_viewer)); - window_menu->addSeparator(); + window_menu->addSeparator(); + + window_menu->addAction(tr("Maximize Panel"), this, SLOT(maximize_panel()), QKeySequence("`"))->setProperty("id", "maximizepanel"); + + window_menu->addSeparator(); window_menu->addAction(tr("Reset to Default Layout"), this, SLOT(reset_layout()))->setProperty("id", "resetdefaultlayout"); @@ -1185,7 +1191,34 @@ void MainWindow::next_cut() { QDockWidget* focused_panel = get_focused_panel(); if (sequence != nullptr && (panel_timeline == focused_panel || panel_sequence_viewer == focused_panel)) { panel_timeline->next_cut(); - } + } +} + +void MainWindow::maximize_panel() { + // toggles between normal state and a state of one panel being maximized + if (temp_panel_state.isEmpty()) { + // get currently hovered panel + QDockWidget* focused_panel = get_focused_panel(true); + + // if the mouse is in fact hovering over a panel + if (focused_panel != nullptr) { + // store the current state of panels + temp_panel_state = saveState(); + + // remove all dock widgets (kind of painful having to do each individually) + if (focused_panel != panel_project) removeDockWidget(panel_project); + if (focused_panel != panel_effect_controls) removeDockWidget(panel_effect_controls); + if (focused_panel != panel_timeline) removeDockWidget(panel_timeline); + if (focused_panel != panel_sequence_viewer) removeDockWidget(panel_sequence_viewer); + if (focused_panel != panel_footage_viewer) removeDockWidget(panel_footage_viewer); + } + } else { + // we must be maximized, restore previous state + restoreState(temp_panel_state); + + // clear temp panel state for next maximize call + temp_panel_state.clear(); + } } void MainWindow::preferences() @@ -1200,7 +1233,15 @@ void MainWindow::zoom_in_tracks() { } void MainWindow::zoom_out_tracks() { - panel_timeline->decrease_track_height(); + panel_timeline->decrease_track_height(); +} + +void MainWindow::full_screen_viewer() { + if (get_focused_panel() == panel_footage_viewer) { + panel_footage_viewer->viewer_widget->set_fullscreen(); + } else { + panel_sequence_viewer->viewer_widget->set_fullscreen(); + } } void MainWindow::windowMenu_About_To_Be_Shown() { @@ -1585,6 +1626,10 @@ void MainWindow::toggle_panel_visibility() { QAction* action = static_cast(sender()); QDockWidget* w = reinterpret_cast(action->data().value()); w->setVisible(!w->isVisible()); + + // layout has changed, we're no longer in maximized panel mode, + // so we clear this byte array + temp_panel_state.clear(); } void MainWindow::set_timecode_view() { diff --git a/mainwindow.h b/mainwindow.h index 4652b2c24..b00bf28c9 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -78,14 +78,16 @@ private slots: void prev_cut(); void next_cut(); + void maximize_panel(); void reset_layout(); void preferences(); void zoom_in_tracks(); - void zoom_out_tracks(); + void full_screen_viewer(); + void fileMenu_About_To_Be_Shown(); void fileMenu_About_To_Hide(); void editMenu_About_To_Be_Shown(); @@ -204,6 +206,9 @@ private: bool enable_launch_with_project; QString appName; + + // used to store the panel state when one panel is maximized + QByteArray temp_panel_state; }; extern MainWindow* mainWindow; diff --git a/panels/panels.cpp b/panels/panels.cpp index 98a61dcd2..b460647c9 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -115,9 +115,9 @@ void update_ui(bool modified) { panel_graph_editor->update_panel(); } -QDockWidget *get_focused_panel() { +QDockWidget *get_focused_panel(bool force_hover) { QDockWidget* w = nullptr; - if (config.hover_focus) { + if (config.hover_focus || force_hover) { if (panel_project->underMouse()) { w = panel_project; } else if (panel_effect_controls->underMouse()) { diff --git a/panels/panels.h b/panels/panels.h index 2434d1daa..0e934513e 100644 --- a/panels/panels.h +++ b/panels/panels.h @@ -19,7 +19,7 @@ extern Timeline* panel_timeline; extern GraphEditor* panel_graph_editor; void update_ui(bool modified); -QDockWidget* get_focused_panel(); +QDockWidget* get_focused_panel(bool force_hover = false); void alloc_panels(QWidget *parent); void free_panels(); void scroll_to_frame_internal(QScrollBar* bar, long frame, double zoom, int area_width); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index ea2322836..f6031f4ea 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -93,7 +93,20 @@ void ViewerWidget::set_waveform_scroll(int s) { if (waveform) { waveform_scroll = s; update(); - } + } +} + +void ViewerWidget::set_fullscreen(int screen) { + if (screen >= 0 && screen < QGuiApplication::screens().size()) { + QScreen* selected_screen = QGuiApplication::screens().at(screen); + window->showFullScreen(); + window->setGeometry(selected_screen->geometry()); + + // HACK: window seems to show with distorted texture on first showing, so we queue an update after it's shown + QTimer::singleShot(100, window, SLOT(update())); + } else { + qCritical() << "Failed to find requested screen" << screen << "to set fullscreen to"; + } } void ViewerWidget::show_context_menu() { @@ -170,12 +183,7 @@ void ViewerWidget::fullscreen_menu_action(QAction *action) { if (action->data().isNull()) { window->hide(); } else { - QScreen* selected_screen = QGuiApplication::screens().at(action->data().toInt()); - window->showFullScreen(); - window->setGeometry(selected_screen->geometry()); - - // HACK: window seems to show with distorted texture on first showing, so we queue an update after it's shown - QTimer::singleShot(100, window, SLOT(update())); + set_fullscreen(action->data().toInt()); } } } diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index e6f0526c8..ce09c790a 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -47,6 +47,7 @@ public: void set_scroll(double x, double y); public slots: void set_waveform_scroll(int s); + void set_fullscreen(int screen = 0); protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); From db92e5231fbec55ba4af7a3a394619aad3e6b1c2 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 02:53:54 +1100 Subject: [PATCH 2/9] 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); From 0399c36dfd6511f9748811e1200a9db7483a8ddb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 10:05:22 +1100 Subject: [PATCH 3/9] added search to project toolbar --- panels/project.cpp | 6 +++++- project/projectfilter.cpp | 41 +++++++++++++++++++++++++++++++++++---- project/projectfilter.h | 20 ++++++++++++++++++- project/undo.cpp | 1 + 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/panels/project.cpp b/panels/project.cpp index 1bf591aee..80c49ede9 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -130,7 +130,11 @@ Project::Project(QWidget *parent) : connect(toolbar_redo, SIGNAL(clicked(bool)), mainWindow, SLOT(redo())); toolbar->addWidget(toolbar_redo); - toolbar->addStretch(); + QLineEdit* toolbar_search = new QLineEdit(); + toolbar_search->setPlaceholderText(tr("Search media, markers, etc.")); + connect(toolbar_search, SIGNAL(textChanged(QString)), sorter, SLOT(update_search_filter(const QString&))); + toolbar->addWidget(toolbar_search); + QPushButton* toolbar_tree_view = new QPushButton(); QIcon icon6; icon6.addFile(QStringLiteral(":/icons/treeview.png"), QSize(), QIcon::Normal, QIcon::On); diff --git a/project/projectfilter.cpp b/project/projectfilter.cpp index 798174c6e..807ad0bbc 100644 --- a/project/projectfilter.cpp +++ b/project/projectfilter.cpp @@ -1,6 +1,7 @@ #include "projectfilter.h" #include "project/media.h" +#include "project/sequence.h" #include @@ -15,17 +16,49 @@ bool ProjectFilter::get_show_sequences() { void ProjectFilter::set_show_sequences(bool b) { show_sequences = b; - invalidateFilter(); + invalidateFilter(); +} + +void ProjectFilter::update_search_filter(const QString &s) { + search_filter = s; + invalidateFilter(); } bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { + // retrieve media object from index + QModelIndex index = sourceModel()->index(source_row, 0, source_parent); + Media* media = static_cast(index.internalPointer()); + + // hide sequences if show_sequences is false if (!show_sequences) { - // hide sequences if show_sequences is false - QModelIndex index = sourceModel()->index(source_row, 0, source_parent); - Media* media = static_cast(index.internalPointer()); if (media != nullptr && media->get_type() == MEDIA_TYPE_SEQUENCE) { return false; } } + + // filter by search filter string + if (!search_filter.isEmpty()) { + // search markers if media is a sequene + bool marker_contains_search = false; + + if (media->get_type() == MEDIA_TYPE_SEQUENCE) { + Sequence* s = media->to_sequence(); + for (int i=0;imarkers.size();i++) { + qDebug() << "marker name:" << s->markers.at(i).name; + if (s->markers.at(i).name.contains(search_filter, Qt::CaseInsensitive)) { + marker_contains_search = true; + break; + } + } + } + + // hide any rows that don't contain the search string (unless it's a folder) + if (!marker_contains_search + && media->get_type() != MEDIA_TYPE_FOLDER + && !media->get_name().contains(search_filter, Qt::CaseInsensitive)) { + return false; + } + } + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } diff --git a/project/projectfilter.h b/project/projectfilter.h index 6b14bb680..848acbffd 100644 --- a/project/projectfilter.h +++ b/project/projectfilter.h @@ -7,13 +7,31 @@ class ProjectFilter : public QSortFilterProxyModel { Q_OBJECT public: ProjectFilter(QObject *parent = nullptr); + + // are sequences visible bool get_show_sequences(); + public slots: + + // set whether sequences are visible void set_show_sequences(bool b); + + // update search filter + void update_search_filter(const QString& s); + protected: - bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + + // function that filters whether rows are displayed or not + virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + private: + + // internal variable for whether to show sequences bool show_sequences; + + // search filter variable + QString search_filter; + }; #endif // PROJECTFILTER_H diff --git a/project/undo.cpp b/project/undo.cpp index ce577f855..b4fb804a8 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -842,6 +842,7 @@ void AddMarkerAction::redo() { if (index == -1) { Marker m; m.frame = time; + m.name = name; markers.append(m); } else { old_name = markers.at(index).name; From 5d4b564ba11436770acb40707cbe29ff2dc717ec Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 10:07:42 +1100 Subject: [PATCH 4/9] removed unnecessary debug out --- project/projectfilter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/project/projectfilter.cpp b/project/projectfilter.cpp index 807ad0bbc..8b084b141 100644 --- a/project/projectfilter.cpp +++ b/project/projectfilter.cpp @@ -44,7 +44,6 @@ bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_p if (media->get_type() == MEDIA_TYPE_SEQUENCE) { Sequence* s = media->to_sequence(); for (int i=0;imarkers.size();i++) { - qDebug() << "marker name:" << s->markers.at(i).name; if (s->markers.at(i).name.contains(search_filter, Qt::CaseInsensitive)) { marker_contains_search = true; break; From 4478a386af988d715920abd6548b9a5b67d2430a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 11:02:05 +1100 Subject: [PATCH 5/9] preference for changing language --- dialogs/preferencesdialog.cpp | 71 ++++++++++++++++++++++++++++------- dialogs/preferencesdialog.h | 1 + io/config.cpp | 8 +++- io/config.h | 1 + mainwindow.cpp | 11 +++++- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 85150b666..936d66bda 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "debug.h" @@ -139,8 +140,7 @@ void PreferencesDialog::save() { bool reset_audio_required = (config.preferred_audio_output != audio_output_devices->currentData().toString() || config.preferred_audio_input != audio_input_devices->currentData().toString()); config.preferred_audio_output = audio_output_devices->currentData().toString(); - config.preferred_audio_input = audio_input_devices->currentData().toString(); - qDebug() << "selected audio input" << audio_input_devices->currentData().toString(); + config.preferred_audio_input = audio_input_devices->currentData().toString(); config.audio_rate = audio_sample_rate->currentData().toInt(); // the following settings may require a restart of Olive to take effect: @@ -149,13 +149,18 @@ void PreferencesDialog::save() { if (config.effect_textbox_lines != effect_textbox_lines_field->value()) { needs_restart = true; + config.effect_textbox_lines = effect_textbox_lines_field->value(); } - config.effect_textbox_lines = effect_textbox_lines_field->value(); if (config.use_software_fallback != use_software_fallbacks_checkbox->isChecked()) { needs_restart = true; + config.use_software_fallback = use_software_fallbacks_checkbox->isChecked(); } - config.use_software_fallback = use_software_fallbacks_checkbox->isChecked(); + + if (config.language_file != language_combobox->currentData().toString()) { + needs_restart = true; + config.language_file = language_combobox->currentData().toString(); + } // save keyboard shortcuts for (int i=0;i Language + general_layout->addWidget(new QLabel(tr("Language:")), row, 0, 1, 1); + + language_combobox = new QComboBox(); + + // add default language (en-US) + language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); + + // add languages from file + QDir translation_dir(QApplication::applicationDirPath().append("/ts")); + QStringList translation_files = translation_dir.entryList({"*.qm"}, QDir::Files | QDir::NoDotAndDotDot); + for (int i=0;iaddItem(QLocale::languageToString(QLocale(locale_str).language()), locale_full_path); + + if (config.language_file == locale_full_path) { + language_combobox->setCurrentIndex(language_combobox->count() - 1); + } + } + + general_layout->addWidget(language_combobox, row, 1, 1, 2); + + row++; + // General -> Custom CSS - general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), 0, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0, 1, 1); custom_css_fn = new QLineEdit(general_tab); custom_css_fn->setText(config.css_path); - general_layout->addWidget(custom_css_fn, 0, 1, 1, 1); + general_layout->addWidget(custom_css_fn, row, 1, 1, 1); QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); - general_layout->addWidget(custom_css_browse, 0, 2, 1, 1); + general_layout->addWidget(custom_css_browse, row, 2, 1, 1); + + row++; // General -> Image Sequence Formats - general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), 1, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0, 1, 1); imgSeqFormatEdit = new QLineEdit(general_tab); - general_layout->addWidget(imgSeqFormatEdit, 1, 1, 1, 2); + general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 2); + + row++; // General -> Audio Recording - general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), 2, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0, 1, 1); recordingComboBox = new QComboBox(general_tab); recordingComboBox->addItem(tr("Mono")); recordingComboBox->addItem(tr("Stereo")); - general_layout->addWidget(recordingComboBox, 2, 1, 1, 2); + general_layout->addWidget(recordingComboBox, row, 1, 1, 2); + + row++; // General -> Effect Textbox Lines - general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), 3, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0, 1, 1); effect_textbox_lines_field = new QSpinBox(general_tab); effect_textbox_lines_field->setMinimum(1); effect_textbox_lines_field->setValue(config.effect_textbox_lines); - general_layout->addWidget(effect_textbox_lines_field, 3, 1, 1, 2); + general_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); + + row++; // General -> Use Software Fallbacks When Possible use_software_fallbacks_checkbox = new QCheckBox(general_tab); use_software_fallbacks_checkbox->setText(tr("Use Software Fallbacks When Possible")); use_software_fallbacks_checkbox->setChecked(config.use_software_fallback); - general_layout->addWidget(use_software_fallbacks_checkbox, 4, 0, 1, 1); + general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 1); tabWidget->addTab(general_tab, tr("General")); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 2e8243fda..4679ce0da 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -65,6 +65,7 @@ private: QComboBox* audio_output_devices; QComboBox* audio_input_devices; QComboBox* audio_sample_rate; + QComboBox* language_combobox; QVector key_shortcut_actions; QVector key_shortcut_items; diff --git a/io/config.cpp b/io/config.cpp index 2a3122557..4e0f83a5a 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -179,7 +179,10 @@ void Config::load(QString path) { } else if (stream.name() == "PreferredAudioInput") { stream.readNext(); preferred_audio_input = stream.text().toString(); - } + } else if (stream.name() == "LanguageFile") { + stream.readNext(); + language_file = stream.text().toString(); + } } } if (stream.hasError()) { @@ -242,7 +245,8 @@ void Config::save(QString path) { stream.writeTextElement("UseSoftwareFallback", QString::number(use_software_fallback)); stream.writeTextElement("CenterTimelineTimecodes", QString::number(center_timeline_timecodes)); stream.writeTextElement("PreferredAudioOutput", preferred_audio_output); - stream.writeTextElement("PreferredAudioInput", preferred_audio_input); + stream.writeTextElement("PreferredAudioInput", preferred_audio_input); + stream.writeTextElement("LanguageFile", language_file); stream.writeEndElement(); // configuration stream.writeEndDocument(); // doc diff --git a/io/config.h b/io/config.h index c01ee0ee3..90d83b32c 100644 --- a/io/config.h +++ b/io/config.h @@ -66,6 +66,7 @@ struct Config { bool center_timeline_timecodes; QString preferred_audio_output; QString preferred_audio_input; + QString language_file; void load(QString path); void save(QString path); diff --git a/mainwindow.cpp b/mainwindow.cpp index 582a8049d..394a09ed5 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -50,6 +50,7 @@ #include #include #include +#include MainWindow* mainWindow; @@ -205,10 +206,18 @@ MainWindow::MainWindow(QWidget *parent, const QString &an) : } } + // load preferred language from file + if (!config.language_file.isEmpty() + && QFileInfo::exists(config.language_file)) { + QTranslator* translator = new QTranslator(this); + translator->load(config.language_file); + QApplication::installTranslator(translator); + } + alloc_panels(this); QStatusBar* statusBar = new QStatusBar(this); - statusBar->showMessage("Welcome to " + appName); + statusBar->showMessage(tr("Welcome to %1").arg(appName)); setStatusBar(statusBar); setup_menus(); From 6a3c22bcd461a9f8816bb2709b5750243dcb39f7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 11:22:18 +1100 Subject: [PATCH 6/9] use native language names --- dialogs/preferencesdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 936d66bda..a29e4f0eb 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -327,7 +327,7 @@ void PreferencesDialog::setup_ui() { QFileInfo locale_file(translation_files.at(i)); QString locale_file_basename = locale_file.baseName(); QString locale_str = locale_file_basename.mid(locale_file_basename.lastIndexOf('_')+1); - language_combobox->addItem(QLocale::languageToString(QLocale(locale_str).language()), locale_full_path); + language_combobox->addItem(QLocale(locale_str).nativeLanguageName(), locale_full_path); if (config.language_file == locale_full_path) { language_combobox->setCurrentIndex(language_combobox->count() - 1); From a34b4463028e3002f445243cfd8415c74e244a7e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 16:06:42 +1100 Subject: [PATCH 7/9] updated snap for 16.04 --- snap/snapcraft.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cf7350087..a31bf2697 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -23,6 +23,7 @@ apps: - pulseaudio - home - removable-media + - unity7 parts: olive: From 2da663d0570a7696bf4fc798e5aac0b560f875a4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 18:39:26 +1100 Subject: [PATCH 8/9] added settings for waveform/thumbnail resolution --- dialogs/preferencesdialog.cpp | 170 +++++++++++++++++++++++++--------- dialogs/preferencesdialog.h | 4 +- io/config.cpp | 24 +++-- io/config.h | 4 +- io/previewgenerator.cpp | 7 +- 5 files changed, 152 insertions(+), 57 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index a29e4f0eb..2e5e8ef81 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -1,6 +1,7 @@ #include "preferencesdialog.h" #include "io/config.h" +#include "io/path.h" #include "playback/audio.h" #include "mainwindow.h" @@ -140,7 +141,7 @@ void PreferencesDialog::save() { bool reset_audio_required = (config.preferred_audio_output != audio_output_devices->currentData().toString() || config.preferred_audio_input != audio_input_devices->currentData().toString()); config.preferred_audio_output = audio_output_devices->currentData().toString(); - config.preferred_audio_input = audio_input_devices->currentData().toString(); + config.preferred_audio_input = audio_input_devices->currentData().toString(); config.audio_rate = audio_sample_rate->currentData().toInt(); // the following settings may require a restart of Olive to take effect: @@ -149,18 +150,81 @@ void PreferencesDialog::save() { if (config.effect_textbox_lines != effect_textbox_lines_field->value()) { needs_restart = true; - config.effect_textbox_lines = effect_textbox_lines_field->value(); + config.effect_textbox_lines = effect_textbox_lines_field->value(); } if (config.use_software_fallback != use_software_fallbacks_checkbox->isChecked()) { needs_restart = true; - config.use_software_fallback = use_software_fallbacks_checkbox->isChecked(); + config.use_software_fallback = use_software_fallbacks_checkbox->isChecked(); } - if (config.language_file != language_combobox->currentData().toString()) { - needs_restart = true; - config.language_file = language_combobox->currentData().toString(); - } + if (config.language_file != language_combobox->currentData().toString()) { + needs_restart = true; + config.language_file = language_combobox->currentData().toString(); + } + + if (config.thumbnail_resolution != thumbnail_res_spinbox->value() + || config.waveform_resolution != waveform_res_spinbox->value()) { + // we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start + + needs_restart = true; + + // delete nothing + char delete_match = 0; + + if (config.thumbnail_resolution != thumbnail_res_spinbox->value()) { + // delete existing thumbnails + config.thumbnail_resolution = thumbnail_res_spinbox->value(); + + // delete only thumbnails + delete_match = 't'; + } + + if (config.waveform_resolution != waveform_res_spinbox->value()) { + // delete existing waveforms + config.waveform_resolution = waveform_res_spinbox->value(); + + // if we're already deleting thumbnails + if (delete_match == 't') { + // delete all + delete_match = 1; + } else { + // just delete waveforms + delete_match = 'w'; + } + } + + if (delete_match != 0) { + QDir preview_path(get_data_path() + "/previews"); + + if (delete_match == 1) { + // indiscriminately delete everything + preview_path.removeRecursively(); + } else { + QStringList preview_file_list = preview_path.entryList(QDir::Files | QDir::NoDotAndDotDot); + for (int i=0;i= 0 + && preview_file_str.at(identifier_char_index) >= 48 + && preview_file_str.at(identifier_char_index) <= 57) { + identifier_char_index--; + } + + // thumbnails will have a 't' towards the end of the filenames, waveforms will have a 'w' + // if they match the type of preview we're deleting, remove them + if (preview_file_str.at(identifier_char_index) == delete_match) { + QFile::remove(preview_path.filePath(preview_file_str)); + } + } + } + } + } // save keyboard shortcuts for (int i=0;i Language - general_layout->addWidget(new QLabel(tr("Language:")), row, 0, 1, 1); + // General -> Language + general_layout->addWidget(new QLabel(tr("Language:")), row, 0, 1, 1); - language_combobox = new QComboBox(); + language_combobox = new QComboBox(); - // add default language (en-US) - language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); + // add default language (en-US) + language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); - // add languages from file - QDir translation_dir(QApplication::applicationDirPath().append("/ts")); - QStringList translation_files = translation_dir.entryList({"*.qm"}, QDir::Files | QDir::NoDotAndDotDot); - for (int i=0;iaddItem(QLocale(locale_str).nativeLanguageName(), locale_full_path); + // add languages from file + QDir translation_dir(QApplication::applicationDirPath().append("/ts")); + QStringList translation_files = translation_dir.entryList({"*.qm"}, QDir::Files | QDir::NoDotAndDotDot); + for (int i=0;iaddItem(QLocale(locale_str).nativeLanguageName(), locale_full_path); - if (config.language_file == locale_full_path) { - language_combobox->setCurrentIndex(language_combobox->count() - 1); - } - } + if (config.language_file == locale_full_path) { + language_combobox->setCurrentIndex(language_combobox->count() - 1); + } + } - general_layout->addWidget(language_combobox, row, 1, 1, 2); + general_layout->addWidget(language_combobox, row, 1, 1, 3); - row++; + row++; // General -> Custom CSS - general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0, 1, 1); custom_css_fn = new QLineEdit(general_tab); custom_css_fn->setText(config.css_path); - general_layout->addWidget(custom_css_fn, row, 1, 1, 1); + general_layout->addWidget(custom_css_fn, row, 1, 1, 2); QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); - general_layout->addWidget(custom_css_browse, row, 2, 1, 1); + general_layout->addWidget(custom_css_browse, row, 3, 1, 1); - row++; + row++; // General -> Image Sequence Formats - general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0, 1, 1); imgSeqFormatEdit = new QLineEdit(general_tab); - general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 2); + general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 3); - row++; + row++; // General -> Audio Recording - general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0, 1, 1); recordingComboBox = new QComboBox(general_tab); recordingComboBox->addItem(tr("Mono")); recordingComboBox->addItem(tr("Stereo")); - general_layout->addWidget(recordingComboBox, row, 1, 1, 2); + general_layout->addWidget(recordingComboBox, row, 1, 1, 3); - row++; + row++; // General -> Effect Textbox Lines - general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0, 1, 1); + general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0, 1, 1); effect_textbox_lines_field = new QSpinBox(general_tab); effect_textbox_lines_field->setMinimum(1); effect_textbox_lines_field->setValue(config.effect_textbox_lines); - general_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); + general_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 3); - row++; + row++; + + // General -> Thumbnail and Waveform Resolution + general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0, 1, 1); + + thumbnail_res_spinbox = new QSpinBox(this); + thumbnail_res_spinbox->setMinimum(1); + thumbnail_res_spinbox->setMaximum(INT_MAX); + thumbnail_res_spinbox->setValue(config.thumbnail_resolution); + general_layout->addWidget(thumbnail_res_spinbox, row, 1, 1, 1); + + general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2, 1, 1); + + waveform_res_spinbox = new QSpinBox(this); + waveform_res_spinbox->setMinimum(1); + waveform_res_spinbox->setMaximum(INT_MAX); + waveform_res_spinbox->setValue(config.waveform_resolution); + general_layout->addWidget(waveform_res_spinbox, row, 3, 1, 1); + + + row++; // General -> Use Software Fallbacks When Possible use_software_fallbacks_checkbox = new QCheckBox(general_tab); use_software_fallbacks_checkbox->setText(tr("Use Software Fallbacks When Possible")); use_software_fallbacks_checkbox->setChecked(config.use_software_fallback); - general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 1); + general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 4); tabWidget->addTab(general_tab, tr("General")); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 4679ce0da..f086c1c40 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -65,7 +65,9 @@ private: QComboBox* audio_output_devices; QComboBox* audio_input_devices; QComboBox* audio_sample_rate; - QComboBox* language_combobox; + QComboBox* language_combobox; + QSpinBox* thumbnail_res_spinbox; + QSpinBox* waveform_res_spinbox; QVector key_shortcut_actions; QVector key_shortcut_items; diff --git a/io/config.cpp b/io/config.cpp index 4e0f83a5a..a3f356794 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -48,7 +48,9 @@ Config::Config() seek_also_selects(false), effect_textbox_lines(3), use_software_fallback(false), - center_timeline_timecodes(true) + center_timeline_timecodes(true), + waveform_resolution(64), + thumbnail_resolution(120) {} void Config::load(QString path) { @@ -179,10 +181,16 @@ void Config::load(QString path) { } else if (stream.name() == "PreferredAudioInput") { stream.readNext(); preferred_audio_input = stream.text().toString(); - } else if (stream.name() == "LanguageFile") { - stream.readNext(); - language_file = stream.text().toString(); - } + } else if (stream.name() == "LanguageFile") { + stream.readNext(); + language_file = stream.text().toString(); + } else if (stream.name() == "ThumbnailResolution") { + stream.readNext(); + thumbnail_resolution = stream.text().toInt(); + } else if (stream.name() == "WaveformResolution") { + stream.readNext(); + waveform_resolution = stream.text().toInt(); + } } } if (stream.hasError()) { @@ -245,8 +253,10 @@ void Config::save(QString path) { stream.writeTextElement("UseSoftwareFallback", QString::number(use_software_fallback)); stream.writeTextElement("CenterTimelineTimecodes", QString::number(center_timeline_timecodes)); stream.writeTextElement("PreferredAudioOutput", preferred_audio_output); - stream.writeTextElement("PreferredAudioInput", preferred_audio_input); - stream.writeTextElement("LanguageFile", language_file); + stream.writeTextElement("PreferredAudioInput", preferred_audio_input); + stream.writeTextElement("LanguageFile", language_file); + stream.writeTextElement("ThumbnailResolution", QString::number(thumbnail_resolution)); + stream.writeTextElement("WaveformResolution", QString::number(waveform_resolution)); stream.writeEndElement(); // configuration stream.writeEndDocument(); // doc diff --git a/io/config.h b/io/config.h index 90d83b32c..ec6d2af89 100644 --- a/io/config.h +++ b/io/config.h @@ -66,7 +66,9 @@ struct Config { bool center_timeline_timecodes; QString preferred_audio_output; QString preferred_audio_input; - QString language_file; + QString language_file; + int waveform_resolution; + int thumbnail_resolution; void load(QString path); void save(QString path); diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index ca2fd3bbe..e1da9262b 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -18,9 +18,6 @@ #include #include -#define WAVEFORM_RESOLUTION 64 -#define THUMBNAIL_RESOLUTION 120 - extern "C" { #include #include @@ -278,7 +275,7 @@ void PreviewGenerator::generate_waveform() { if (s != nullptr) { if (fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (!s->preview_done) { - int dstH = THUMBNAIL_RESOLUTION; + int dstH = config.thumbnail_resolution; int dstW = qRound(dstH * (float(temp_frame->width)/float(temp_frame->height))); uint8_t* data = new uint8_t[size_t(dstW*dstH*4)]; @@ -317,7 +314,7 @@ void PreviewGenerator::generate_waveform() { } media_lengths[packet->stream_index]++; } else if (fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4; + int interval = qFloor((temp_frame->sample_rate/config.waveform_resolution)/4)*4; AVFrame* swr_frame = av_frame_alloc(); swr_frame->channel_layout = temp_frame->channel_layout; From 3b276fea40268c608d2d9a19542279a75ad218bb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 1 Feb 2019 18:50:34 +1100 Subject: [PATCH 9/9] improved waveform drawing for higher density waveforms --- ui/timelinewidget.cpp | 79 ++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 596fb9b3a..bf0ee5e55 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1245,7 +1245,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { for (int i=0;ighosts.size();i++) { const Ghost& g = panel_timeline->ghosts.at(i); - // snap ghost's in point + // 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)) { @@ -1254,7 +1254,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } } - // snap ghost's out point + // 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)) { @@ -1263,18 +1263,18 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } } - // 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; - } - } - } + // 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; + } + } + } } } @@ -2164,8 +2164,11 @@ void draw_waveform(Clip* clip, const FootageStream* ms, long media_length, QPain int divider = ms->audio_channels*2; int channel_height = clip_rect.height()/ms->audio_channels; + int last_waveform_index = -1; + for (int i=waveform_start;iclip_in + ((double) i/zoom))/media_length) * ms->audio_preview.size())/divider)*divider; + if (last_waveform_index < 0) last_waveform_index = waveform_index; if (clip->reverse) { waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2); @@ -2173,21 +2176,35 @@ void draw_waveform(Clip* clip, const FootageStream* ms, long media_length, QPain for (int j=0;jaudio_channels;j++) { int mid = (config.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2); - int offset = waveform_index+(j*2); - if ((offset + 1) < ms->audio_preview.size()) { - qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2); - qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2); + int offset_range_start = last_waveform_index+(j*2); + int offset_range_end = waveform_index+(j*2); + qint8 min = qint8(qRound(double(ms->audio_preview.at(offset_range_start)) / 128.0 * (channel_height/2))); + qint8 max = qint8(qRound(double(ms->audio_preview.at(offset_range_start+1)) / 128.0 * (channel_height/2))); + + if ((offset_range_end + 1) < ms->audio_preview.size()) { + + // for waveform drawings, we get the maximum below 0 and maximum above 0 for this waveform range + for (int k=offset_range_start+2;k<=offset_range_end;k+=2) { + min = qMin(min, qint8(qRound(double(ms->audio_preview.at(k)) / 128.0 * (channel_height/2)))); + max = qMax(max, qint8(qRound(double(ms->audio_preview.at(k+1)) / 128.0 * (channel_height/2)))); + } + + // draw waveforms if (config.rectified_waveforms) { + + // rectified waveforms start from the bottom and draw upwards p->drawLine(clip_rect.left()+i, mid, clip_rect.left()+i, mid - (max - min)); } else { + + // non-rectified waveforms start from the center and draw outwards p->drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); + } - }/* else { - qWarning() << "Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size(); - }*/ + } } + last_waveform_index = waveform_index; } } @@ -2411,17 +2428,17 @@ void TimelineWidget::paintEvent(QPaintEvent*) { } } - // draw clip markers - for (int j=0;jmarkers.size();j++) { - const Marker& m = clip->markers.at(j); + // 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); - } - } + // 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);