/** * 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; queue :: queue(unsigned int flags) : q_cur(-1), q_flags(flags), q_length(0), q_notify(&def_notify) {} queue :: queue() : q_cur(-1), q_flags(0), q_length(0), q_notify(&def_notify) {} 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(queue_flags flag) { q_flags |= flag; } void queue :: unset_flag(queue_flags flag) { q_flags &= ~flag; } 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; } unsigned int queue :: find_sorted_id(struct track *rhs) { struct track *lhs; unsigned int begin = 0, end = (q_tracks.size() - 1), mid; if (q_tracks.size() == 0) return 0; while (end > begin) { mid = begin + ((end - begin) / 2); lhs = q_tracks[mid]; if (track_less_than(lhs, rhs, q_sort)) begin = mid + 1; else { if (mid == begin) return begin; else end = mid - 1; } } lhs = q_tracks[begin]; if (track_less_than(lhs, rhs, q_sort)) return begin + 1; return begin; } unsigned int queue :: _add_at(struct track *track, unsigned int pos) { q_tracks.insert(q_tracks.begin() + pos, track); q_length += track->tr_length; q_notify->on_track_added(pos); return pos; } unsigned int queue :: add(struct track *track) { unsigned int id = q_tracks.size(); if (q_sort.size() > 0) id = find_sorted_id(track); return _add_at(track, id); } 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(compare_t field, bool reset) { bool found = false; struct sort_info info = { field, true }; if (queue_has_flag(this, Q_NO_SORT)) return; if (reset) q_sort.clear(); for (unsigned int i = 0; i < q_sort.size(); i++) { if (q_sort[i].field == info.field) { q_sort[i].ascending = !q_sort[i].ascending; found = true; break; } } if (!found) q_sort.push_back(info); std::stable_sort(q_tracks.begin(), q_tracks.end(), SortTracks(q_sort)); for (unsigned int i = 0; i < q_tracks.size(); i++) q_notify->on_track_updated(i); }