From 3d434f33aa5bd4a5a412ba91ac6b0326c00aa88f Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Tue, 19 Jun 2018 00:37:31 +0200 Subject: [PATCH] Add some playlist manipulation controls. --- clip_list.cpp | 28 +++++++++++++ clip_list.h | 7 ++++ mainwindow.cpp | 78 +++++++++++++++++++++++++++++++++++ mainwindow.h | 6 +++ ui_mainwindow.ui | 103 ++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 213 insertions(+), 9 deletions(-) diff --git a/clip_list.cpp b/clip_list.cpp index e15fbfe..373ef0f 100644 --- a/clip_list.cpp +++ b/clip_list.cpp @@ -304,6 +304,34 @@ void PlayList::add_clip(const Clip &clip) endInsertRows(); } +void PlayList::duplicate_clips(size_t first, size_t last) +{ + beginInsertRows(QModelIndex(), first, last); + clips.insert(clips.begin() + first, clips.begin() + first, clips.begin() + last + 1); + endInsertRows(); +} + +void PlayList::erase_clips(size_t first, size_t last) +{ + beginRemoveRows(QModelIndex(), first, last); + clips.erase(clips.begin() + first, clips.begin() + last + 1); + endRemoveRows(); +} + +void PlayList::move_clips(size_t first, size_t last, int delta) +{ + if (delta == -1) { + beginMoveRows(QModelIndex(), first, last, QModelIndex(), first - 1); + rotate(clips.begin() + first - 1, clips.begin() + first, clips.begin() + last + 1); + } else { + beginMoveRows(QModelIndex(), first, last, QModelIndex(), first + (last-first+1) + 1); + first = clips.size() - first - 1; + last = clips.size() - last - 1; + rotate(clips.rbegin() + last - 1, clips.rbegin() + last, clips.rbegin() + first + 1); + } + endMoveRows(); +} + void ClipList::emit_data_changed(size_t row) { emit dataChanged(index(row, 0), index(row, int(Column::NUM_COLUMNS))); diff --git a/clip_list.h b/clip_list.h index 64d06cd..126d1d5 100644 --- a/clip_list.h +++ b/clip_list.h @@ -104,6 +104,13 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; void add_clip(const Clip &clip); + + // is inclusive in all of these. + void duplicate_clips(size_t first, size_t last); + void erase_clips(size_t first, size_t last); + // is -1 to move upwards, +1 to move downwards. + void move_clips(size_t first, size_t last, int delta); + size_t size() const { return clips.size(); } bool empty() const { return clips.empty(); } diff --git a/mainwindow.cpp b/mainwindow.cpp index 04b4e56..6b100ac 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -74,6 +74,19 @@ MainWindow::MainWindow() connect(preview_4, &QShortcut::activated, ui->preview_4_btn, &QPushButton::click); connect(ui->preview_4_btn, &QPushButton::clicked, [this]{ preview_angle_clicked(3); }); + connect(ui->playlist_duplicate_btn, &QPushButton::clicked, this, &MainWindow::playlist_duplicate); + + // TODO: support the delete key iff the widget has focus? + connect(ui->playlist_remove_btn, &QPushButton::clicked, this, &MainWindow::playlist_remove); + + // TODO: support drag-and-drop. + connect(ui->playlist_move_up_btn, &QPushButton::clicked, [this]{ playlist_move(-1); }); + connect(ui->playlist_move_down_btn, &QPushButton::clicked, [this]{ playlist_move(1); }); + + connect(ui->playlist->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &MainWindow::playlist_selection_changed); + playlist_selection_changed(); // First time set-up. + preview_player = new Player(ui->preview_display); live_player = new Player(ui->live_display); live_player->set_done_callback([this]{ @@ -92,6 +105,7 @@ void MainWindow::cue_in_clicked() Clip clip; clip.pts_in = current_pts; cliplist_clips->add_clip(clip); + playlist_selection_changed(); } void MainWindow::cue_out_clicked() @@ -122,6 +136,7 @@ void MainWindow::queue_clicked() Clip clip = *cliplist_clips->clip(index.row()); clip.stream_idx = index.column() - int(ClipList::Column::CAMERA_1); playlist_clips->add_clip(clip); + playlist_selection_changed(); } } @@ -158,6 +173,55 @@ void MainWindow::preview_angle_clicked(unsigned stream_idx) } } +void MainWindow::playlist_duplicate() +{ + QItemSelectionModel *selected = ui->playlist->selectionModel(); + if (!selected->hasSelection()) { + // Should have been grayed out, but OK. + return; + } + QModelIndexList rows = selected->selectedRows(); + int first = rows.front().row(), last = rows.back().row(); + playlist_clips->duplicate_clips(first, last); + playlist_selection_changed(); +} + +void MainWindow::playlist_remove() +{ + QItemSelectionModel *selected = ui->playlist->selectionModel(); + if (!selected->hasSelection()) { + // Should have been grayed out, but OK. + return; + } + QModelIndexList rows = selected->selectedRows(); + int first = rows.front().row(), last = rows.back().row(); + playlist_clips->erase_clips(first, last); + + // TODO: select the next one in the list? + + playlist_selection_changed(); +} + +void MainWindow::playlist_move(int delta) +{ + QItemSelectionModel *selected = ui->playlist->selectionModel(); + if (!selected->hasSelection()) { + // Should have been grayed out, but OK. + return; + } + + QModelIndexList rows = selected->selectedRows(); + int first = rows.front().row(), last = rows.back().row(); + if ((delta == -1 && first == 0) || + (delta == 1 && size_t(last) == playlist_clips->size() - 1)) { + // Should have been grayed out, but OK. + return; + } + + playlist_clips->move_clips(first, last, delta); + playlist_selection_changed(); +} + void MainWindow::play_clicked() { if (playlist_clips->empty()) return; @@ -173,6 +237,7 @@ void MainWindow::play_clicked() const Clip &clip = *playlist_clips->clip(row); live_player->play_clip(clip, clip.stream_idx); playlist_clips->set_currently_playing(row); + playlist_selection_changed(); } void MainWindow::live_player_clip_done() @@ -365,3 +430,16 @@ void MainWindow::preview_single_frame(int64_t pts, unsigned stream_idx, MainWind fake_clip.pts_out = pts + 1; preview_player->play_clip(fake_clip, stream_idx); } + +void MainWindow::playlist_selection_changed() +{ + QItemSelectionModel *selected = ui->playlist->selectionModel(); + bool any_selected = selected->hasSelection(); + ui->playlist_duplicate_btn->setEnabled(any_selected); + ui->playlist_remove_btn->setEnabled(any_selected); + ui->playlist_move_up_btn->setEnabled( + any_selected && selected->selectedRows().front().row() > 0); + ui->playlist_move_down_btn->setEnabled( + any_selected && selected->selectedRows().back().row() < int(playlist_clips->size()) - 1); + ui->play_btn->setEnabled(!playlist_clips->empty()); +} diff --git a/mainwindow.h b/mainwindow.h index 76124ae..8deca18 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -43,10 +43,16 @@ private: void preview_angle_clicked(unsigned stream_idx); void play_clicked(); void live_player_clip_done(); + void playlist_duplicate(); + void playlist_remove(); + void playlist_move(int delta); enum Rounding { FIRST_AT_OR_AFTER, LAST_BEFORE }; void preview_single_frame(int64_t pts, unsigned stream_idx, Rounding rounding); + // Also covers when the playlist itself changes. + void playlist_selection_changed(); + void resizeEvent(QResizeEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override; diff --git a/ui_mainwindow.ui b/ui_mainwindow.ui index 2dd07d7..183fcea 100644 --- a/ui_mainwindow.ui +++ b/ui_mainwindow.ui @@ -162,12 +162,18 @@ - + + + + Queue (&Q) + + + @@ -175,6 +181,9 @@ Preview (&W) + + + @@ -192,27 +201,103 @@ - - - Play (space) + + + Qt::Horizontal - + + + 40 + 20 + + + - - - - QAbstractItemView::SingleSelection + QAbstractItemView::ContiguousSelection QAbstractItemView::SelectRows + + + + + + Duplicate + + + + + + + + + + + 0 + 0 + + + + Remove + + + + + + + + + + Move up + + + + + + + + + + Move down + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Play (space) + + + + + + + + -- 2.39.2