aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--doc/protocol.xml10
-rw-r--r--src/command.c8
-rw-r--r--src/playlist.h2
-rw-r--r--src/playlist_edit.c31
-rw-r--r--src/queue.c42
-rw-r--r--src/queue.h6
6 files changed, 79 insertions, 20 deletions
diff --git a/doc/protocol.xml b/doc/protocol.xml
index 409f9ca0e..8f5b4b9e8 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -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>
diff --git a/src/command.c b/src/command.c
index 7603f669c..1b8c45f26 100644
--- a/src/command.c
+++ b/src/command.c
@@ -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);
}
diff --git a/src/playlist.h b/src/playlist.h
index efe13b0b8..41befe455 100644
--- a/src/playlist.h
+++ b/src/playlist.h
@@ -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);
diff --git a/src/playlist_edit.c b/src/playlist_edit.c
index 8580a5030..b83dc0933 100644
--- a/src/playlist_edit.c
+++ b/src/playlist_edit.c
@@ -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)
diff --git a/src/queue.c b/src/queue.c
index 581e5c566..b9486cfe5 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -173,6 +173,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)
{
struct song *song;
diff --git a/src/queue.h b/src/queue.h
index 402c6bd26..7f46c2e19 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -292,6 +292,12 @@ 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.
*/
void