Code

renamed screen_play.c to screen_queue.c
authorMax Kellermann <max@duempel.org>
Sun, 11 Oct 2009 16:16:05 +0000 (18:16 +0200)
committerMax Kellermann <max@duempel.org>
Sun, 11 Oct 2009 16:16:05 +0000 (18:16 +0200)
Makefile.am
src/screen.c
src/screen_file.c
src/screen_list.c
src/screen_play.c [deleted file]
src/screen_play.h [deleted file]
src/screen_queue.c [new file with mode: 0644]
src/screen_queue.h [new file with mode: 0644]

index ca5264fab2767b2a68bdb8ca5564b5cc6f08c74d..8ad132b2b2f8b1dbbbe2cb7613ca2f507674a506 100644 (file)
@@ -46,7 +46,7 @@ ncmpc_headers = \
        src/defaults.h \
        src/i18n.h \
        src/screen_help.h \
-       src/screen_play.h \
+       src/screen_queue.h \
        src/screen_file.h \
        src/screen_artist.h \
        src/screen_browser.h \
@@ -89,7 +89,7 @@ src_ncmpc_SOURCES = \
        src/screen_find.c \
        src/screen_utils.c \
        src/screen_client.c \
-       src/screen_play.c \
+       src/screen_queue.c \
        src/screen_browser.c \
        src/screen_file.c \
        src/list_window.c \
index 58cc492edd69c7b223047cb5947a207cdfa0c34b..4abb35a429e0af46b3a45bfdc67bb96f9917bea1 100644 (file)
@@ -31,7 +31,7 @@
 #include "colors.h"
 #include "player_command.h"
 #include "screen_help.h"
-#include "screen_play.h"
+#include "screen_queue.h"
 #include "screen_file.h"
 #include "screen_artist.h"
 #include "screen_search.h"
@@ -60,8 +60,8 @@ static const int SCREEN_MIN_ROWS = 5;
 /* screens */
 
 struct screen screen;
-static const struct screen_functions *mode_fn = &screen_playlist;
-static const struct screen_functions *mode_fn_prev = &screen_playlist;
+static const struct screen_functions *mode_fn = &screen_queue;
+static const struct screen_functions *mode_fn_prev = &screen_queue;
 
 gboolean
 screen_is_visible(const struct screen_functions *sf)
@@ -523,7 +523,7 @@ screen_cmd(struct mpdclient *c, command_t cmd)
                screen_next_mode(c, 1);
                break;
        case CMD_SCREEN_PLAY:
-               screen_switch(&screen_playlist, c);
+               screen_switch(&screen_queue, c);
                break;
        case CMD_SCREEN_FILE:
                screen_switch(&screen_browse, c);
index c5688fe6263cd520a8005a298141dd1d0896fb8e..c4fa8171ab2e371b5b74c11cbf016a280ccd614d 100644 (file)
@@ -21,6 +21,7 @@
 #include "screen_browser.h"
 #include "screen_interface.h"
 #include "screen_message.h"
+#include "screen_queue.h"
 #include "screen.h"
 #include "config.h"
 #include "i18n.h"
@@ -28,7 +29,6 @@
 #include "mpdclient.h"
 #include "filelist.h"
 #include "screen_utils.h"
-#include "screen_play.h"
 #include "screen_client.h"
 
 #include <mpd/client.h>
index 8f218a14fd9ffe834e140e6640b608d93d698712..b2959a0672dd78809083cc67abd588e9a0d985b4 100644 (file)
@@ -21,7 +21,7 @@
 #include "screen_interface.h"
 #include "screen.h"
 #include "screen_help.h"
-#include "screen_play.h"
+#include "screen_queue.h"
 #include "screen_file.h"
 #include "screen_artist.h"
 #include "screen_search.h"
