queue/playlist/command: move range

The move command now accepts a range for the first argument, in the same
form as other range commands, e.g. move 15:17 3.  The first song in the
range is placed at the destination position. Note that as with other
range commands, the range is inclusive on the left only; this example
would move only songs 15 and 16, not 17.

[mk: fixed signed/unsigned warnings; use G_MAXUINT instead of
UINT_MAX]
This commit is contained in:
Jeffrey Middleton 2009-03-26 22:02:56 +01:00 committed by Max Kellermann
parent 7684c446c6
commit 13208bf5a7
6 changed files with 79 additions and 20 deletions

View File

@ -634,14 +634,18 @@ OK
<term> <term>
<cmdsynopsis> <cmdsynopsis>
<command>move</command> <command>move</command>
<arg choice="req"><replaceable>FROM</replaceable></arg> <group>
<arg choice="req"><replaceable>FROM</replaceable></arg>
<arg choice="req"><replaceable>START:END</replaceable></arg>
</group>
<arg choice="req"><replaceable>TO</replaceable></arg> <arg choice="req"><replaceable>TO</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
</term> </term>
<listitem> <listitem>
<para> <para>
Moves the song at <varname>FROM</varname> to Moves the song at <varname>FROM</varname> or range of songs
<varname>TO</varname> in the playlist. at <varname>START:END</varname> to <varname>TO</varname>
in the playlist.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -1181,14 +1181,16 @@ handle_list(struct client *client, int argc, char *argv[])
static enum command_return static enum command_return
handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{ {
int from, to; unsigned start, end;
int to;
enum playlist_result result; enum playlist_result result;
if (!check_int(client, &from, argv[1], check_integer, argv[1])) if (!check_range(client, &start, &end,
argv[1], need_range))
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[2], check_integer, argv[2])) if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
result = moveSongInPlaylist(&g_playlist, from, to); result = moveSongRangeInPlaylist(&g_playlist, start, end, to);
return print_playlist_result(client, result); return print_playlist_result(client, result);
} }

View File

@ -158,7 +158,7 @@ void
deleteASongFromPlaylist(struct playlist *playlist, const struct song *song); deleteASongFromPlaylist(struct playlist *playlist, const struct song *song);
enum playlist_result enum playlist_result
moveSongInPlaylist(struct playlist *playlist, unsigned from, int to); moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to);
enum playlist_result enum playlist_result
moveSongInPlaylistById(struct playlist *playlist, unsigned id, int to); moveSongInPlaylistById(struct playlist *playlist, unsigned id, int to);

View File

@ -290,19 +290,21 @@ deleteASongFromPlaylist(struct playlist *playlist, const struct song *song)
} }
enum playlist_result enum playlist_result
moveSongInPlaylist(struct playlist *playlist, unsigned from, int to) moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to)
{ {
const struct song *queued; const struct song *queued;
int currentSong; int currentSong;
if (!queue_valid_position(&playlist->queue, from)) if (!queue_valid_position(&playlist->queue, start) ||
!queue_valid_position(&playlist->queue, end - 1))
return PLAYLIST_RESULT_BAD_RANGE; return PLAYLIST_RESULT_BAD_RANGE;
if ((to >= 0 && to >= (int)queue_length(&playlist->queue)) || if ((to >= 0 && to + end - start - 1 >= queue_length(&playlist->queue)) ||
(to < 0 && abs(to) > (int)queue_length(&playlist->queue))) (to < 0 && abs(to) > (int)queue_length(&playlist->queue)))
return PLAYLIST_RESULT_BAD_RANGE; return PLAYLIST_RESULT_BAD_RANGE;
if ((int)from == to) /* no-op */ if ((int)start == to)
/* nothing happens */
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
queued = playlist_get_queued_song(playlist); queued = playlist_get_queued_song(playlist);
@ -316,24 +318,27 @@ moveSongInPlaylist(struct playlist *playlist, unsigned from, int to)
playlist->current) playlist->current)
: -1; : -1;
if (to < 0 && playlist->current >= 0) { if (to < 0 && playlist->current >= 0) {
if ((unsigned)currentSong == from) if (start <= (unsigned)currentSong && (unsigned)currentSong <= end)
/* no-op, can't be moved to offset of itself */ /* no-op, can't be moved to offset of itself */
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
to = (currentSong + abs(to)) % queue_length(&playlist->queue); to = (currentSong + abs(to)) % queue_length(&playlist->queue);
if (start < (unsigned)to)
to--;
} }
queue_move(&playlist->queue, from, to); queue_move_range(&playlist->queue, start, end, to);
if (!playlist->queue.random) { if (!playlist->queue.random) {
/* update current/queued */ /* update current/queued */
if (playlist->current == (int)from) if ((int)start <= playlist->current &&
playlist->current = to; (unsigned)playlist->current < end)
else if (playlist->current > (int)from && playlist->current += to - start;
else if (playlist->current >= (int)end &&
playlist->current <= to) { playlist->current <= to) {
playlist->current--; playlist->current -= end - start;
} else if (playlist->current >= to && } else if (playlist->current >= to &&
playlist->current < (int)from) { playlist->current < (int)start) {
playlist->current++; playlist->current += end - start;
} }
} }
@ -351,7 +356,7 @@ moveSongInPlaylistById(struct playlist *playlist, unsigned id1, int to)
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return moveSongInPlaylist(playlist, song, to); return moveSongRangeInPlaylist(playlist, song, song+1, to);
} }
void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end) void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end)

View File

@ -172,6 +172,48 @@ queue_move(struct queue *queue, unsigned from, unsigned to)
} }
} }
void
queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to)
{
struct queue_item items[end - start];
// Copy the original block [start,end-1]
for (unsigned i = start; i < end; i++)
items[i - start] = queue->items[i];
// If to > start, we need to move to-start items to start, starting from end
for (unsigned i = end; i < end + to - start; i++)
queue_move_song_to(queue, i, start + i - end);
// If to < start, we need to move start-to items to newend (= end + to - start), starting from to
// This is the same as moving items from start-1 to to (decreasing), with start-1 going to end-1
// We have to iterate in this order to avoid writing over something we haven't yet moved
for (unsigned i = start - 1; i >= to && i != G_MAXUINT; i--)
queue_move_song_to(queue, i, i + end - start);
// Copy the original block back in, starting at to.
for (unsigned i = start; i< end; i++)
{
queue->idToPosition[items[i-start].id] = to + i - start;
queue->items[to + i - start] = items[i-start];
queue->items[to + i - start].version = queue->version;
}
if (queue->random) {
// Update the positions in the queue.
// Note that the ranges for these cases are the same as the ranges of
// the loops above.
for (unsigned i = 0; i < queue->length; i++) {
if (queue->order[i] >= end && queue->order[i] < to + end - start)
queue->order[i] -= end - start;
else if (queue->order[i] < start &&
queue->order[i] >= to)
queue->order[i] += end - start;
else if (start <= queue->order[i] && queue->order[i] < end)
queue->order[i] += to - start;
}
}
}
void void
queue_delete(struct queue *queue, unsigned position) queue_delete(struct queue *queue, unsigned position)
{ {

View File

@ -291,6 +291,12 @@ queue_swap_order(struct queue *queue, unsigned order1, unsigned order2)
void void
queue_move(struct queue *queue, unsigned from, unsigned to); queue_move(struct queue *queue, unsigned from, unsigned to);
/**
* Moves a range of songs to a new position.
*/
void
queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to);
/** /**
* Removes a song from the playlist. * Removes a song from the playlist.
*/ */