aboutsummaryrefslogtreecommitdiff
path: root/src/ui.cc
blob: 82e874d8212cf31bb0ff5db742cfe21e8b0e9672 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "ui.h"
#include "playback.h"
#include "labeller.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <sys/ioctl.h>
#include <unistd.h>

namespace frontend {
    struct ui_impl {
        std::shared_ptr<playback> pb;
        std::shared_ptr<backend::labeller> llr;
        bool play = false;
        bool stalePrintout = true;
    };

    ui::ui(std::shared_ptr<playback> playback, std::shared_ptr<backend::labeller> labeller) {
        data = std::shared_ptr<ui_impl>(new ui_impl);
        data->pb = playback;
        data->llr = labeller;
    }

    bool handleKey(int keycode, const std::shared_ptr<ui_impl>& data) {
        if(keycode != -1) {
            data->stalePrintout = true;
            if(keycode >= 48 && keycode <= 57) { // Number -> label
                std::size_t num = keycode - 48;
                if(num <= data->llr->getLabels().size()) {
                    data->llr->applyLabel(data->llr->getLabels()[num-1], data->pb->getTime());
                }
            } else {
                switch(keycode) {
                    case 27: // Escape quits
                        std::cout << std::endl;
                        return true;
                    case 32: // Space pauses
                        data->play = ! data->play;
                        break;
                    case 65361: // Left seeks backward 1 frame
                        data->pb->seekFrame(data->pb->getFrame() - 1);
                        break;
                    case 65362: // Up seeks backward 1 second
                        if(data->pb->getTime() < 1) {
                            data->pb->seekTime(data->pb->getTime() * -1);
                        } else {
                            data->pb->seekTime(data->pb->getTime() - 1);
                        }
                        break;
                    case 65363: // Right seeks forward 1 frame
                        data->pb->seekFrame(data->pb->getFrame() + 1);
                        break;
                    case 65364: // Down seeks forward 1 second
                        data->pb->seekTime(data->pb->getTime() + 1);
                        break;
                    case 117: // u undoes
                        data->llr->undo();
                        break;
                    case 114: // r redoes
                        data->llr->redo();
                        break;
                    case 65535: // DEL deletes
                        data->llr->deleteLabel(data->pb->getTime());
                        break;
                    case 115: // s saves
                        data->llr->save();
                        break;
                    default:
                        std::cout << "Pressed the " << keycode << " key" << std::endl;
                        break;
                }
            }
        }
        return false;
    }

    void ui::begin() {
        std::cout << "Playing a video that's " << data->pb->getMaxFrame() << " frames (" << data->pb->getMaxTime() << " seconds) long." << std::endl;
        std::cout << "Annotations:" << std::endl;
        int num = 0;
        for(auto ann : data->llr->getLabels()) {
            std::cout << ++num << ": " << ann << std::endl;
        }
        // Get window size
        struct winsize size;
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
        int cols = size.ws_col;
        while(true) {
            data->pb->display("Video");
            data->pb->interFrameSleep();
            if(handleKey(cv::pollKey(), data)) {
                break;
            }
            if(data->play) {
                data->pb->seekFrame(data->pb->getFrame() + 1);
            }
            if(data->play || data->stalePrintout) {
                std::stringstream toPrint;
                toPrint << "Frame: " << data->pb->getFrame() << " (" << std::setprecision(4) << std::setw(6) << std::left << data->pb->getTime() << " s)";
                std::string timeString = toPrint.str();
                toPrint.str(""); // clear contents
                // Get surrounding labels
                auto labs = data->llr->getSurrounding(data->pb->getTime());
                if(! labs.first.name.empty()) toPrint << labs.first.name << " (t=" << std::setprecision(4) << labs.first.time << ")";
                else toPrint << "START (t=0)";
                toPrint << " CURRENT ";
                if(! labs.second.name.empty()) toPrint << labs.second.name << " (t=" << std::setprecision(4) << labs.second.time << ")";
                else toPrint << "END (t=" << data->pb->getMaxTime() << ")";
                toPrint << std::string(cols - toPrint.str().size() - timeString.size() - 1, ' ') << timeString;
                std::cout << "\r\b\r" << toPrint.str();
                std::cout.flush();
                data->stalePrintout = false;
            }
        }
    }
}