ocarina/core/queue.cpp

228 lines
4.5 KiB
C++
Raw Normal View History

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/queue.h>
extern "C" {
#include <core/random.h>
}
#include <core/string.h>
#include <algorithm>
#include <sstream>
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;
}
bool queue :: has_flag(queue_flags flag)
{
return (q_flags & flag) == (unsigned int)flag;
}
static bool track_less_than(struct track *lhs, struct track *rhs,
std::vector<struct sort_info> &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 track *track)
{
for (unsigned int i = 0; i < q_tracks.size(); i++) {
if (q_tracks[i] == track)
q_notify->on_track_updated(i);
}
}
void queue_selected(struct queue *queue, unsigned int index)
{
queue->q_cur = index;
if (queue->has_flag(Q_REPEAT) == false)
queue->del(index);
}
struct track *queue :: next()
{
struct track *res;
if (!(q_flags & Q_ENABLED))
return NULL;
else if (q_tracks.size() == 0)
return NULL;
else if (q_tracks.size() == 1)
q_cur = 0;
else if (q_flags & Q_RANDOM)
q_cur += random_range(1, q_tracks.size() / 2);
else
q_cur++;
q_cur %= q_tracks.size();
res = q_tracks[q_cur];
queue_selected(this, q_cur);
return res;
}
unsigned int queue :: size()
{
return q_tracks.size();
}
class SortTracks {
public:
std::vector<struct sort_info> fields;
SortTracks(std::vector<sort_info> 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 (q_flags & 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);
}
struct track *queue :: operator[](unsigned int index)
{
return q_tracks[index];
}