@@ -37,7 +37,7 @@ static const struct
        const char *name;
        const struct screen_functions *functions;
 } screens[] = {
-       { "playlist", &screen_playlist },
+       { "playlist", &screen_queue },
        { "browse", &screen_browse },
 #ifdef ENABLE_ARTIST_SCREEN
        { "artist", &screen_artist },
diff --git a/src/screen_play.c b/src/screen_play.c
deleted file mode 100644 (file)
index 882dd7a..0000000
+++ /dev/null
@@ -1,799 +0,0 @@
-/* ncmpc (Ncurses MPD Client)
- * (c) 2004-2009 The Music Player Daemon Project
- * Project homepage: http://musicpd.org
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "screen_play.h"
-#include "screen_interface.h"
-#include "screen_file.h"
-#include "screen_message.h"
-#include "screen_find.h"
-#include "config.h"
-#include "i18n.h"
-#include "charset.h"
-#include "options.h"
-#include "mpdclient.h"
-#include "utils.h"
-#include "strfsong.h"
-#include "wreadln.h"
-#include "colors.h"
-#include "screen.h"
-#include "screen_utils.h"
-#include "screen_song.h"
-#include "screen_lyrics.h"
-
-#ifndef NCMPC_MINI
-#include "hscroll.h"
-#endif
-
-#include <mpd/client.h>
-
-#include <ctype.h>
-#include <string.h>
-#include <glib.h>
-
-#define MAX_SONG_LENGTH 512
-
-#ifndef NCMPC_MINI
-typedef struct
-{
-       GList **list;
-       GList **dir_list;
-       struct mpdclient *c;
-} completion_callback_data_t;
-
-static struct hscroll hscroll;
-static guint scroll_source_id;
-#endif
-
-static struct mpdclient_playlist *playlist;
-static int current_song_id = -1;
-static int selected_song_id = -1;
-static struct list_window *lw;
-static guint timer_hide_cursor_id;
-
-static void
-screen_playlist_paint(void);
-
-static void
-playlist_repaint(void)
-{
-       screen_playlist_paint();
-       wrefresh(lw->w);
-}
-
-static const struct mpd_song *
-playlist_selected_song(void)
-{
-       return !lw->range_selection &&
-               lw->selected < playlist_length(playlist)
-               ? playlist_get(playlist, lw->selected)
-               : NULL;
-}
-
-static void
-playlist_save_selection(void)
-{
-       selected_song_id = playlist_selected_song() != NULL
-               ? (int)mpd_song_get_id(playlist_selected_song())
-               : -1;
-}
-
-static void
-playlist_restore_selection(void)
-{
-       const struct mpd_song *song;
-       int pos;
-
-       list_window_set_length(lw, playlist_length(playlist));
-
-       if (selected_song_id < 0)
-               /* there was no selection */
-               return;
-
-       song = playlist_selected_song();
-       if (song != NULL &&
-           mpd_song_get_id(song) == (unsigned)selected_song_id)
-               /* selection is still valid */
-               return;
-
-       pos = playlist_get_index_from_id(playlist, selected_song_id);
-       if (pos >= 0)
-               list_window_set_cursor(lw, pos);
-
-       playlist_save_selection();
-}
-
-#ifndef NCMPC_MINI
-static gboolean
-scroll_timer_callback(G_GNUC_UNUSED gpointer data)
-{
-       scroll_source_id = 0;
-
-       hscroll_step(&hscroll);
-       playlist_repaint();
-       return false;
-}
-#endif
-
-static const char *
-list_callback(unsigned idx, bool *highlight, char **second_column, G_GNUC_UNUSED void *data)
-{
-       static char songname[MAX_SONG_LENGTH];
-       struct mpd_song *song;
-
-       assert(playlist != NULL);
-       assert(idx < playlist_length(playlist));
-
-       song = playlist_get(playlist, idx);
-       if ((int)mpd_song_get_id(song) == current_song_id)
-               *highlight = true;
-
-       strfsong(songname, MAX_SONG_LENGTH, options.list_format, song);
-
-#ifndef NCMPC_MINI
-       if (second_column != NULL && mpd_song_get_duration(song) > 0) {
-               char duration[32];
-               format_duration_short(duration, sizeof(duration),
-                                     mpd_song_get_duration(song));
-               *second_column = g_strdup(duration);
-       }
-
-       if (idx == lw->selected)
-       {
-               int second_column_len = 0;
-               if (second_column != NULL && *second_column != NULL)
-                       second_column_len = strlen(*second_column);
-               if (options.scroll && utf8_width(songname) > (unsigned)(COLS - second_column_len - 1) )
-               {
-                       static unsigned current_song;
-                       char *tmp;
-
-                       if (current_song != lw->selected) {
-                               hscroll_reset(&hscroll);
-                               current_song = lw->selected;
-                       }
-
-                       tmp = strscroll(&hscroll, songname, options.scroll_sep,
-                                       MAX_SONG_LENGTH);
-                       g_strlcpy(songname, tmp, MAX_SONG_LENGTH);
-                       g_free(tmp);
-
-                       if (scroll_source_id == 0)
-                               scroll_source_id =
-                                       g_timeout_add(1000,
-                                                     scroll_timer_callback,
-                                                     NULL);
-               } else {
-                       hscroll_reset(&hscroll);
-
-                       if (scroll_source_id != 0) {
-                               g_source_remove(scroll_source_id);
-                               scroll_source_id = 0;
-                       }
-               }
-       }
-#else
-       (void)second_column;
-#endif
-
-       return songname;
-}
-
-static void
-center_playing_item(struct mpdclient *c, bool center_cursor)
-{
-       const struct mpd_song *song;
-       unsigned length = c->playlist.list->len;
-       int idx;
-
-       song = mpdclient_get_current_song(c);
-       if (song == NULL)
-               return;
-
-       /* try to center the song that are playing */
-       idx = playlist_get_index(&c->playlist, c->song);
-       if (idx < 0)
-               return;
-
-       if (length < lw->rows)
-       {
-               if (center_cursor)
-                       list_window_set_cursor(lw, idx);
-               return;
-       }
-
-       list_window_center(lw, idx);
-
-       if (center_cursor) {
-               list_window_set_cursor(lw, idx);
-               return;
-       }
-
-       /* make sure the cursor is in the window */
-       list_window_fetch_cursor(lw);
-}
-
-#ifndef NCMPC_MINI
-static void
-save_pre_completion_cb(GCompletion *gcmp, G_GNUC_UNUSED gchar *line,
-                      void *data)
-{
-       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
-       GList **list = tmp->list;
-       struct mpdclient *c = tmp->c;
-
-       if( *list == NULL ) {
-               /* create completion list */
-               *list = gcmp_list_from_path(c, "", NULL, GCMP_TYPE_PLAYLIST);
-               g_completion_add_items(gcmp, *list);
-       }
-}
-
-static void
-save_post_completion_cb(G_GNUC_UNUSED GCompletion *gcmp,
-                       G_GNUC_UNUSED gchar *line, GList *items,
-                       G_GNUC_UNUSED void *data)
-{
-       if (g_list_length(items) >= 1)
-               screen_display_completion_list(items);
-}
-#endif
-
-#ifndef NCMPC_MINI
-/**
- * Wrapper for strncmp().  We are not allowed to pass &strncmp to
- * g_completion_set_compare(), because strncmp() takes size_t where
- * g_completion_set_compare passes a gsize value.
- */
-static gint
-completion_strncmp(const gchar *s1, const gchar *s2, gsize n)
-{
-       return strncmp(s1, s2, n);
-}
-#endif
-
-int
-playlist_save(struct mpdclient *c, char *name, char *defaultname)
-{
-       struct mpd_connection *connection;
-       gchar *filename, *filename_utf8;
-#ifndef NCMPC_MINI
-       GCompletion *gcmp;
-       GList *list = NULL;
-       completion_callback_data_t data;
-#endif
-
-#ifdef NCMPC_MINI
-       (void)defaultname;
-#endif
-
-#ifndef NCMPC_MINI
-       if (name == NULL) {
-               /* initialize completion support */
-               gcmp = g_completion_new(NULL);
-               g_completion_set_compare(gcmp, completion_strncmp);
-               data.list = &list;
-               data.dir_list = NULL;
-               data.c = c;
-               wrln_completion_callback_data = &data;
-               wrln_pre_completion_callback = save_pre_completion_cb;
-               wrln_post_completion_callback = save_post_completion_cb;
-
-
-               /* query the user for a filename */
-               filename = screen_readln(_("Save playlist as"),
-                                        defaultname,
-                                        NULL,
-                                        gcmp);
-
-               /* destroy completion support */
-               wrln_completion_callback_data = NULL;
-               wrln_pre_completion_callback = NULL;
-               wrln_post_completion_callback = NULL;
-               g_completion_free(gcmp);
-               list = string_list_free(list);
-               if( filename )
-                       filename=g_strstrip(filename);
-       } else
-#endif
-                       filename=g_strdup(name);
-
-       if (filename == NULL)
-               return -1;
-
-       /* send save command to mpd */
-
-       filename_utf8 = locale_to_utf8(filename);
-
-       connection = mpdclient_get_connection(c);
-       if (!mpd_run_save(connection, filename_utf8)) {
-               if (mpd_connection_get_error(connection) == MPD_ERROR_SERVER &&
-                   mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_EXIST &&
-                   mpd_connection_clear_error(connection)) {
-                       char *buf;
-                       int key;
-
-                       buf = g_strdup_printf(_("Replace %s [%s/%s] ? "),
-                                             filename, YES, NO);
-                       key = tolower(screen_getch(buf));
-                       g_free(buf);
-
-                       if (key != YES[0]) {
-                               g_free(filename_utf8);
-                               g_free(filename);
-                               screen_status_printf(_("Aborted"));
-                               return -1;
-                       }
-
-                       if (!mpd_run_rm(connection, filename_utf8) ||
-                           !mpd_run_save(connection, filename_utf8)) {
-                               mpdclient_handle_error(c);
-                               g_free(filename_utf8);
-                               g_free(filename);
-                               return -1;
-                       }
-               } else {
-                       mpdclient_handle_error(c);
-                       g_free(filename_utf8);
-                       g_free(filename);
-                       return -1;
-               }
-       }
-
-       c->events |= MPD_IDLE_STORED_PLAYLIST;
-
-       g_free(filename_utf8);
-
-       /* success */
-       screen_status_printf(_("Saved %s"), filename);
-       g_free(filename);
-       return 0;
-}
-
-#ifndef NCMPC_MINI
-static void add_dir(GCompletion *gcmp, gchar *dir, GList **dir_list,
-                   GList **list, struct mpdclient *c)
-{
-       g_completion_remove_items(gcmp, *list);
-       *list = string_list_remove(*list, dir);
-       *list = gcmp_list_from_path(c, dir, *list, GCMP_TYPE_RFILE);
-       g_completion_add_items(gcmp, *list);
-       *dir_list = g_list_append(*dir_list, g_strdup(dir));
-}
-
-static void add_pre_completion_cb(GCompletion *gcmp, gchar *line, void *data)
-{
-       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
-       GList **dir_list = tmp->dir_list;
-       GList **list = tmp->list;
-       struct mpdclient *c = tmp->c;
-
-       if (*list == NULL) {
-               /* create initial list */
-               *list = gcmp_list_from_path(c, "", NULL, GCMP_TYPE_RFILE);
-               g_completion_add_items(gcmp, *list);
-       } else if (line && line[0] && line[strlen(line)-1]=='/' &&
-                  string_list_find(*dir_list, line) == NULL) {
-               /* add directory content to list */
-               add_dir(gcmp, line, dir_list, list, c);
-       }
-}
-
-static void add_post_completion_cb(GCompletion *gcmp, gchar *line,
-                                  GList *items, void *data)
-{
-       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
-       GList **dir_list = tmp->dir_list;
-       GList **list = tmp->list;
-       struct mpdclient *c = tmp->c;
-
-       if (g_list_length(items) >= 1)
-               screen_display_completion_list(items);
-
-       if (line && line[0] && line[strlen(line) - 1] == '/' &&
-           string_list_find(*dir_list, line) == NULL) {
-               /* add directory content to list */
-               add_dir(gcmp, line, dir_list, list, c);
-       }
-}
-#endif
-
-static int
-handle_add_to_playlist(struct mpdclient *c)
-{
-       gchar *path;
-#ifndef NCMPC_MINI
-       GCompletion *gcmp;
-       GList *list = NULL;
-       GList *dir_list = NULL;
-       completion_callback_data_t data;
-
-       /* initialize completion support */
-       gcmp = g_completion_new(NULL);
-       g_completion_set_compare(gcmp, completion_strncmp);
-       data.list = &list;
-       data.dir_list = &dir_list;
-       data.c = c;
-       wrln_completion_callback_data = &data;
-       wrln_pre_completion_callback = add_pre_completion_cb;
-       wrln_post_completion_callback = add_post_completion_cb;
-#endif
-
-       /* get path */
-       path = screen_readln(_("Add"),
-                            NULL,
-                            NULL,
-#ifdef NCMPC_MINI
-                            NULL
-#else
-                            gcmp
-#endif
-                            );
-
-       /* destroy completion data */
-#ifndef NCMPC_MINI
-       wrln_completion_callback_data = NULL;
-       wrln_pre_completion_callback = NULL;
-       wrln_post_completion_callback = NULL;
-       g_completion_free(gcmp);
-       string_list_free(list);
-       string_list_free(dir_list);
-#endif
-
-       /* add the path to the playlist */
-       if (path != NULL) {
-               char *path_utf8 = locale_to_utf8(path);
-               mpdclient_cmd_add_path(c, path_utf8);
-               g_free(path_utf8);
-       }
-
-       g_free(path);
-       return 0;
-}
-
-static void
-screen_playlist_init(WINDOW *w, int cols, int rows)
-{
-       lw = list_window_init(w, cols, rows);
-}
-
-static gboolean
-timer_hide_cursor(gpointer data)
-{
-       struct mpdclient *c = data;
-
-       assert(options.hide_cursor > 0);
-       assert(timer_hide_cursor_id != 0);
-
-       timer_hide_cursor_id = 0;
-
-       /* hide the cursor when mpd is playing and the user is inactive */
-
-       if (c->status != NULL &&
-           mpd_status_get_state(c->status) == MPD_STATE_PLAY) {
-               lw->hide_cursor = true;
-               playlist_repaint();
-       } else
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
-
-       return FALSE;
-}
-
-static void
-screen_playlist_open(struct mpdclient *c)
-{
-       playlist = &c->playlist;
-
-       assert(timer_hide_cursor_id == 0);
-       if (options.hide_cursor > 0) {
-               lw->hide_cursor = false;
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
-       }
-
-       playlist_restore_selection();
-}
-
-static void
-screen_playlist_close(void)
-{
-       if (timer_hide_cursor_id != 0) {
-               g_source_remove(timer_hide_cursor_id);
-               timer_hide_cursor_id = 0;
-       }
-}
-
-static void
-screen_playlist_resize(int cols, int rows)
-{
-       list_window_resize(lw, cols, rows);
-}
-
-
-static void
-screen_playlist_exit(void)
-{
-       list_window_free(lw);
-}
-
-static const char *
-screen_playlist_title(char *str, size_t size)
-{
-       if (options.host == NULL)
-               return _("Playlist");
-
-       g_snprintf(str, size, _("Playlist on %s"), options.host);
-       return str;
-}
-
-static void
-screen_playlist_paint(void)
-{
-       list_window_paint(lw, list_callback, NULL);
-}
-
-static void
-screen_playlist_update(struct mpdclient *c)
-{
-       static int prev_song_id = -1;
-
-       if (c->events & MPD_IDLE_PLAYLIST)
-               playlist_restore_selection();
-
-       current_song_id = c->status != NULL &&
-               (mpd_status_get_state(c->status) == MPD_STATE_PLAY ||
-                mpd_status_get_state(c->status) == MPD_STATE_PAUSE)
-               ? (int)mpd_status_get_song_id(c->status) : -1;
-
-       if (current_song_id != prev_song_id) {
-               prev_song_id = current_song_id;
-
-               /* center the cursor */
-               if (options.auto_center && current_song_id != -1 && ! lw->range_selection)
-                       center_playing_item(c, false);
-
-               playlist_repaint();
-       } else if (c->events & MPD_IDLE_PLAYLIST) {
-               /* the playlist has changed, we must paint the new
-                  version */
-               playlist_repaint();
-       }
-}
-
-#ifdef HAVE_GETMOUSE
-static bool
-handle_mouse_event(struct mpdclient *c)
-{
-       int row;
-       unsigned selected;
-       unsigned long bstate;
-
-       if (screen_get_mouse_event(c, &bstate, &row) ||
-           list_window_mouse(lw, bstate, row)) {
-               playlist_repaint();
-               return true;
-       }
-
-       if (bstate & BUTTON1_DOUBLE_CLICKED) {
-               /* stop */
-               screen_cmd(c, CMD_STOP);
-               return true;
-       }
-
-       selected = lw->start + row;
-
-       if (bstate & BUTTON1_CLICKED) {
-               /* play */
-               if (lw->start + row < playlist_length(playlist))
-                       mpdclient_cmd_play(c, lw->start + row);
-       } else if (bstate & BUTTON3_CLICKED) {
-               /* delete */
-               if (selected == lw->selected)
-                       mpdclient_cmd_delete(c, lw->selected);
-       }
-
-       list_window_set_cursor(lw, selected);
-       playlist_save_selection();
-       playlist_repaint();
-
-       return true;
-}
-#endif
-
-static bool
-screen_playlist_cmd(struct mpdclient *c, command_t cmd)
-{
-       struct mpd_connection *connection;
-       static command_t cached_cmd = CMD_NONE;
-       command_t prev_cmd = cached_cmd;
-       struct list_window_range range;
-
-       cached_cmd = cmd;
-
-       lw->hide_cursor = false;
-
-       if (options.hide_cursor > 0) {
-               if (timer_hide_cursor_id != 0)
-                       g_source_remove(timer_hide_cursor_id);
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
-       }
-
-       if (list_window_cmd(lw, cmd)) {
-               playlist_save_selection();
-               playlist_repaint();
-               return true;
-       }
-
-       switch(cmd) {
-       case CMD_SCREEN_UPDATE:
-               center_playing_item(c, prev_cmd == CMD_SCREEN_UPDATE);
-               playlist_repaint();
-               return false;
-       case CMD_SELECT_PLAYING:
-               list_window_set_cursor(lw, playlist_get_index(&c->playlist,
-                                                             c->song));
-               playlist_save_selection();
-               playlist_repaint();
-               return true;
-
-       case CMD_LIST_FIND:
-       case CMD_LIST_RFIND:
-       case CMD_LIST_FIND_NEXT:
-       case CMD_LIST_RFIND_NEXT:
-               screen_find(lw, cmd, list_callback, NULL);
-               playlist_save_selection();
-               playlist_repaint();
-               return true;
-       case CMD_LIST_JUMP:
-               screen_jump(lw, list_callback, NULL, NULL);
-               playlist_save_selection();
-               playlist_repaint();
-               return true;
-
-#ifdef HAVE_GETMOUSE
-       case CMD_MOUSE_EVENT:
-               return handle_mouse_event(c);
-#endif
-
-#ifdef ENABLE_SONG_SCREEN
-       case CMD_SCREEN_SONG:
-               if (playlist_selected_song()) {
-                       screen_song_switch(c, playlist_selected_song());
-                       return true;
-               }
-
-               break;
-#endif
-
-#ifdef ENABLE_LYRICS_SCREEN
-       case CMD_SCREEN_LYRICS:
-               if (lw->selected < playlist_length(&c->playlist)) {
-                       struct mpd_song *selected = playlist_get(&c->playlist, lw->selected);
-                       bool follow = false;
-
-                       if (c->song && selected &&
-                           !strcmp(mpd_song_get_uri(selected),
-                                   mpd_song_get_uri(c->song)))
-                               follow = true;
-
-                       screen_lyrics_switch(c, selected, follow);
-                       return true;
-               }
-
-               break;
-#endif
-       case CMD_SCREEN_SWAP:
-               screen_swap(c, playlist_get(&c->playlist, lw->selected));
-               return true;
-
-       default:
-               break;
-       }
-
-       if (!mpdclient_is_connected(c))
-               return false;
-
-       switch(cmd) {
-       case CMD_PLAY:
-               mpdclient_cmd_play(c, lw->selected);
-               return true;
-
-       case CMD_DELETE:
-               list_window_get_range(lw, &range);
-               mpdclient_cmd_delete_range(c, range.start, range.end);
-
-               list_window_set_cursor(lw, range.start);
-               return true;
-
-       case CMD_SAVE_PLAYLIST:
-               playlist_save(c, NULL, NULL);
-               return true;
-
-       case CMD_ADD:
-               handle_add_to_playlist(c);
-               return true;
-
-       case CMD_SHUFFLE:
-               list_window_get_range(lw, &range);
-               if (range.end < range.start + 1)
-                       /* No range selection, shuffle all list. */
-                       break;
-
-               connection = mpdclient_get_connection(c);
-               if (mpd_run_shuffle_range(connection, range.start, range.end))
-                       screen_status_message(_("Shuffled playlist"));
-               else
-                       mpdclient_handle_error(c);
-               return true;
-
-       case CMD_LIST_MOVE_UP:
-               list_window_get_range(lw, &range);
-               if (range.start == 0 || range.end <= range.start)
-                       return false;
-
-               for (unsigned i = range.start; i < range.end; ++i)
-                       mpdclient_cmd_move(c, i, i - 1);
-
-               lw->selected--;
-               lw->range_base--;
-
-               playlist_save_selection();
-               return true;
-
-       case CMD_LIST_MOVE_DOWN:
-               list_window_get_range(lw, &range);
-               if (range.end >= playlist_length(&c->playlist))
-                       return false;
-
-               for (int i = range.end - 1; i >= (int)range.start; --i)
-                       mpdclient_cmd_move(c, i, i + 1);
-
-               lw->selected++;
-               lw->range_base++;
-
-               playlist_save_selection();
-               return true;
-
-       case CMD_LOCATE:
-               if (playlist_selected_song()) {
-                       screen_file_goto_song(c, playlist_selected_song());
-                       return true;
-               }
-
-               break;
-
-       default:
-               break;
-       }
-
-       return false;
-}
-
-const struct screen_functions screen_playlist = {
-       .init = screen_playlist_init,
-       .exit = screen_playlist_exit,
-       .open = screen_playlist_open,
-       .close = screen_playlist_close,
-       .resize = screen_playlist_resize,
-       .paint = screen_playlist_paint,
-       .update = screen_playlist_update,
-       .cmd = screen_playlist_cmd,
-       .get_title = screen_playlist_title,
-};
diff --git a/src/screen_play.h b/src/screen_play.h
deleted file mode 100644 (file)
index 9c77677..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* ncmpc (Ncurses MPD Client)
- * (c) 2004-2009 The Music Player Daemon Project
- * Project homepage: http://musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef NCMPC_SCREEN_PLAY_H
-#define NCMPC_SCREEN_PLAY_H
-
-struct mpdclient;
-
-extern const struct screen_functions screen_playlist;
-
-int
-playlist_save(struct mpdclient *c, char *name, char *defaultname);
-
-#endif
diff --git a/src/screen_queue.c b/src/screen_queue.c
new file mode 100644 (file)
index 0000000..0381d52
--- /dev/null
@@ -0,0 +1,800 @@
+/* ncmpc (Ncurses MPD Client)
+ * (c) 2004-2009 The Music Player Daemon Project
+ * Project homepage: http://musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "screen_queue.h"
+#include "screen_interface.h"
+#include "screen_file.h"
+#include "screen_message.h"
+#include "screen_find.h"
+#include "config.h"
+#include "i18n.h"
+#include "charset.h"
+#include "options.h"
+#include "mpdclient.h"
+#include "utils.h"
+#include "strfsong.h"
+#include "wreadln.h"
+#include "colors.h"
+#include "screen.h"
+#include "screen_utils.h"
+#include "screen_song.h"
+#include "screen_lyrics.h"
+
+#ifndef NCMPC_MINI
+#include "hscroll.h"
+#endif
+
+#include <mpd/client.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+
+#define MAX_SONG_LENGTH 512
+
+#ifndef NCMPC_MINI
+typedef struct
+{
+       GList **list;
+       GList **dir_list;
+       struct mpdclient *c;
+} completion_callback_data_t;
+
+static struct hscroll hscroll;
+static guint scroll_source_id;
+#endif
+
+static struct mpdclient_playlist *playlist;
+static int current_song_id = -1;
+static int selected_song_id = -1;
+static struct list_window *lw;
+static guint timer_hide_cursor_id;
+
+static void
+screen_queue_paint(void);
+
+static void
+screen_queue_repaint(void)
+{
+       screen_queue_paint();
+       wrefresh(lw->w);
+}
+
+static const struct mpd_song *
+screen_queue_selected_song(void)
+{
+       return !lw->range_selection &&
+               lw->selected < playlist_length(playlist)
+               ? playlist_get(playlist, lw->selected)
+               : NULL;
+}
+
+static void
+screen_queue_save_selection(void)
+{
+       selected_song_id = screen_queue_selected_song() != NULL
+               ? (int)mpd_song_get_id(screen_queue_selected_song())
+               : -1;
+}
+
+static void
+screen_queue_restore_selection(void)
+{
+       const struct mpd_song *song;
+       int pos;
+
+       list_window_set_length(lw, playlist_length(playlist));
+
+       if (selected_song_id < 0)
+               /* there was no selection */
+               return;
+
+       song = screen_queue_selected_song();
+       if (song != NULL &&
+           mpd_song_get_id(song) == (unsigned)selected_song_id)
+               /* selection is still valid */
+               return;
+
+       pos = playlist_get_index_from_id(playlist, selected_song_id);
+       if (pos >= 0)
+               list_window_set_cursor(lw, pos);
+
+       screen_queue_save_selection();
+}
+
+#ifndef NCMPC_MINI
+static gboolean
+scroll_timer_callback(G_GNUC_UNUSED gpointer data)
+{
+       scroll_source_id = 0;
+
+       hscroll_step(&hscroll);
+       screen_queue_repaint();
+       return false;
+}
+#endif
+
+static const char *
+screen_queue_lw_callback(unsigned idx, bool *highlight, char **second_column,
+                        G_GNUC_UNUSED void *data)
+{
+       static char songname[MAX_SONG_LENGTH];
+       struct mpd_song *song;
+
+       assert(playlist != NULL);
+       assert(idx < playlist_length(playlist));
+
+       song = playlist_get(playlist, idx);
+       if ((int)mpd_song_get_id(song) == current_song_id)
+               *highlight = true;
+
+       strfsong(songname, MAX_SONG_LENGTH, options.list_format, song);
+
+#ifndef NCMPC_MINI
+       if (second_column != NULL && mpd_song_get_duration(song) > 0) {
+               char duration[32];
+               format_duration_short(duration, sizeof(duration),
+                                     mpd_song_get_duration(song));
+               *second_column = g_strdup(duration);
+       }
+
+       if (idx == lw->selected)
+       {
+               int second_column_len = 0;
+               if (second_column != NULL && *second_column != NULL)
+                       second_column_len = strlen(*second_column);
+               if (options.scroll && utf8_width(songname) > (unsigned)(COLS - second_column_len - 1) )
+               {
+                       static unsigned current_song;
+                       char *tmp;
+
+                       if (current_song != lw->selected) {
+                               hscroll_reset(&hscroll);
+                               current_song = lw->selected;
+                       }
+
+                       tmp = strscroll(&hscroll, songname, options.scroll_sep,
+                                       MAX_SONG_LENGTH);
+                       g_strlcpy(songname, tmp, MAX_SONG_LENGTH);
+                       g_free(tmp);
+
+                       if (scroll_source_id == 0)
+                               scroll_source_id =
+                                       g_timeout_add(1000,
+                                                     scroll_timer_callback,
+                                                     NULL);
+               } else {
+                       hscroll_reset(&hscroll);
+
+                       if (scroll_source_id != 0) {
+                               g_source_remove(scroll_source_id);
+                               scroll_source_id = 0;
+                       }
+               }
+       }
+#else
+       (void)second_column;
+#endif
+
+       return songname;
+}
+
+static void
+center_playing_item(struct mpdclient *c, bool center_cursor)
+{
+       const struct mpd_song *song;
+       unsigned length = c->playlist.list->len;
+       int idx;
+
+       song = mpdclient_get_current_song(c);
+       if (song == NULL)
+               return;
+
+       /* try to center the song that are playing */
+       idx = playlist_get_index(&c->playlist, c->song);
+       if (idx < 0)
+               return;
+
+       if (length < lw->rows)
+       {
+               if (center_cursor)
+                       list_window_set_cursor(lw, idx);
+               return;
+       }
+
+       list_window_center(lw, idx);
+
+       if (center_cursor) {
+               list_window_set_cursor(lw, idx);
+               return;
+       }
+
+       /* make sure the cursor is in the window */
+       list_window_fetch_cursor(lw);
+}
+
+#ifndef NCMPC_MINI
+static void
+save_pre_completion_cb(GCompletion *gcmp, G_GNUC_UNUSED gchar *line,
+                      void *data)
+{
+       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
+       GList **list = tmp->list;
+       struct mpdclient *c = tmp->c;
+
+       if( *list == NULL ) {
+               /* create completion list */
+               *list = gcmp_list_from_path(c, "", NULL, GCMP_TYPE_PLAYLIST);
+               g_completion_add_items(gcmp, *list);
+       }
+}
+
+static void
+save_post_completion_cb(G_GNUC_UNUSED GCompletion *gcmp,
+                       G_GNUC_UNUSED gchar *line, GList *items,
+                       G_GNUC_UNUSED void *data)
+{
+       if (g_list_length(items) >= 1)
+               screen_display_completion_list(items);
+}
+#endif
+
+#ifndef NCMPC_MINI
+/**
+ * Wrapper for strncmp().  We are not allowed to pass &strncmp to
+ * g_completion_set_compare(), because strncmp() takes size_t where
+ * g_completion_set_compare passes a gsize value.
+ */
+static gint
+completion_strncmp(const gchar *s1, const gchar *s2, gsize n)
+{
+       return strncmp(s1, s2, n);
+}
+#endif
+
+int
+playlist_save(struct mpdclient *c, char *name, char *defaultname)
+{
+       struct mpd_connection *connection;
+       gchar *filename, *filename_utf8;
+#ifndef NCMPC_MINI
+       GCompletion *gcmp;
+       GList *list = NULL;
+       completion_callback_data_t data;
+#endif
+
+#ifdef NCMPC_MINI
+       (void)defaultname;
+#endif
+
+#ifndef NCMPC_MINI
+       if (name == NULL) {
+               /* initialize completion support */
+               gcmp = g_completion_new(NULL);
+               g_completion_set_compare(gcmp, completion_strncmp);
+               data.list = &list;
+               data.dir_list = NULL;
+               data.c = c;
+               wrln_completion_callback_data = &data;
+               wrln_pre_completion_callback = save_pre_completion_cb;
+               wrln_post_completion_callback = save_post_completion_cb;
+
+
+               /* query the user for a filename */
+               filename = screen_readln(_("Save playlist as"),
+                                        defaultname,
+                                        NULL,
+                                        gcmp);
+
+               /* destroy completion support */
+               wrln_completion_callback_data = NULL;
+               wrln_pre_completion_callback = NULL;
+               wrln_post_completion_callback = NULL;
+               g_completion_free(gcmp);
+               list = string_list_free(list);
+               if( filename )
+                       filename=g_strstrip(filename);
+       } else
+#endif
+                       filename=g_strdup(name);
+
+       if (filename == NULL)
+               return -1;
+
+       /* send save command to mpd */
+
+       filename_utf8 = locale_to_utf8(filename);
+
+       connection = mpdclient_get_connection(c);
+       if (!mpd_run_save(connection, filename_utf8)) {
+               if (mpd_connection_get_error(connection) == MPD_ERROR_SERVER &&
+                   mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_EXIST &&
+                   mpd_connection_clear_error(connection)) {
+                       char *buf;
+                       int key;
+
+                       buf = g_strdup_printf(_("Replace %s [%s/%s] ? "),
+                                             filename, YES, NO);
+                       key = tolower(screen_getch(buf));
+                       g_free(buf);
+
+                       if (key != YES[0]) {
+                               g_free(filename_utf8);
+                               g_free(filename);
+                               screen_status_printf(_("Aborted"));
+                               return -1;
+                       }
+
+                       if (!mpd_run_rm(connection, filename_utf8) ||
+                           !mpd_run_save(connection, filename_utf8)) {
+                               mpdclient_handle_error(c);
+                               g_free(filename_utf8);
+                               g_free(filename);
+                               return -1;
+                       }
+               } else {
+                       mpdclient_handle_error(c);
+                       g_free(filename_utf8);
+                       g_free(filename);
+                       return -1;
+               }
+       }
+
+       c->events |= MPD_IDLE_STORED_PLAYLIST;
+
+       g_free(filename_utf8);
+
+       /* success */
+       screen_status_printf(_("Saved %s"), filename);
+       g_free(filename);
+       return 0;
+}
+
+#ifndef NCMPC_MINI
+static void add_dir(GCompletion *gcmp, gchar *dir, GList **dir_list,
+                   GList **list, struct mpdclient *c)
+{
+       g_completion_remove_items(gcmp, *list);
+       *list = string_list_remove(*list, dir);
+       *list = gcmp_list_from_path(c, dir, *list, GCMP_TYPE_RFILE);
+       g_completion_add_items(gcmp, *list);
+       *dir_list = g_list_append(*dir_list, g_strdup(dir));
+}
+
+static void add_pre_completion_cb(GCompletion *gcmp, gchar *line, void *data)
+{
+       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
+       GList **dir_list = tmp->dir_list;
+       GList **list = tmp->list;
+       struct mpdclient *c = tmp->c;
+
+       if (*list == NULL) {
+               /* create initial list */
+               *list = gcmp_list_from_path(c, "", NULL, GCMP_TYPE_RFILE);
+               g_completion_add_items(gcmp, *list);
+       } else if (line && line[0] && line[strlen(line)-1]=='/' &&
+                  string_list_find(*dir_list, line) == NULL) {
+               /* add directory content to list */
+               add_dir(gcmp, line, dir_list, list, c);
+       }
+}
+
+static void add_post_completion_cb(GCompletion *gcmp, gchar *line,
+                                  GList *items, void *data)
+{
+       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
+       GList **dir_list = tmp->dir_list;
+       GList **list = tmp->list;
+       struct mpdclient *c = tmp->c;
+
+       if (g_list_length(items) >= 1)
+               screen_display_completion_list(items);
+
+       if (line && line[0] && line[strlen(line) - 1] == '/' &&
+           string_list_find(*dir_list, line) == NULL) {
+               /* add directory content to list */
+               add_dir(gcmp, line, dir_list, list, c);
+       }
+}
+#endif
+
+static int
+handle_add_to_playlist(struct mpdclient *c)
+{
+       gchar *path;
+#ifndef NCMPC_MINI
+       GCompletion *gcmp;
+       GList *list = NULL;
+       GList *dir_list = NULL;
+       completion_callback_data_t data;
+
+       /* initialize completion support */
+       gcmp = g_completion_new(NULL);
+       g_completion_set_compare(gcmp, completion_strncmp);
+       data.list = &list;
+       data.dir_list = &dir_list;
+       data.c = c;
+       wrln_completion_callback_data = &data;
+       wrln_pre_completion_callback = add_pre_completion_cb;
+       wrln_post_completion_callback = add_post_completion_cb;
+#endif
+
+       /* get path */
+       path = screen_readln(_("Add"),
+                            NULL,
+                            NULL,
+#ifdef NCMPC_MINI
+                            NULL
+#else
+                            gcmp
+#endif
+                            );
+
+       /* destroy completion data */
+#ifndef NCMPC_MINI
+       wrln_completion_callback_data = NULL;
+       wrln_pre_completion_callback = NULL;
+       wrln_post_completion_callback = NULL;
+       g_completion_free(gcmp);
+       string_list_free(list);
+       string_list_free(dir_list);
+#endif
+
+       /* add the path to the playlist */
+       if (path != NULL) {
+               char *path_utf8 = locale_to_utf8(path);
+               mpdclient_cmd_add_path(c, path_utf8);
+               g_free(path_utf8);
+       }
+
+       g_free(path);
+       return 0;
+}
+
+static void
+screen_queue_init(WINDOW *w, int cols, int rows)
+{
+       lw = list_window_init(w, cols, rows);
+}
+
+static gboolean
+timer_hide_cursor(gpointer data)
+{
+       struct mpdclient *c = data;
+
+       assert(options.hide_cursor > 0);
+       assert(timer_hide_cursor_id != 0);
+
+       timer_hide_cursor_id = 0;
+
+       /* hide the cursor when mpd is playing and the user is inactive */
+
+       if (c->status != NULL &&
+           mpd_status_get_state(c->status) == MPD_STATE_PLAY) {
+               lw->hide_cursor = true;
+               screen_queue_repaint();
+       } else
+               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
+                                                    timer_hide_cursor, c);
+
+       return FALSE;
+}
+
+static void
+screen_queue_open(struct mpdclient *c)
+{
+       playlist = &c->playlist;
+
+       assert(timer_hide_cursor_id == 0);
+       if (options.hide_cursor > 0) {
+               lw->hide_cursor = false;
+               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
+                                                    timer_hide_cursor, c);
+       }
+
+       screen_queue_restore_selection();
+}
+
+static void
+screen_queue_close(void)
+{
+       if (timer_hide_cursor_id != 0) {
+               g_source_remove(timer_hide_cursor_id);
+               timer_hide_cursor_id = 0;
+       }
+}
+
+static void
+screen_queue_resize(int cols, int rows)
+{
+       list_window_resize(lw, cols, rows);
+}
+
+
+static void
+screen_queue_exit(void)
+{
+       list_window_free(lw);
+}
+
+static const char *
+screen_queue_title(char *str, size_t size)
+{
+       if (options.host == NULL)
+               return _("Playlist");
+
+       g_snprintf(str, size, _("Playlist on %s"), options.host);
+       return str;
+}
+
+static void
+screen_queue_paint(void)
+{
+       list_window_paint(lw, screen_queue_lw_callback, NULL);
+}
+
+static void
+screen_queue_update(struct mpdclient *c)
+{
+       static int prev_song_id = -1;
+
+       if (c->events & MPD_IDLE_PLAYLIST)
+               screen_queue_restore_selection();
+
+       current_song_id = c->status != NULL &&
+               (mpd_status_get_state(c->status) == MPD_STATE_PLAY ||
+                mpd_status_get_state(c->status) == MPD_STATE_PAUSE)
+               ? (int)mpd_status_get_song_id(c->status) : -1;
+
+       if (current_song_id != prev_song_id) {
+               prev_song_id = current_song_id;
+
+               /* center the cursor */
+               if (options.auto_center && current_song_id != -1 && ! lw->range_selection)
+                       center_playing_item(c, false);
+
+               screen_queue_repaint();
+       } else if (c->events & MPD_IDLE_PLAYLIST) {
+               /* the playlist has changed, we must paint the new
+                  version */
+               screen_queue_repaint();
+       }
+}
+
+#ifdef HAVE_GETMOUSE
+static bool
+handle_mouse_event(struct mpdclient *c)
+{
+       int row;
+       unsigned selected;
+       unsigned long bstate;
+
+       if (screen_get_mouse_event(c, &bstate, &row) ||
+           list_window_mouse(lw, bstate, row)) {
+               screen_queue_repaint();
+               return true;
+       }
+
+       if (bstate & BUTTON1_DOUBLE_CLICKED) {
+               /* stop */
+               screen_cmd(c, CMD_STOP);
+               return true;
+       }
+
+       selected = lw->start + row;
+
+       if (bstate & BUTTON1_CLICKED) {
+               /* play */
+               if (lw->start + row < playlist_length(playlist))
+                       mpdclient_cmd_play(c, lw->start + row);
+       } else if (bstate & BUTTON3_CLICKED) {
+               /* delete */
+               if (selected == lw->selected)
+                       mpdclient_cmd_delete(c, lw->selected);
+       }
+
+       list_window_set_cursor(lw, selected);
+       screen_queue_save_selection();
+       screen_queue_repaint();
+
+       return true;
+}
+#endif
+
+static bool
+screen_queue_cmd(struct mpdclient *c, command_t cmd)
+{
+       struct mpd_connection *connection;
+       static command_t cached_cmd = CMD_NONE;
+       command_t prev_cmd = cached_cmd;
+       struct list_window_range range;
+
+       cached_cmd = cmd;
+
+       lw->hide_cursor = false;
+
+       if (options.hide_cursor > 0) {
+               if (timer_hide_cursor_id != 0)
+                       g_source_remove(timer_hide_cursor_id);
+               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
+                                                    timer_hide_cursor, c);
+       }
+
+       if (list_window_cmd(lw, cmd)) {
+               screen_queue_save_selection();
+               screen_queue_repaint();
+               return true;
+       }
+
+       switch(cmd) {
+       case CMD_SCREEN_UPDATE:
+               center_playing_item(c, prev_cmd == CMD_SCREEN_UPDATE);
+               screen_queue_repaint();
+               return false;
+       case CMD_SELECT_PLAYING:
+               list_window_set_cursor(lw, playlist_get_index(&c->playlist,
+                                                             c->song));
+               screen_queue_save_selection();
+               screen_queue_repaint();
+               return true;
+
+       case CMD_LIST_FIND:
+       case CMD_LIST_RFIND:
+       case CMD_LIST_FIND_NEXT:
+       case CMD_LIST_RFIND_NEXT:
+               screen_find(lw, cmd, screen_queue_lw_callback, NULL);
+               screen_queue_save_selection();
+               screen_queue_repaint();
+               return true;
+       case CMD_LIST_JUMP:
+               screen_jump(lw, screen_queue_lw_callback, NULL, NULL);
+               screen_queue_save_selection();
+               screen_queue_repaint();
+               return true;
+
+#ifdef HAVE_GETMOUSE
+       case CMD_MOUSE_EVENT:
+               return handle_mouse_event(c);
+#endif
+
+#ifdef ENABLE_SONG_SCREEN
+       case CMD_SCREEN_SONG:
+               if (screen_queue_selected_song() != NULL) {
+                       screen_song_switch(c, screen_queue_selected_song());
+                       return true;
+               }
+
+               break;
+#endif
+
+#ifdef ENABLE_LYRICS_SCREEN
+       case CMD_SCREEN_LYRICS:
+               if (lw->selected < playlist_length(&c->playlist)) {
+                       struct mpd_song *selected = playlist_get(&c->playlist, lw->selected);
+                       bool follow = false;
+
+                       if (c->song && selected &&
+                           !strcmp(mpd_song_get_uri(selected),
+                                   mpd_song_get_uri(c->song)))
+                               follow = true;
+
+                       screen_lyrics_switch(c, selected, follow);
+                       return true;
+               }
+
+               break;
+#endif
+       case CMD_SCREEN_SWAP:
+               screen_swap(c, playlist_get(&c->playlist, lw->selected));
+               return true;
+
+       default:
+               break;
+       }
+
+       if (!mpdclient_is_connected(c))
+               return false;
+
+       switch(cmd) {
+       case CMD_PLAY:
+               mpdclient_cmd_play(c, lw->selected);
+               return true;
+
+       case CMD_DELETE:
+               list_window_get_range(lw, &range);
+               mpdclient_cmd_delete_range(c, range.start, range.end);
+
+               list_window_set_cursor(lw, range.start);
+               return true;
+
+       case CMD_SAVE_PLAYLIST:
+               playlist_save(c, NULL, NULL);
+               return true;
+
+       case CMD_ADD:
+               handle_add_to_playlist(c);
+               return true;
+
+       case CMD_SHUFFLE:
+               list_window_get_range(lw, &range);
+               if (range.end < range.start + 1)
+                       /* No range selection, shuffle all list. */
+                       break;
+
+               connection = mpdclient_get_connection(c);
+               if (mpd_run_shuffle_range(connection, range.start, range.end))
+                       screen_status_message(_("Shuffled playlist"));
+               else
+                       mpdclient_handle_error(c);
+               return true;
+
+       case CMD_LIST_MOVE_UP:
+               list_window_get_range(lw, &range);
+               if (range.start == 0 || range.end <= range.start)
+                       return false;
+
+               for (unsigned i = range.start; i < range.end; ++i)
+                       mpdclient_cmd_move(c, i, i - 1);
+
+               lw->selected--;
+               lw->range_base--;
+
+               screen_queue_save_selection();
+               return true;
+
+       case CMD_LIST_MOVE_DOWN:
+               list_window_get_range(lw, &range);
+               if (range.end >= playlist_length(&c->playlist))
+                       return false;
+
+               for (int i = range.end - 1; i >= (int)range.start; --i)
+                       mpdclient_cmd_move(c, i, i + 1);
+
+               lw->selected++;
+               lw->range_base++;
+
+               screen_queue_save_selection();
+               return true;
+
+       case CMD_LOCATE:
+               if (screen_queue_selected_song() != NULL) {
+                       screen_file_goto_song(c, screen_queue_selected_song());
+                       return true;
+               }
+
+               break;
+
+       default:
+               break;
+       }
+
+       return false;
+}
+
+const struct screen_functions screen_queue = {
+       .init = screen_queue_init,
+       .exit = screen_queue_exit,
+       .open = screen_queue_open,
+       .close = screen_queue_close,
+       .resize = screen_queue_resize,
+       .paint = screen_queue_paint,
+       .update = screen_queue_update,
+       .cmd = screen_queue_cmd,
+       .get_title = screen_queue_title,
+};
diff --git a/src/screen_queue.h b/src/screen_queue.h
new file mode 100644 (file)
index 0000000..2c3075f
--- /dev/null
@@ -0,0 +1,30 @@
+/* ncmpc (Ncurses MPD Client)
+ * (c) 2004-2009 The Music Player Daemon Project
+ * Project homepage: http://musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef NCMPC_SCREEN_QUEUE_H
+#define NCMPC_SCREEN_QUEUE_H
+
+struct mpdclient;
+
+extern const struct screen_functions screen_queue;
+
+int
+playlist_save(struct mpdclient *c, char *name, char *defaultname);
+
+#endif