-string format_timestamp(uint64_t pos)
-{
- int ms = pos % 1000;
- pos /= 1000;
- int sec = pos % 60;
- pos /= 60;
- int min = pos % 60;
- int hour = pos / 60;
-
- char buf[256];
- snprintf(buf, sizeof(buf), "%d:%02d:%02d.%03d", hour, min, sec, ms);
- return buf;
-}
-
-MainWindow::MainWindow(EventsModel *events, PlayersModel *players) : events(events), players(players)
-{
- video = new QMediaPlayer;
- //video->setSource(QUrl::fromLocalFile("/home/sesse/dev/stats/ultimate.mkv"));
- video->setSource(QUrl::fromLocalFile("/home/sesse/dev/stats/ultimate-prores.mkv"));
- video->play();
-
- ui = new Ui::MainWindow;
- ui->setupUi(this);
-
- ui->event_view->setModel(events);
- connect(ui->event_view->selectionModel(), &QItemSelectionModel::currentRowChanged,
- [this, events](const QModelIndex ¤t, const QModelIndex &previous) {
- uint64_t t = events->get_time(current.row());
- if (t != video->position()) {
- video->setPosition(events->get_time(current.row()));
- } else {
- // Selection could have changed, so we still need to update.
- // (Just calling setPosition() would not give us the signal
- // in this case.)
- update_ui_from_time(t);
- }
- });
-
- ui->player_view->setModel(players);
-
- connect(video, &QMediaPlayer::positionChanged, [this](uint64_t pos) {
- position_changed(pos);
- });
-
- video->setVideoOutput(ui->video);
-
- connect(ui->minus10s, &QPushButton::clicked, [this]() { seek(-10000); });
- connect(ui->plus10s, &QPushButton::clicked, [this]() { seek(10000); });
-
- connect(ui->minus2s, &QPushButton::clicked, [this]() { seek(-2000); });
- connect(ui->plus2s, &QPushButton::clicked, [this]() { seek(2000); });
-
- // TODO: Would be nice to actually have a frame...
- connect(ui->minus1f, &QPushButton::clicked, [this]() { seek(-20); });
- connect(ui->plus1f, &QPushButton::clicked, [this]() { seek(20); });
-
- connect(ui->play_pause, &QPushButton::clicked, [this]() {
- if (playing) {
- video->pause();
- ui->play_pause->setText("Play (space)");
- } else {
- video->setPlaybackRate(1.0);
- video->play();
- ui->play_pause->setText("Pause (space)");
- }
- playing = !playing;
-
- // Needs to be set anew when we modify setText(), evidently.
- ui->play_pause->setShortcut(QCoreApplication::translate("MainWindow", "Space", nullptr));
- });
-
- connect(ui->player_1, &QPushButton::clicked, [this]() { insert_event(1); });
- connect(ui->player_2, &QPushButton::clicked, [this]() { insert_event(2); });
- connect(ui->player_3, &QPushButton::clicked, [this]() { insert_event(3); });
- connect(ui->player_4, &QPushButton::clicked, [this]() { insert_event(4); });
- connect(ui->player_5, &QPushButton::clicked, [this]() { insert_event(5); });
- connect(ui->player_6, &QPushButton::clicked, [this]() { insert_event(6); });
- connect(ui->player_7, &QPushButton::clicked, [this]() { insert_event(7); });
-
- // Offensive events
- connect(ui->offense_label, &ClickableLabel::clicked, [this]() { insert_noplayer_event("set_offense"); });
- connect(ui->catch_, &QPushButton::clicked, [this]() { set_current_event_type("catch"); });
- connect(ui->throwaway, &QPushButton::clicked, [this, events]() {
- EventsModel::Status s = events->get_status_at(video->position());
- if (s.attack_state == EventsModel::Status::DEFENSE && s.pull_state == EventsModel::Status::PULL_IN_AIR) {
- insert_noplayer_event("pull_oob");
- } else {
- set_current_event_type("throwaway");
- }
- });
- connect(ui->drop, &QPushButton::clicked, [this]() { set_current_event_type("drop"); });
- connect(ui->goal, &QPushButton::clicked, [this]() { set_current_event_type("goal"); });
- connect(ui->offensive_soft_plus, &QPushButton::clicked, [this]() { set_current_event_type("offensive_soft_plus"); });
- connect(ui->offensive_soft_minus, &QPushButton::clicked, [this]() { set_current_event_type("offensive_soft_minus"); });
- connect(ui->pull, &QPushButton::clicked, [this, events]() {
- EventsModel::Status s = events->get_status_at(video->position());
- if (s.pull_state == EventsModel::Status::SHOULD_PULL) {
- set_current_event_type("pull");
- } else if (EventsModel::Status::PULL_IN_AIR) {
- insert_noplayer_event("pull_landed");
- }
- });
-
- // Defensive events (TODO add more)
- connect(ui->defense_label, &ClickableLabel::clicked, [this]() { insert_noplayer_event("set_defense"); });
- connect(ui->their_throwaway, &QPushButton::clicked, [this]() { insert_noplayer_event("their_throwaway"); });
- connect(ui->their_goal, &QPushButton::clicked, [this]() { insert_noplayer_event("their_goal"); });
- connect(ui->their_pull, &QPushButton::clicked, [this, events]() {
- EventsModel::Status s = events->get_status_at(video->position());
- if (s.pull_state == EventsModel::Status::SHOULD_PULL) {
- insert_noplayer_event("their_pull");
- }
- });
- connect(ui->our_defense, &QPushButton::clicked, [this]() { set_current_event_type("defense"); });
- connect(ui->defensive_soft_plus, &QPushButton::clicked, [this]() { set_current_event_type("defensive_soft_plus"); });
- connect(ui->defensive_soft_minus, &QPushButton::clicked, [this]() { set_current_event_type("defensive_soft_minus"); });
-
- // Misc. events
- connect(ui->substitution, &QPushButton::clicked, [this]() { make_substitution(); });
- connect(ui->stoppage, &QPushButton::clicked, [this, events]() {
- EventsModel::Status s = events->get_status_at(video->position());
- if (s.stoppage) {
- insert_noplayer_event("restart");
- } else {
- insert_noplayer_event("stoppage");
- }
- });
- connect(ui->unknown, &QPushButton::clicked, [this]() { insert_noplayer_event("unknown"); });
-
- QShortcut *key_delete = new QShortcut(QKeySequence(Qt::Key_Delete), this);
- connect(key_delete, &QShortcut::activated, [this]() { ui->delete_->animateClick(); });
- connect(ui->delete_, &QPushButton::clicked, [this]() { delete_current_event(); });
-}
-
-void MainWindow::position_changed(uint64_t pos)
-{
- ui->timestamp->setText(QString::fromUtf8(format_timestamp(pos)));
- if (buffered_seek) {
- video->setPosition(*buffered_seek);
- buffered_seek.reset();
- }
- if (!playing) {
- video->pause(); // We only played to get a picture.
- }
- if (playing) {
- QModelIndex row = events->get_last_event_qt(video->position());
- ui->event_view->scrollTo(row, QAbstractItemView::PositionAtCenter);
- }
- update_ui_from_time(pos);
-}
-
-void MainWindow::seek(int64_t delta_ms)
-{
- int64_t current_pos = buffered_seek ? *buffered_seek : video->position();
- uint64_t pos = max<int64_t>(current_pos + delta_ms, 0);
- buffered_seek = pos;
- if (!playing) {
- video->setPlaybackRate(0.01);
- video->play(); // Or Qt won't show the seek.
- }
-}
-
-void MainWindow::insert_event(int button_id)