case Column::OUT:
case Column::DURATION:
case Column::FADE_TIME:
+ case Column::SPEED:
return Qt::AlignRight + Qt::AlignVCenter;
case Column::CAMERA:
return Qt::AlignCenter;
}
if (role == Qt::BackgroundRole) {
if (Column(column) == Column::PLAYING) {
- auto it = current_progress.find(row);
+ auto it = current_progress.find(clips[row].id);
if (it != current_progress.end()) {
double play_progress = it->second;
switch (Column(column)) {
case Column::PLAYING:
- return current_progress.count(row) ? "→" : "";
+ return current_progress.count(clips[row].id) ? "→" : "";
case Column::IN:
- return QString::fromStdString(pts_to_string(clips[row].pts_in));
+ return QString::fromStdString(pts_to_string(clips[row].clip.pts_in));
case Column::OUT:
- if (clips[row].pts_out >= 0) {
- return QString::fromStdString(pts_to_string(clips[row].pts_out));
+ if (clips[row].clip.pts_out >= 0) {
+ return QString::fromStdString(pts_to_string(clips[row].clip.pts_out));
} else {
return QVariant();
}
case Column::DURATION:
- if (clips[row].pts_out >= 0) {
- return QString::fromStdString(duration_to_string(clips[row].pts_out - clips[row].pts_in));
+ if (clips[row].clip.pts_out >= 0) {
+ return QString::fromStdString(duration_to_string(clips[row].clip.pts_out - clips[row].clip.pts_in));
} else {
return QVariant();
}
case Column::CAMERA:
- return qlonglong(clips[row].stream_idx + 1);
+ return qlonglong(clips[row].clip.stream_idx + 1);
case Column::DESCRIPTION:
- return QString::fromStdString(clips[row].descriptions[clips[row].stream_idx]);
+ return QString::fromStdString(clips[row].clip.descriptions[clips[row].clip.stream_idx]);
case Column::FADE_TIME: {
stringstream ss;
ss.imbue(locale("C"));
ss.precision(3);
- ss << fixed << clips[row].fade_time_seconds;
+ ss << fixed << clips[row].clip.fade_time_seconds;
+ return QString::fromStdString(ss.str());
+ }
+ case Column::SPEED: {
+ stringstream ss;
+ ss.imbue(locale("C"));
+ ss.precision(3);
+ ss << fixed << clips[row].clip.speed;
return QString::fromStdString(ss.str());
}
default:
case Column::DURATION:
return "Duration";
default:
- if (section >= int(Column::CAMERA_1) && section < int(Column::CAMERA_1) + num_cameras) {
+ if (is_camera_column(section)) {
return QString::fromStdString("Camera " + to_string(section - int(Column::CAMERA_1) + 1));
} else {
return "";
return "Description";
case Column::FADE_TIME:
return "Fade time";
+ case Column::SPEED:
+ return "Speed";
default:
return "";
}
case Column::DESCRIPTION:
case Column::CAMERA:
case Column::FADE_TIME:
- return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
+ case Column::SPEED:
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
default:
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
switch (Column(column)) {
case Column::DESCRIPTION:
- clips[row].descriptions[clips[row].stream_idx] = value.toString().toStdString();
+ clips[row].clip.descriptions[clips[row].clip.stream_idx] = value.toString().toStdString();
emit_data_changed(row);
return true;
case Column::CAMERA: {
bool ok;
int camera_idx = value.toInt(&ok);
- if (!ok || camera_idx < 1 || camera_idx > num_cameras) {
+ if (!ok || camera_idx < 1 || camera_idx > int(num_cameras)) {
return false;
}
- clips[row].stream_idx = camera_idx - 1;
+ clips[row].clip.stream_idx = camera_idx - 1;
emit_data_changed(row);
return true;
}
if (!ok || !(val >= 0.0)) {
return false;
}
- clips[row].fade_time_seconds = val;
+ clips[row].clip.fade_time_seconds = val;
+ emit_data_changed(row);
+ return true;
+ }
+ case Column::SPEED: {
+ bool ok;
+ double val = value.toDouble(&ok);
+ if (!ok || !(val >= 0.001)) {
+ return false;
+ }
+ clips[row].clip.speed = val;
emit_data_changed(row);
return true;
}
void PlayList::add_clip(const Clip &clip)
{
beginInsertRows(QModelIndex(), clips.size(), clips.size());
- clips.push_back(clip);
+ clips.emplace_back(ClipWithID{ clip, clip_counter++ });
endInsertRows();
emit any_content_changed();
}
void PlayList::duplicate_clips(size_t first, size_t last)
{
- beginInsertRows(QModelIndex(), first, last);
- clips.insert(clips.begin() + first, clips.begin() + first, clips.begin() + last + 1);
+ beginInsertRows(QModelIndex(), last + 1, last + 1 + (last - first));
+
+ vector<ClipWithID> new_clips;
+ for (auto it = clips.begin() + first; it <= clips.begin() + last; ++it) {
+ new_clips.emplace_back(ClipWithID{ it->clip, clip_counter++ }); // Give them new IDs.
+ }
+ clips.insert(clips.begin() + last + 1, new_clips.begin(), new_clips.end()); // Note: The new elements are inserted after the old ones.
endInsertRows();
emit any_content_changed();
}
emit any_content_changed();
}
-void PlayList::set_currently_playing(int index, double progress)
-{
- int old_index = currently_playing_index;
- int column = int(Column::PLAYING);
- if (index != old_index) {
- currently_playing_index = index;
- play_progress = progress;
- if (old_index != -1) {
- emit dataChanged(this->index(old_index, column), this->index(old_index, column));
- }
- if (index != -1) {
- emit dataChanged(this->index(index, column), this->index(index, column));
- }
- } else if (index != -1 && fabs(progress - play_progress) > 1e-3) {
- play_progress = progress;
- emit dataChanged(this->index(index, column), this->index(index, column));
- }
-}
-
-void PlayList::set_progress(const map<size_t, double> &progress)
+void PlayList::set_progress(const map<uint64_t, double> &progress)
{
const int column = int(Column::PLAYING);
- map<size_t, double> old_progress = move(this->current_progress);
+ map<uint64_t, double> old_progress = move(this->current_progress);
this->current_progress = progress;
- for (auto it : old_progress) {
- size_t index = it.first;
- if (current_progress.count(index) == 0) {
- emit dataChanged(this->index(index, column), this->index(index, column));
+ for (size_t row = 0; row < clips.size(); ++row) {
+ uint64_t id = clips[row].id;
+ if (current_progress.count(id) || old_progress.count(id)) {
+ emit dataChanged(this->index(row, column), this->index(row, column));
}
}
- for (auto it : current_progress) {
- size_t index = it.first;
- emit dataChanged(this->index(index, column), this->index(index, column));
- }
}
namespace {
}
clip.stream_idx = clip_proto.stream_idx();
clip.fade_time_seconds = clip_proto.fade_time_seconds();
+ if (clip_proto.speed() < 0.001) {
+ clip.speed = 0.5; // Default.
+ } else {
+ clip.speed = clip_proto.speed();
+ }
return clip;
}
}
clip_proto->set_stream_idx(clip.stream_idx);
clip_proto->set_fade_time_seconds(clip.fade_time_seconds);
+ clip_proto->set_speed(clip.speed);
}
} // namespace
PlayList::PlayList(const ClipListProto &serialized)
{
for (const ClipProto &clip_proto : serialized.clip()) {
- clips.push_back(deserialize_clip(clip_proto));
+ clips.emplace_back(ClipWithID{ deserialize_clip(clip_proto), clip_counter++ });
}
}
ClipListProto PlayList::serialize() const
{
ClipListProto ret;
- for (const Clip &clip : clips) {
- serialize_clip(clip, ret.add_clip());
+ for (const ClipWithID &clip : clips) {
+ serialize_clip(clip.clip, ret.add_clip());
}
return ret;
}