]> git.sesse.net Git - nageru/blob - clip_list.cpp
Add some playlist manipulation controls.
[nageru] / clip_list.cpp
1 #include "mainwindow.h"
2
3 #include <math.h>
4 #include <string>
5 #include <vector>
6
7 #include "clip_list.h"
8 #include "ui_mainwindow.h"
9
10 using namespace std;
11
12 string pts_to_string(int64_t pts)
13 {
14         // FIXME: This depends on a fixed timebase.
15         int64_t t = lrint((pts / 12800.0) * 1e3);  // In milliseconds.
16         int ms = t % 1000;
17         t /= 1000;
18         int sec = t % 60;
19         t /= 60;
20         int min = t % 60;
21         t /= 60;
22         int hour = t;
23
24         char buf[256];
25         snprintf(buf, sizeof(buf), "%d:%02d:%02d.%03d", hour, min, sec, ms);
26         return buf;
27 }
28
29 string duration_to_string(int64_t pts_diff)
30 {
31         // FIXME: This depends on a fixed timebase.
32         int64_t t = lrint((pts_diff / 12800.0) * 1e3);  // In milliseconds.
33         int ms = t % 1000;
34         t /= 1000;
35         int sec = t % 60;
36         t /= 60;
37         int min = t;
38
39         char buf[256];
40         snprintf(buf, sizeof(buf), "%d:%02d.%03d", min, sec, ms);
41         return buf;
42 }
43
44 int ClipList::rowCount(const QModelIndex &parent) const {
45         if (parent.isValid()) return 0;
46         return clips.size();
47 }
48
49 int PlayList::rowCount(const QModelIndex &parent) const {
50         if (parent.isValid()) return 0;
51         return clips.size();
52 }
53
54 int ClipList::columnCount(const QModelIndex &parent) const {
55         if (parent.isValid()) return 0;
56         return int(Column::NUM_COLUMNS);
57 }
58
59 int PlayList::columnCount(const QModelIndex &parent) const {
60         if (parent.isValid()) return 0;
61         return int(Column::NUM_COLUMNS);
62 }
63
64 QVariant ClipList::data(const QModelIndex &parent, int role) const {
65         if (!parent.isValid())
66                 return QVariant();
67         const int row = parent.row(), column = parent.column();
68         if (size_t(row) >= clips.size())
69                 return QVariant();
70
71         if (role == Qt::TextAlignmentRole) {
72                 switch (Column(column)) {
73                 case Column::IN:
74                 case Column::OUT:
75                 case Column::DURATION:
76                         return Qt::AlignRight + Qt::AlignVCenter;
77                 default:
78                         return Qt::AlignLeft + Qt::AlignVCenter;
79                 }
80         }
81
82         if (role != Qt::DisplayRole)
83                 return QVariant();
84
85         switch (Column(column)) {
86         case Column::IN:
87                 return QString::fromStdString(pts_to_string(clips[row].pts_in));
88         case Column::OUT:
89                 if (clips[row].pts_out >= 0) {
90                         return QString::fromStdString(pts_to_string(clips[row].pts_out));
91                 } else {
92                         return QVariant();
93                 }
94         case Column::DURATION:
95                 if (clips[row].pts_out >= 0) {
96                         return QString::fromStdString(duration_to_string(clips[row].pts_out - clips[row].pts_in));
97                 } else {
98                         return QVariant();
99                 }
100         case Column::CAMERA_1:
101         case Column::CAMERA_2:
102         case Column::CAMERA_3:
103         case Column::CAMERA_4: {
104                 unsigned stream_idx = column - int(Column::CAMERA_1);
105                 return QString::fromStdString(clips[row].descriptions[stream_idx]);
106         }
107         default:
108                 return "";
109         }
110 }
111
112 QVariant PlayList::data(const QModelIndex &parent, int role) const {
113         if (!parent.isValid())
114                 return QVariant();
115         const int row = parent.row(), column = parent.column();
116         if (size_t(row) >= clips.size())
117                 return QVariant();
118
119         if (role == Qt::TextAlignmentRole) {
120                 switch (Column(column)) {
121                 case Column::PLAYING:
122                         return Qt::AlignCenter;
123                 case Column::IN:
124                 case Column::OUT:
125                 case Column::DURATION:
126                         return Qt::AlignRight + Qt::AlignVCenter;
127                 case Column::CAMERA:
128                         return Qt::AlignCenter;
129                 default:
130                         return Qt::AlignLeft + Qt::AlignVCenter;
131                 }
132         }
133
134         if (role != Qt::DisplayRole)
135                 return QVariant();
136
137         switch (Column(column)) {
138         case Column::PLAYING:
139                 return (row == currently_playing_index) ? "→" : "";
140         case Column::IN:
141                 return QString::fromStdString(pts_to_string(clips[row].pts_in));
142         case Column::OUT:
143                 if (clips[row].pts_out >= 0) {
144                         return QString::fromStdString(pts_to_string(clips[row].pts_out));
145                 } else {
146                         return QVariant();
147                 }
148         case Column::DURATION:
149                 if (clips[row].pts_out >= 0) {
150                         return QString::fromStdString(duration_to_string(clips[row].pts_out - clips[row].pts_in));
151                 } else {
152                         return QVariant();
153                 }
154         case Column::CAMERA:
155                 return qlonglong(clips[row].stream_idx + 1);
156         case Column::DESCRIPTION:
157                 return QString::fromStdString(clips[row].descriptions[clips[row].stream_idx]);
158         default:
159                 return "";
160         }
161 }
162
163 QVariant ClipList::headerData(int section, Qt::Orientation orientation, int role) const {
164         if (role != Qt::DisplayRole)
165                 return QVariant();
166         if (orientation != Qt::Horizontal)
167                 return QVariant();
168
169         switch (Column(section)) {
170         case Column::IN:
171                 return "In";
172         case Column::OUT:
173                 return "Out";
174         case Column::DURATION:
175                 return "Duration";
176         case Column::CAMERA_1:
177                 return "Camera 1";
178         case Column::CAMERA_2:
179                 return "Camera 2";
180         case Column::CAMERA_3:
181                 return "Camera 3";
182         case Column::CAMERA_4:
183                 return "Camera 4";
184         default:
185                 return "";
186         }
187 }
188
189 QVariant PlayList::headerData(int section, Qt::Orientation orientation, int role) const {
190         if (role != Qt::DisplayRole)
191                 return QVariant();
192         if (orientation != Qt::Horizontal)
193                 return QVariant();
194
195         switch (Column(section)) {
196         case Column::PLAYING:
197                 return "";
198         case Column::IN:
199                 return "In";
200         case Column::OUT:
201                 return "Out";
202         case Column::DURATION:
203                 return "Duration";
204         case Column::CAMERA:
205                 return "Camera";
206         case Column::DESCRIPTION:
207                 return "Description";
208         default:
209                 return "";
210         }
211 }
212
213 Qt::ItemFlags ClipList::flags(const QModelIndex &index) const
214 {
215         if (!index.isValid())
216                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
217         const int row = index.row(), column = index.column();
218         if (size_t(row) >= clips.size())
219                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
220
221         switch (Column(column)) {
222         case Column::CAMERA_1:
223         case Column::CAMERA_2:
224         case Column::CAMERA_3:
225         case Column::CAMERA_4:
226                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
227         default:
228                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
229         }
230 }
231
232 Qt::ItemFlags PlayList::flags(const QModelIndex &index) const
233 {
234         if (!index.isValid())
235                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
236         const int row = index.row(), column = index.column();
237         if (size_t(row) >= clips.size())
238                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
239
240         switch (Column(column)) {
241         case Column::DESCRIPTION:
242                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
243         default:
244                 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
245         }
246 }
247
248 bool ClipList::setData(const QModelIndex &index, const QVariant &value, int role)
249 {
250         if (!index.isValid() || role != Qt::EditRole) {
251                 return false;
252         }
253
254         const int row = index.row(), column = index.column();
255         if (size_t(row) >= clips.size())
256                 return false;
257
258         switch (Column(column)) {
259         case Column::CAMERA_1:
260         case Column::CAMERA_2:
261         case Column::CAMERA_3:
262         case Column::CAMERA_4: {
263                 unsigned stream_idx = column - int(Column::CAMERA_1);
264                 clips[row].descriptions[stream_idx] = value.toString().toStdString();
265                 emit_data_changed(row);
266                 return true;
267         }
268         default:
269                 return false;
270         }
271 }
272
273 bool PlayList::setData(const QModelIndex &index, const QVariant &value, int role)
274 {
275         if (!index.isValid() || role != Qt::EditRole) {
276                 return false;
277         }
278
279         const int row = index.row(), column = index.column();
280         if (size_t(row) >= clips.size())
281                 return false;
282
283         switch (Column(column)) {
284         case Column::DESCRIPTION:
285                 clips[row].descriptions[clips[row].stream_idx] = value.toString().toStdString();
286                 emit_data_changed(row);
287                 return true;
288         default:
289                 return false;
290         }
291 }
292
293 void ClipList::add_clip(const Clip &clip)
294 {
295         beginInsertRows(QModelIndex(), clips.size(), clips.size());
296         clips.push_back(clip);
297         endInsertRows();
298 }
299
300 void PlayList::add_clip(const Clip &clip)
301 {
302         beginInsertRows(QModelIndex(), clips.size(), clips.size());
303         clips.push_back(clip);
304         endInsertRows();
305 }
306
307 void PlayList::duplicate_clips(size_t first, size_t last)
308 {
309         beginInsertRows(QModelIndex(), first, last);
310         clips.insert(clips.begin() + first, clips.begin() + first, clips.begin() + last + 1);
311         endInsertRows();
312 }
313
314 void PlayList::erase_clips(size_t first, size_t last)
315 {
316         beginRemoveRows(QModelIndex(), first, last);
317         clips.erase(clips.begin() + first, clips.begin() + last + 1);
318         endRemoveRows();
319 }
320
321 void PlayList::move_clips(size_t first, size_t last, int delta)
322 {
323         if (delta == -1) {
324                 beginMoveRows(QModelIndex(), first, last, QModelIndex(), first - 1);
325                 rotate(clips.begin() + first - 1, clips.begin() + first, clips.begin() + last + 1);
326         } else {
327                 beginMoveRows(QModelIndex(), first, last, QModelIndex(), first + (last-first+1) + 1);
328                 first = clips.size() - first - 1;
329                 last = clips.size() - last - 1;
330                 rotate(clips.rbegin() + last - 1, clips.rbegin() + last, clips.rbegin() + first + 1);
331         }
332         endMoveRows();
333 }
334
335 void ClipList::emit_data_changed(size_t row)
336 {
337         emit dataChanged(index(row, 0), index(row, int(Column::NUM_COLUMNS)));
338 }
339
340 void PlayList::emit_data_changed(size_t row)
341 {
342         emit dataChanged(index(row, 0), index(row, int(Column::NUM_COLUMNS)));
343 }
344
345 void PlayList::set_currently_playing(int index)
346 {
347         int old_index = currently_playing_index;
348         if (index != old_index) {
349                 currently_playing_index = index;
350                 if (old_index != -1) {
351                         emit_data_changed(old_index);
352                 }
353                 if (index != -1) {
354                         emit_data_changed(index);
355                 }
356         }
357 }