]> git.sesse.net Git - pkanalytics/commitdiff
Make it possible to sub (in/out events only, no real effect).
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 1 May 2023 16:06:44 +0000 (18:06 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 1 May 2023 16:06:44 +0000 (18:06 +0200)
events.cpp
events.h
main.cpp
mainwindow.h
mainwindow.ui
players.h

index 4ce3e86c67604f3692ea68bc8a29c7e992feb754..a2d5e07b82df5743f2bd13f5f11266de322f2b9c 100644 (file)
@@ -117,7 +117,7 @@ void EventsModel::load_data()
        }
 }
 
-unsigned EventsModel::insert_event(uint64_t t, int player_id)
+unsigned EventsModel::insert_event(uint64_t t, int player_id, const string &type)
 {
        auto it = lower_bound(events.begin(), events.end(), t,
                [](const Event &e, uint64_t t) { return e.t < t; });
@@ -127,7 +127,7 @@ unsigned EventsModel::insert_event(uint64_t t, int player_id)
        Event e;
        e.t = t;
        e.player_id = player_id;
-       e.type = "unknown";
+       e.type = type;
        events.insert(events.begin() + pos, e);
 
        endInsertRows();
@@ -142,7 +142,7 @@ unsigned EventsModel::insert_event(uint64_t t, int player_id)
 
        sqlite3_bind_int64(stmt, 1, t);
        sqlite3_bind_int64(stmt, 2, player_id);
-       sqlite3_bind_text(stmt, 3, e.type.data(), e.type.size(), SQLITE_STATIC);
+       sqlite3_bind_text(stmt, 3, type.data(), type.size(), SQLITE_STATIC);
 
        ret = sqlite3_step(stmt);
        if (ret == SQLITE_ROW) {
@@ -257,3 +257,20 @@ EventsModel::Status EventsModel::get_status_at(uint64_t t)
        s.possession_sec = (s.offense && last_gained_possession != 0) ? (t - last_gained_possession) / 1000 : 0;
        return s;
 }
+
+set<int> EventsModel::get_team_at(uint64_t t)
+{
+       set<int> team;
+       for (const Event &e : events) {
+               if (e.t > t) {
+                       break;
+               }
+               if (e.type == "in") {
+                       team.insert(*e.player_id);
+               }
+               if (e.type == "out") {
+                       team.erase(*e.player_id);
+               }
+       }
+       return team;
+}
index 910e2b92a6517ad88803e16b9b42a405fa010e9a..946ebb543b2dc7db95a6bb4461f1df3c35cdd205 100644 (file)
--- a/events.h
+++ b/events.h
@@ -7,6 +7,7 @@
 #include <map>
 #include <vector>
 #include <optional>
+#include <set>
 
 class EventsModel : public QAbstractTableModel
 {
@@ -24,7 +25,7 @@ public:
        QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
        QVariant data(const QModelIndex &index, int role) const override;
 
-       unsigned insert_event(uint64_t t, int player_id);  // Returns the row.
+       unsigned insert_event(uint64_t t, int player_id, const std::string &type = "unknown");  // Returns the row.
        void delete_event(unsigned row);
        void set_event_type(unsigned row, const std::string &type);
        uint64_t get_time(unsigned row) { return events[row].t; }
@@ -36,6 +37,7 @@ public:
                unsigned possession_sec;
        };
        Status get_status_at(uint64_t t);
+       std::set<int> get_team_at(uint64_t t);
 
 private:
        struct Player {
index 2e083b89cca286581b5c4a19ccef331fc4588d72..dd23d8aac39a0c61c7ac6fc6994cc21d0a954b3a 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -98,6 +98,8 @@ MainWindow::MainWindow(EventsModel *events, PlayersModel *players) : events(even
        connect(ui->pull, &QPushButton::clicked, [this]() { set_current_event_type("pull"); });
        connect(ui->pull_landed, &QPushButton::clicked, [this]() { set_current_event_type("pull_landed"); });
 
+       connect(ui->substitution, &QPushButton::clicked, [this]() { make_substitution(); });
+
        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(); });
@@ -158,6 +160,37 @@ void MainWindow::delete_current_event()
        update_status();
 }
 
+void MainWindow::make_substitution()
+{
+       QItemSelectionModel *select = ui->player_view->selectionModel();
+
+       // FIXME: we should backdate t to start of point (last goal, or 0) if:
+       // - no players we're removing have had actions yet
+       // - there have been no other in/out events
+       //
+       // ...but if so, we might need to modify in/out events that are already there
+       // (perhaps just overwrite them all?)
+       uint64_t t = player->position();
+
+       set<int> old_team = events->get_team_at(t);
+       set<int> new_team;
+
+       for (QModelIndex row : select->selectedRows()) {
+               new_team.insert(players->get_player_id(row.row()));
+       }
+
+       for (int player_id : old_team) {
+               if (!new_team.count(player_id)) {
+                       events->insert_event(t, player_id, "out");
+               }
+       }
+       for (int player_id : new_team) {
+               if (!old_team.count(player_id)) {
+                       events->insert_event(t, player_id, "in");
+               }
+       }
+}
+
 void MainWindow::update_status()
 {
        EventsModel::Status s = events->get_status_at(player->position());
index 079a3713b3e8bb873713a4bb55a55aea96d48c63..9f27068b0dc5089cd710c55f0c795c2c256ae05b 100644 (file)
@@ -21,6 +21,7 @@ private:
        void insert_event(int button_id);
        void set_current_event_type(const std::string &type);
        void delete_current_event();
+       void make_substitution();
        void update_status();
 
        Ui::MainWindow *ui;
index a0fe53fd70214ac0cd278041b8a970a3774063d4..c3ba4d6f94ead0173d2bf0204d5ea70183247014 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1031</width>
+    <width>1251</width>
     <height>754</height>
    </rect>
   </property>
@@ -16,7 +16,7 @@
   <widget class="QWidget" name="centralwidget">
    <layout class="QGridLayout" name="gridLayout_2">
     <item row="0" column="0">
-     <layout class="QGridLayout" name="main_grid" rowstretch="1,0,0,0,0,0" columnstretch="1,0">
+     <layout class="QGridLayout" name="main_grid" rowstretch="1,0,0" columnstretch="1,0">
       <item row="0" column="0">
        <widget class="QVideoWidget" name="video" native="true">
         <property name="minimumSize">
             <property name="text">
              <string>Substitution (&amp;b)</string>
             </property>
+            <property name="shortcut">
+             <string>B</string>
+            </property>
            </widget>
           </item>
           <item row="1" column="0">
             <property name="text">
              <string>Unknown (&amp;?)</string>
             </property>
+            <property name="shortcut">
+             <string>?</string>
+            </property>
            </widget>
           </item>
           <item row="1" column="1">
             <property name="text">
              <string>Stoppage (&amp;v)</string>
             </property>
+            <property name="shortcut">
+             <string>V</string>
+            </property>
            </widget>
           </item>
          </layout>
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>1031</width>
+     <width>1251</width>
      <height>23</height>
     </rect>
    </property>
index f7886f35f007571487b82b550519a2a0847e3699..24c10b9843255890f604272bcf7d25cd69e9918b 100644 (file)
--- a/players.h
+++ b/players.h
@@ -22,7 +22,9 @@ public:
        QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
        QVariant data(const QModelIndex &index, int role) const override;
 
-//     Player get_player(int player_id) const;
+       int get_player_id(unsigned row) const {
+               return players[row].player_id;
+       }
 
 private:
        struct Player {