]> git.sesse.net Git - nageru/blob - futatabi/clip_list.h
Release Nageru and Futatabi 1.9.1.
[nageru] / futatabi / clip_list.h
1 #ifndef _CLIP_LIST_H
2 #define _CLIP_LIST_H 1
3
4 #include "defs.h"
5 #include "state.pb.h"
6
7 #include <QAbstractTableModel>
8 #include <map>
9 #include <stdint.h>
10 #include <string>
11 #include <vector>
12
13 struct Clip {
14         int64_t pts_in = -1, pts_out = -1;  // pts_in is inclusive, pts_out is exclusive.
15         std::string descriptions[MAX_STREAMS];
16
17         // These are for the playlist only.
18         unsigned stream_idx = 0;
19         double fade_time_seconds = 0.5;
20         double speed = 0.5;
21 };
22 struct ClipWithID {
23         Clip clip;
24         uint64_t id;  // Used for progress callback only. Immutable.
25 };
26
27 class DataChangedReceiver {
28 public:
29         virtual ~DataChangedReceiver() {}
30         virtual void emit_data_changed(size_t row) = 0;
31 };
32
33 // Like a smart pointer to a Clip, but emits dataChanged when it goes out of scope.
34 struct ClipProxy {
35 public:
36         ClipProxy(Clip &clip, DataChangedReceiver *clip_list, size_t row)
37                 : clip(clip), clip_list(clip_list), row(row) {}
38         ~ClipProxy()
39         {
40                 if (clip_list != nullptr) {
41                         clip_list->emit_data_changed(row);
42                 }
43         }
44         Clip *operator->() { return &clip; }
45         Clip &operator*() { return clip; }
46
47 private:
48         Clip &clip;
49         DataChangedReceiver *clip_list;
50         size_t row;
51 };
52
53 class ClipList : public QAbstractTableModel, public DataChangedReceiver {
54         Q_OBJECT
55
56 public:
57         ClipList(const ClipListProto &serialized);
58
59         enum class Column {
60                 IN,
61                 OUT,
62                 DURATION,
63                 CAMERA_1,  // Then CAMERA_2, CAMERA_3, etc. as needed.
64                 NUM_NON_CAMERA_COLUMNS = CAMERA_1
65         };
66
67         int rowCount(const QModelIndex &parent) const override;
68         int columnCount(const QModelIndex &parent) const override;
69         QVariant data(const QModelIndex &parent, int role) const override;
70         QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
71         Qt::ItemFlags flags(const QModelIndex &index) const override;
72         bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
73
74         void add_clip(const Clip &clip);
75         size_t size() const { return clips.size(); }
76         bool empty() const { return clips.empty(); }
77
78         ClipProxy mutable_clip(size_t index) { return ClipProxy(clips[index], this, index); }
79         const Clip *clip(size_t index) const { return &clips[index]; }
80
81         ClipProxy mutable_back() { return mutable_clip(size() - 1); }
82         const Clip *back() const { return clip(size() - 1); }
83
84         ClipListProto serialize() const;
85
86         void change_num_cameras(size_t num_cameras);  // Defaults to 2. Cannot decrease.
87         void emit_data_changed(size_t row) override;
88
89         bool is_camera_column(int column) const
90         {
91                 return (column >= int(Column::CAMERA_1) && column < int(Column::CAMERA_1) + int(num_cameras));
92         }
93
94 signals:
95         void any_content_changed();
96
97 private:
98         std::vector<Clip> clips;
99         size_t num_cameras = 2;
100 };
101
102 class PlayList : public QAbstractTableModel, public DataChangedReceiver {
103         Q_OBJECT
104
105 public:
106         explicit PlayList(const ClipListProto &serialized);
107
108         enum class Column {
109                 PLAYING,
110                 IN,
111                 OUT,
112                 DURATION,
113                 CAMERA,
114                 DESCRIPTION,
115                 FADE_TIME,
116                 SPEED,
117                 NUM_COLUMNS
118         };
119
120         int rowCount(const QModelIndex &parent) const override;
121         int columnCount(const QModelIndex &parent) const override;
122         QVariant data(const QModelIndex &parent, int role) const override;
123         QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
124         Qt::ItemFlags flags(const QModelIndex &index) const override;
125         bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
126
127         void add_clip(const Clip &clip);
128
129         // <last> is inclusive in all of these.
130         void duplicate_clips(size_t first, size_t last);
131         void erase_clips(size_t first, size_t last);
132         // <delta> is -1 to move upwards, +1 to move downwards.
133         void move_clips(size_t first, size_t last, int delta);
134
135         size_t size() const { return clips.size(); }
136         bool empty() const { return clips.empty(); }
137
138         ClipProxy mutable_clip(size_t index) { return ClipProxy(clips[index].clip, this, index); }
139         const Clip *clip(size_t index) const { return &clips[index].clip; }
140         const ClipWithID *clip_with_id(size_t index) const { return &clips[index]; }
141
142         ClipProxy mutable_back() { return mutable_clip(size() - 1); }
143         const Clip *back() const { return clip(size() - 1); }
144
145         void set_progress(const std::map<uint64_t, double> &progress);
146
147         ClipListProto serialize() const;
148
149         void change_num_cameras(size_t num_cameras)  // Defaults to 2. Cannot decrease.
150         {
151                 this->num_cameras = num_cameras;
152         }
153
154         void emit_data_changed(size_t row) override;
155
156 signals:
157         void any_content_changed();
158
159 private:
160         std::vector<ClipWithID> clips;
161         double play_progress = 0.0;
162         std::map<uint64_t, double> current_progress;
163         size_t num_cameras = 2;
164         uint64_t clip_counter = 1000000;  // Used for generating IDs. Starting at a high number to avoid any kind of bugs treating IDs as rows.
165 };
166
167 #endif  // !defined (_CLIP_LIST_H)