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:
parent
7684c446c6
commit
13208bf5a7
|
@ -634,14 +634,18 @@ OK
|
|||
<term>
|
||||
<cmdsynopsis>
|
||||
<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>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Moves the song at <varname>FROM</varname> to
|
||||
<varname>TO</varname> in the playlist.
|
||||
Moves the song at <varname>FROM</varname> or range of songs
|
||||
at <varname>START:END</varname> to <varname>TO</varname>
|
||||
in the playlist.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
@ -1181,14 +1181,16 @@ handle_list(struct client *client, int argc, char *argv[])
|
|||
static enum command_return
|
||||
handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||
{
|
||||
int from, to;
|
||||
unsigned start, end;
|
||||
int to;
|
||||
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;
|
||||
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
||||
return COMMAND_RETURN_ERROR;
|
||||
result = moveSongInPlaylist(&g_playlist, from, to);
|
||||
result = moveSongRangeInPlaylist(&g_playlist, start, end, to);
|
||||
return print_playlist_result(client, result);
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ void
|
|||
deleteASongFromPlaylist(struct playlist *playlist, const struct song *song);
|
||||
|
||||
enum playlist_result
|
||||
moveSongInPlaylist(struct playlist *playlist, unsigned from, int to);
|
||||
moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to);
|
||||
|
||||
enum playlist_result
|
||||
moveSongInPlaylistById(struct playlist *playlist, unsigned id, int to);
|
||||
|
|
|
@ -290,19 +290,21 @@ deleteASongFromPlaylist(struct playlist *playlist, const struct song *song)
|
|||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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)))
|
||||
return PLAYLIST_RESULT_BAD_RANGE;
|
||||
|
||||
if ((int)from == to) /* no-op */
|
||||
if ((int)start == to)
|
||||
/* nothing happens */
|
||||
return PLAYLIST_RESULT_SUCCESS;
|
||||
|
||||
queued = playlist_get_queued_song(playlist);
|
||||
|
@ -316,24 +318,27 @@ moveSongInPlaylist(struct playlist *playlist, unsigned from, int to)
|
|||
playlist->current)
|
||||
: -1;
|
||||
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 */
|
||||
return PLAYLIST_RESULT_SUCCESS;
|
||||
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) {
|
||||
/* update current/queued */
|
||||
if (playlist->current == (int)from)
|
||||
playlist->current = to;
|
||||
else if (playlist->current > (int)from &&
|
||||
if ((int)start <= playlist->current &&
|
||||
(unsigned)playlist->current < end)
|
||||
playlist->current += to - start;
|
||||
else if (playlist->current >= (int)end &&
|
||||
playlist->current <= to) {
|
||||
playlist->current--;
|
||||
playlist->current -= end - start;
|
||||
} else if (playlist->current >= to &&
|
||||
playlist->current < (int)from) {
|
||||
playlist->current++;
|
||||
playlist->current < (int)start) {
|
||||
playlist->current += end - start;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +356,7 @@ moveSongInPlaylistById(struct playlist *playlist, unsigned id1, int to)
|
|||
if (song < 0)
|
||||
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)
|
||||
|
|
42
src/queue.c
42
src/queue.c
|
@ -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
|
||||
queue_delete(struct queue *queue, unsigned position)
|
||||
{
|
||||
|
|
|
@ -291,6 +291,12 @@ queue_swap_order(struct queue *queue, unsigned order1, unsigned order2)
|
|||
void
|
||||
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.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue