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>
|
<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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
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
|
void
|
||||||
queue_delete(struct queue *queue, unsigned position)
|
queue_delete(struct queue *queue, unsigned position)
|
||||||
{
|
{
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user