/** * Copyright 2013 (c) Anna Schumaker. */ #include extern "C" { #include } #include #include #include static class DefaultNotifier : public QNotifier { public: DefaultNotifier() {}; void on_track_added(unsigned int pos) {}; void on_track_removed(unsigned int pos) {}; void on_track_updated(unsigned int pos) {}; } def_notify; static bool track_less_than(struct track *lhs, struct track *rhs, std::vector &order) { int res; for (unsigned int i = 0; i < order.size(); i++) { if (order[i].ascending == true) res = track_compare(lhs, rhs, order[i].field); else res = track_compare(rhs, lhs, order[i].field); if (res == 0) continue; break; } return res < 0; } static inline void __queue_save(struct queue *queue, enum queue_flags flag) { if (queue->q_ops && queue_has_flag(queue, flag)) queue->q_ops->qop_save(queue, flag); } static unsigned int __queue_find_sorted_id(struct queue *queue, struct track *rhs) { struct track *lhs; unsigned int mid, begin = 0, end = queue_size(queue) - 1; if (queue_size(queue) == 0) return 0; while (end > begin) { mid = begin + ((end - begin) / 2); lhs = queue->q_tracks[mid]; if (track_less_than(lhs, rhs, queue->q_sort)) begin = mid + 1; else { if (mid == begin) return begin; else end = mid - 1; } } lhs = queue->q_tracks[begin]; if (track_less_than(lhs, rhs, queue->q_sort)) return begin + 1; return begin; } void queue_init(struct queue *queue, unsigned int flags, const struct queue_ops *ops) { queue->q_cur = -1; queue->q_flags = flags; queue->q_length = 0; queue->q_notify = &def_notify; queue->q_ops = ops; } queue :: ~queue() {} void queue :: write(file &file) { file_writef(&file, "%u %zu", q_flags, q_tracks.size()); for (unsigned int i = 0; i < q_tracks.size(); i++) file_writef(&file, " %u", q_tracks[i]->tr_dbe.dbe_index); } void queue :: read(file &file) { unsigned int n, id; file_readf(&file, "%u %u", &q_flags, &n); q_tracks.resize(n); for (unsigned int i = 0; i < n; i++) { file_readf(&file, "%u", &id); q_tracks[i] = track_get(id); q_length += q_tracks[i]->tr_length; } } void queue_set_flag(struct queue *queue, enum queue_flags flag) { queue->q_flags |= flag; __queue_save(queue, Q_SAVE_FLAGS); } void queue_unset_flag(struct queue *queue, enum queue_flags flag) { queue->q_flags &= ~flag; __queue_save(queue, Q_SAVE_FLAGS); } unsigned int queue_add(struct queue *queue, struct track *track) { unsigned int pos = queue_size(queue); if (queue_has_flag(queue, Q_ADD_FRONT)) pos = 0; else if (queue->q_sort.size() > 0) pos = __queue_find_sorted_id(queue, track); queue->q_tracks.insert(queue->q_tracks.begin() + pos, track); queue->q_length += track->tr_length; queue->q_notify->on_track_added(pos); return pos; } void queue :: del(unsigned int index) { q_length -= q_tracks[index]->tr_length; q_tracks.erase(q_tracks.begin() + index); q_notify->on_track_removed(index); if (q_cur == index) q_cur--; } void queue :: del(struct track *track) { for (unsigned int i = 0; i < q_tracks.size(); i++) { while ((i < q_tracks.size()) && (q_tracks[i] == track)) del(i); } } void queue_updated(struct queue *queue, struct track *track) { for (unsigned int i = 0; i < queue_size(queue); i++) { if (queue->q_tracks[i] == track) queue->q_notify->on_track_updated(i); } } void queue_selected(struct queue *queue, unsigned int index) { queue->q_cur = index; if (queue_has_flag(queue, Q_REPEAT) == false) queue->del(index); } struct track *queue_next(struct queue *queue) { unsigned int size = queue_size(queue); struct track *res; if (!queue_has_flag(queue, Q_ENABLED)) return NULL; else if (size == 0) return NULL; else if (size == 1) queue->q_cur = 0; else if (queue_has_flag(queue, Q_RANDOM)) queue->q_cur += random_range(1, size / 2); else queue->q_cur++; queue->q_cur %= size; res = queue->q_tracks[queue->q_cur]; queue_selected(queue, queue->q_cur); return res; } class SortTracks { public: std::vector fields; SortTracks(std::vector f) : fields(f) {} bool operator()(struct track *lhs, struct track *rhs) { return track_less_than(lhs, rhs, fields); } }; void queue_sort(struct queue *queue, enum compare_t field, bool reset) { bool found = false; struct sort_info info = { field, true }; if (queue_has_flag(queue, Q_NO_SORT)) return; if (reset) queue->q_sort.clear(); for (unsigned int i = 0; i < queue->q_sort.size(); i++) { if (queue->q_sort[i].field == info.field) { queue->q_sort[i].ascending = !queue->q_sort[i].ascending; found = true; break; } } if (!found) queue->q_sort.push_back(info); std::stable_sort(queue->q_tracks.begin(), queue->q_tracks.end(), SortTracks(queue->q_sort)); for (unsigned int i = 0; i < queue->q_tracks.size(); i++) queue->q_notify->on_track_updated(i); __queue_save(queue, Q_SAVE_SORT); }