X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fscreen_browser.c;h=e0c37cbc2e0a48a04e1a66ee3be030b6aad6786a;hb=63fc23f1c83f52eb47b5511e97bb1fe7cf7d82d5;hp=4d911e0d7a618368f0caa3ab0e1ffd3fff438215;hpb=45352152fbdcac20b39161069406ad6d5288bd98;p=ncmpc.git diff --git a/src/screen_browser.c b/src/screen_browser.c index 4d911e0..e0c37cb 100644 --- a/src/screen_browser.c +++ b/src/screen_browser.c @@ -1,6 +1,6 @@ -/* - * (c) 2004 by Kalle Wallin - * Copyright (C) 2008 Max Kellermann +/* ncmpc (Ncurses MPD Client) + * (c) 2004-2017 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 @@ -11,22 +11,33 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * 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 "config.h" #include "screen_browser.h" +#include "screen_file.h" +#include "screen_song.h" +#include "screen_lyrics.h" +#include "screen_status.h" +#include "screen_find.h" +#include "screen.h" #include "i18n.h" #include "options.h" #include "charset.h" #include "strfsong.h" -#include "screen_utils.h" +#include "mpdclient.h" +#include "filelist.h" +#include "colors.h" +#include "paint.h" +#include "song_paint.h" -#include +#include -#undef USE_OLD_ADD +#include #define BUFSIZE 1024 @@ -34,54 +45,23 @@ #define HIGHLIGHT (0x01) #endif -static const char playlist_format[] = "*%s*"; - #ifndef NCMPC_MINI -/* clear the highlight flag for all items in the filelist */ -static void -clear_highlights(mpdclient_filelist_t *fl) -{ - guint i; - - for (i = 0; i < filelist_length(fl); ++i) { - struct filelist_entry *entry = filelist_get(fl, i); - - entry->flags &= ~HIGHLIGHT; - } -} - -/* change the highlight flag for a song */ -static void -set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight) -{ - int i = filelist_find_song(fl, song); - struct filelist_entry *entry; - - if (i < 0) - return; - - entry = filelist_get(fl, i); - if (highlight) - entry->flags |= HIGHLIGHT; - else - entry->flags &= ~HIGHLIGHT; -} - /* sync highlight flags with playlist */ void -sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl) +screen_browser_sync_highlights(struct filelist *fl, + const struct mpdclient_playlist *playlist) { - guint i; - - for (i = 0; i < filelist_length(fl); ++i) { + for (unsigned i = 0; i < filelist_length(fl); ++i) { struct filelist_entry *entry = filelist_get(fl, i); - mpd_InfoEntity *entity = entry->entity; + const struct mpd_entity *entity = entry->entity; - if ( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) { - mpd_Song *song = entity->info.song; + if (entity != NULL && mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { + const struct mpd_song *song = + mpd_entity_get_song(entity); - if( playlist_get_index_from_file(c, song->file) >= 0 ) + if (playlist_get_index_from_same_song(playlist, + song) >= 0) entry->flags |= HIGHLIGHT; else entry->flags &= ~HIGHLIGHT; @@ -89,76 +69,44 @@ sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl) } } -/* the playlist have been updated -> fix highlights */ -void -browser_playlist_changed(struct screen_browser *browser, mpdclient_t *c, - int event, gpointer data) -{ - if (browser->filelist == NULL) - return; - - switch(event) { - case PLAYLIST_EVENT_CLEAR: - clear_highlights(browser->filelist); - break; - case PLAYLIST_EVENT_ADD: - set_highlight(browser->filelist, (mpd_Song *) data, 1); - break; - case PLAYLIST_EVENT_DELETE: - set_highlight(browser->filelist, (mpd_Song *) data, 0); - break; - case PLAYLIST_EVENT_MOVE: - break; - default: - sync_highlights(c, browser->filelist); - break; - } -} - #endif /* list_window callback */ -const char * -browser_lw_callback(unsigned idx, bool *highlight, void *data) +static const char * +browser_lw_callback(unsigned idx, void *data) { + const struct filelist *fl = (const struct filelist *) data; static char buf[BUFSIZE]; - mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data; - filelist_entry_t *entry; - mpd_InfoEntity *entity; - if (idx >= filelist_length(fl)) - return NULL; + assert(fl != NULL); + assert(idx < filelist_length(fl)); - entry = filelist_get(fl, idx); + const struct filelist_entry *entry = filelist_get(fl, idx); assert(entry != NULL); - entity = entry->entity; -#ifndef NCMPC_MINI - *highlight = (entry->flags & HIGHLIGHT) != 0; -#else - *highlight = false; -#endif + const struct mpd_entity *entity = entry->entity; if( entity == NULL ) - return "[..]"; + return ".."; - if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) { - mpd_Directory *dir = entity->info.directory; - char *directory = utf8_to_locale(g_basename(dir->path)); - - g_snprintf(buf, BUFSIZE, "[%s]", directory); + if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_DIRECTORY) { + const struct mpd_directory *dir = + mpd_entity_get_directory(entity); + char *directory = utf8_to_locale(g_basename(mpd_directory_get_path(dir))); + g_strlcpy(buf, directory, sizeof(buf)); g_free(directory); return buf; - } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) { - mpd_Song *song = entity->info.song; + } else if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { + const struct mpd_song *song = mpd_entity_get_song(entity); strfsong(buf, BUFSIZE, options.list_format, song); return buf; - } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) { - mpd_PlaylistFile *plf = entity->info.playlistFile; - char *filename = utf8_to_locale(g_basename(plf->path)); + } else if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_PLAYLIST) { + const struct mpd_playlist *playlist = + mpd_entity_get_playlist(entity); + char *filename = utf8_to_locale(g_basename(mpd_playlist_get_path(playlist))); - g_snprintf(buf, BUFSIZE, playlist_format, filename); + g_strlcpy(buf, filename, sizeof(buf)); g_free(filename); return buf; } @@ -166,244 +114,188 @@ browser_lw_callback(unsigned idx, bool *highlight, void *data) return "Error: Unknown entry!"; } -/* chdir */ -bool -browser_change_directory(struct screen_browser *browser, mpdclient_t *c, - filelist_entry_t *entry, const char *new_path) +static bool +load_playlist(struct mpdclient *c, const struct mpd_playlist *playlist) { - mpd_InfoEntity *entity = NULL; - gchar *path = NULL; - char *old_path; - int idx; - - if( entry!=NULL ) - entity = entry->entity; - else if( new_path==NULL ) + struct mpd_connection *connection = mpdclient_get_connection(c); + + if (connection == NULL) return false; - if( entity==NULL ) { - if( entry || 0==strcmp(new_path, "..") ) { - /* return to parent */ - char *parent = g_path_get_dirname(browser->filelist->path); - if( strcmp(parent, ".") == 0 ) - parent[0] = '\0'; - path = g_strdup(parent); - g_free(parent); - } else { - /* entry==NULL, then new_path ("" is root) */ - path = g_strdup(new_path); - } - } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) { - /* enter sub */ - mpd_Directory *dir = entity->info.directory; - path = g_strdup(dir->path); + if (mpd_run_load(connection, mpd_playlist_get_path(playlist))) { + char *filename = utf8_to_locale(mpd_playlist_get_path(playlist)); + screen_status_printf(_("Loading playlist %s..."), + g_basename(filename)); + g_free(filename); + + c->events |= MPD_IDLE_QUEUE; } else + mpdclient_handle_error(c); + + return true; +} + +static bool +enqueue_and_play(struct mpdclient *c, struct filelist_entry *entry) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) return false; - if (browser->filelist != NULL) { - old_path = g_strdup(browser->filelist->path); - filelist_free(browser->filelist); - } else - old_path = NULL; + const struct mpd_song *song = mpd_entity_get_song(entry->entity); + int id; - browser->filelist = mpdclient_filelist_get(c, path); #ifndef NCMPC_MINI - sync_highlights(c, browser->filelist); + if (!(entry->flags & HIGHLIGHT)) + id = -1; + else #endif + id = playlist_get_id_from_same_song(&c->playlist, song); + + if (id < 0) { + char buf[BUFSIZE]; + + id = mpd_run_add_id(connection, mpd_song_get_uri(song)); + if (id < 0) { + mpdclient_handle_error(c); + return false; + } - idx = old_path != NULL - ? filelist_find_directory(browser->filelist, old_path) - : -1; - g_free(old_path); +#ifndef NCMPC_MINI + entry->flags |= HIGHLIGHT; +#endif + strfsong(buf, BUFSIZE, options.list_format, song); + screen_status_printf(_("Adding \'%s\' to queue"), buf); + } - list_window_reset(browser->lw); - if (idx >= 0) { - list_window_set_selected(browser->lw, idx); - list_window_center(browser->lw, - filelist_length(browser->filelist), idx); + if (!mpd_run_play_id(connection, id)) { + mpdclient_handle_error(c); + return false; } - g_free(path); return true; } -static bool -load_playlist(mpdclient_t *c, filelist_entry_t *entry) +struct filelist_entry * +browser_get_selected_entry(const struct screen_browser *browser) { - mpd_InfoEntity *entity = entry->entity; - mpd_PlaylistFile *plf = entity->info.playlistFile; - char *filename = utf8_to_locale(plf->path); + struct list_window_range range; - if (mpdclient_cmd_load_playlist(c, plf->path) == 0) - screen_status_printf(_("Loading playlist %s..."), - g_basename(filename)); - g_free(filename); - return true; + list_window_get_range(browser->lw, &range); + + if (browser->filelist == NULL || + range.end <= range.start || + range.end > range.start + 1 || + range.start >= filelist_length(browser->filelist)) + return NULL; + + return filelist_get(browser->filelist, range.start); } -static bool -enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry) +static const struct mpd_entity * +browser_get_selected_entity(const struct screen_browser *browser) { - int idx; - mpd_InfoEntity *entity = entry->entity; - mpd_Song *song = entity->info.song; + const struct filelist_entry *entry = browser_get_selected_entry(browser); -#ifndef NCMPC_MINI - if (!(entry->flags & HIGHLIGHT)) { -#endif - if (mpdclient_cmd_add(c, song) == 0) { - char buf[BUFSIZE]; + return entry != NULL + ? entry->entity + : NULL; +} -#ifndef NCMPC_MINI - entry->flags |= HIGHLIGHT; -#endif - strfsong(buf, BUFSIZE, options.list_format, song); - screen_status_printf(_("Adding \'%s\' to playlist\n"), buf); - mpdclient_update(c); /* get song id */ - } else - return false; -#ifndef NCMPC_MINI - } -#endif +static const struct mpd_song * +browser_get_selected_song(const struct screen_browser *browser) +{ + const struct mpd_entity *entity = browser_get_selected_entity(browser); - idx = playlist_get_index_from_file(c, song->file); - mpdclient_cmd_play(c, idx); - return true; + return entity != NULL && + mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG + ? mpd_entity_get_song(entity) + : NULL; } static struct filelist_entry * -browser_get_selected(const struct screen_browser *browser) +browser_get_index(const struct screen_browser *browser, unsigned i) { if (browser->filelist == NULL || - browser->lw->selected >= filelist_length(browser->filelist)) + i >= filelist_length(browser->filelist)) return NULL; - return filelist_get(browser->filelist, browser->lw->selected); + return filelist_get(browser->filelist, i); } static bool -browser_handle_enter(struct screen_browser *browser, mpdclient_t *c) +browser_handle_enter(struct screen_browser *browser, struct mpdclient *c) { - struct filelist_entry *entry = browser_get_selected(browser); - mpd_InfoEntity *entity; + struct filelist_entry *entry = browser_get_selected_entry(browser); + if (entry == NULL) + return false; - if( entry==NULL ) + struct mpd_entity *entity = entry->entity; + if (entity == NULL) return false; - entity = entry->entity; - if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) - return browser_change_directory(browser, c, entry, NULL); - else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) - return load_playlist(c, entry); - else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) + if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_PLAYLIST) + return load_playlist(c, mpd_entity_get_playlist(entity)); + else if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) return enqueue_and_play(c, entry); return false; } - -#ifdef USE_OLD_ADD - -static int -add_directory(mpdclient_t *c, char *dir) -{ - mpd_InfoEntity *entity; - GList *subdir_list = NULL; - GList *list = NULL; - char *dirname; - - dirname = utf8_to_locale(dir); - screen_status_printf(_("Adding directory %s...\n"), dirname); - doupdate(); - g_free(dirname); - dirname = NULL; - - mpd_sendLsInfoCommand(c->connection, dir); - mpd_sendCommandListBegin(c->connection); - while( (entity=mpd_getNextInfoEntity(c->connection)) ) { - if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) { - mpd_Song *song = entity->info.song; - mpd_sendAddCommand(c->connection, song->file); - mpd_freeInfoEntity(entity); - } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) { - subdir_list = g_list_append(subdir_list, (gpointer) entity); - } else - mpd_freeInfoEntity(entity); - } - mpd_sendCommandListEnd(c->connection); - mpdclient_finish_command(c); - c->need_update = TRUE; - - list = g_list_first(subdir_list); - while( list!=NULL ) { - mpd_Directory *dir; - - entity = list->data; - dir = entity->info.directory; - add_directory(c, dir->path); - mpd_freeInfoEntity(entity); - list->data=NULL; - list=list->next; - } - g_list_free(subdir_list); - return 0; -} -#endif - static bool -browser_select_entry(mpdclient_t *c, filelist_entry_t *entry, - G_GNUC_UNUSED gboolean toggle) +browser_select_entry(struct mpdclient *c, struct filelist_entry *entry, + gcc_unused gboolean toggle) { assert(entry != NULL); assert(entry->entity != NULL); - if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) - return load_playlist(c, entry); + if (mpd_entity_get_type(entry->entity) == MPD_ENTITY_TYPE_PLAYLIST) + return load_playlist(c, mpd_entity_get_playlist(entry->entity)); - if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) { - mpd_Directory *dir = entry->entity->info.directory; -#ifdef USE_OLD_ADD - add_directory(c, tmp); -#else - if (mpdclient_cmd_add_path(c, dir->path) == 0) { - char *tmp = utf8_to_locale(dir->path); + if (mpd_entity_get_type(entry->entity) == MPD_ENTITY_TYPE_DIRECTORY) { + const struct mpd_directory *dir = + mpd_entity_get_directory(entry->entity); + + if (mpdclient_cmd_add_path(c, mpd_directory_get_path(dir))) { + char *tmp = utf8_to_locale(mpd_directory_get_path(dir)); - screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp); + screen_status_printf(_("Adding \'%s\' to queue"), tmp); g_free(tmp); } -#endif + return true; } - if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG) + if (mpd_entity_get_type(entry->entity) != MPD_ENTITY_TYPE_SONG) return false; - assert(entry->entity->info.song != NULL); - #ifndef NCMPC_MINI if (!toggle || (entry->flags & HIGHLIGHT) == 0) #endif { - mpd_Song *song = entry->entity->info.song; + const struct mpd_song *song = + mpd_entity_get_song(entry->entity); #ifndef NCMPC_MINI entry->flags |= HIGHLIGHT; #endif - if (mpdclient_cmd_add(c, song) == 0) { + if (mpdclient_cmd_add(c, song)) { char buf[BUFSIZE]; strfsong(buf, BUFSIZE, options.list_format, song); - screen_status_printf(_("Adding \'%s\' to playlist\n"), buf); + screen_status_printf(_("Adding \'%s\' to queue"), buf); } #ifndef NCMPC_MINI } else { /* remove song from playlist */ - mpd_Song *song = entry->entity->info.song; + const struct mpd_song *song = + mpd_entity_get_song(entry->entity); int idx; entry->flags &= ~HIGHLIGHT; - while ((idx = playlist_get_index_from_file(c, song->file)) >=0) + while ((idx = playlist_get_index_from_same_song(&c->playlist, + song)) >= 0) mpdclient_cmd_delete(c, idx); #endif } @@ -412,36 +304,45 @@ browser_select_entry(mpdclient_t *c, filelist_entry_t *entry, } static bool -browser_handle_select(struct screen_browser *browser, mpdclient_t *c) +browser_handle_select(struct screen_browser *browser, struct mpdclient *c) { - struct filelist_entry *entry = browser_get_selected(browser); + struct list_window_range range; + bool success = false; - if (entry == NULL || entry->entity == NULL) - return false; + list_window_get_range(browser->lw, &range); + for (unsigned i = range.start; i < range.end; ++i) { + struct filelist_entry *entry = browser_get_index(browser, i); + if (entry != NULL && entry->entity != NULL) + success = browser_select_entry(c, entry, TRUE); + } - return browser_select_entry(c, entry, TRUE); + return range.end == range.start + 1 && success; } static bool -browser_handle_add(struct screen_browser *browser, mpdclient_t *c) +browser_handle_add(struct screen_browser *browser, struct mpdclient *c) { - struct filelist_entry *entry = browser_get_selected(browser); + struct list_window_range range; + bool success = false; - if (entry == NULL || entry->entity == NULL) - return false; + list_window_get_range(browser->lw, &range); + for (unsigned i = range.start; i < range.end; ++i) { + struct filelist_entry *entry = browser_get_index(browser, i); + if (entry != NULL && entry->entity != NULL) + success = browser_select_entry(c, entry, FALSE) || + success; + } - return browser_select_entry(c, entry, FALSE); + return range.end == range.start + 1 && success; } static void -browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c) +browser_handle_select_all(struct screen_browser *browser, struct mpdclient *c) { - guint i; - if (browser->filelist == NULL) return; - for (i = 0; i < filelist_length(browser->filelist); ++i) { + for (unsigned i = 0; i < filelist_length(browser->filelist); ++i) { struct filelist_entry *entry = filelist_get(browser->filelist, i); if (entry != NULL && entry->entity != NULL) @@ -450,25 +351,17 @@ browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c) } #ifdef HAVE_GETMOUSE -static int -browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c) + +bool +browser_mouse(struct screen_browser *browser, + struct mpdclient *c, gcc_unused int x, int row, mmask_t bstate) { - int row; unsigned prev_selected = browser->lw->selected; - unsigned long bstate; - int length; - - if (browser->filelist) - length = filelist_length(browser->filelist); - else - length = 0; - if (screen_get_mouse_event(c, &bstate, &row) || - list_window_mouse(browser->lw, length, bstate, row)) - return 1; + if (list_window_mouse(browser->lw, bstate, row)) + return true; - browser->lw->selected = browser->lw->start + row; - list_window_check_selected(browser->lw, length); + list_window_set_cursor(browser->lw, browser->lw->start + row); if( bstate & BUTTON1_CLICKED ) { if (prev_selected == browser->lw->selected) @@ -478,97 +371,189 @@ browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c) browser_handle_select(browser, c); } - return 1; + return true; } + #endif +static void +screen_browser_paint_callback(WINDOW *w, unsigned i, unsigned y, + unsigned width, bool selected, const void *data); + bool browser_cmd(struct screen_browser *browser, struct mpdclient *c, command_t cmd) { - struct filelist_entry *entry; + if (browser->filelist == NULL) + return false; - switch (cmd) { - case CMD_PLAY: - browser_handle_enter(browser, c); + if (list_window_cmd(browser->lw, cmd)) return true; - case CMD_SELECT: - if (browser_handle_select(browser, c)) - /* continue and select next item... */ - cmd = CMD_LIST_NEXT; - - /* call list_window_cmd to go to the next item */ - break; - - case CMD_ADD: - if (browser_handle_add(browser, c)) - /* continue and select next item... */ - cmd = CMD_LIST_NEXT; - - /* call list_window_cmd to go to the next item */ - break; - - case CMD_SELECT_ALL: - browser_handle_select_all(browser, c); - return true; + switch (cmd) { +#if defined(ENABLE_SONG_SCREEN) || defined(ENABLE_LYRICS_SCREEN) + const struct mpd_song *song; +#endif case CMD_LIST_FIND: case CMD_LIST_RFIND: case CMD_LIST_FIND_NEXT: case CMD_LIST_RFIND_NEXT: - screen_find(browser->lw, filelist_length(browser->filelist), - cmd, browser_lw_callback, + screen_find(browser->lw, cmd, browser_lw_callback, browser->filelist); return true; - -#ifdef HAVE_GETMOUSE - case CMD_MOUSE_EVENT: - browser_handle_mouse_event(browser, c); + case CMD_LIST_JUMP: + screen_jump(browser->lw, + browser_lw_callback, browser->filelist, + screen_browser_paint_callback, browser); return true; -#endif #ifdef ENABLE_SONG_SCREEN - case CMD_VIEW: - entry = browser_get_selected(browser); - if (entry == NULL || entry->entity == NULL || - entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG) + case CMD_SCREEN_SONG: + song = browser_get_selected_song(browser); + if (song == NULL) return false; - screen_song_switch(c, entry->entity->info.song); + screen_song_switch(c, song); return true; #endif - case CMD_LOCATE: - entry = browser_get_selected(browser); - if (entry == NULL || entry->entity == NULL || - entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG) - return false; - - screen_file_goto_song(c, entry->entity->info.song); - return true; - #ifdef ENABLE_LYRICS_SCREEN case CMD_SCREEN_LYRICS: - entry = browser_get_selected(browser); - if (entry == NULL) + song = browser_get_selected_song(browser); + if (song == NULL) return false; - if (entry->entity == NULL || - entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG) - return true; - - screen_lyrics_switch(c, entry->entity->info.song); + screen_lyrics_switch(c, song, false); return true; #endif + case CMD_SCREEN_SWAP: + screen_swap(c, browser_get_selected_song(browser)); + return true; default: break; } - if (list_window_cmd(browser->lw, filelist_length(browser->filelist), - cmd)) + if (!mpdclient_is_connected(c)) + return false; + + switch (cmd) { + const struct mpd_song *song; + + case CMD_PLAY: + browser_handle_enter(browser, c); return true; + case CMD_SELECT: + if (browser_handle_select(browser, c)) + list_window_cmd(browser->lw, CMD_LIST_NEXT); + return true; + + case CMD_ADD: + if (browser_handle_add(browser, c)) + list_window_cmd(browser->lw, CMD_LIST_NEXT); + return true; + + case CMD_SELECT_ALL: + browser_handle_select_all(browser, c); + return true; + + case CMD_LOCATE: + song = browser_get_selected_song(browser); + if (song == NULL) + return false; + + screen_file_goto_song(c, song); + return true; + + default: + break; + } + return false; } + +void +screen_browser_paint_directory(WINDOW *w, unsigned width, + bool selected, const char *name) +{ + row_color(w, COLOR_DIRECTORY, selected); + + waddch(w, '['); + waddstr(w, name); + waddch(w, ']'); + + /* erase the unused space after the text */ + row_clear_to_eol(w, width, selected); +} + +static void +screen_browser_paint_playlist(WINDOW *w, unsigned width, + bool selected, const char *name) +{ + row_paint_text(w, width, COLOR_PLAYLIST, selected, name); +} + +static void +screen_browser_paint_callback(WINDOW *w, unsigned i, + unsigned y, unsigned width, + bool selected, const void *data) +{ + const struct screen_browser *browser = (const struct screen_browser *) data; + + assert(browser != NULL); + assert(browser->filelist != NULL); + assert(i < filelist_length(browser->filelist)); + + const struct filelist_entry *entry = filelist_get(browser->filelist, i); + assert(entry != NULL); + + const struct mpd_entity *entity = entry->entity; + if (entity == NULL) { + screen_browser_paint_directory(w, width, selected, ".."); + return; + } + +#ifndef NCMPC_MINI + const bool highlight = (entry->flags & HIGHLIGHT) != 0; +#else + const bool highlight = false; +#endif + + switch (mpd_entity_get_type(entity)) { + const struct mpd_directory *directory; + const struct mpd_playlist *playlist; + char *p; + + case MPD_ENTITY_TYPE_DIRECTORY: + directory = mpd_entity_get_directory(entity); + p = utf8_to_locale(g_basename(mpd_directory_get_path(directory))); + screen_browser_paint_directory(w, width, selected, p); + g_free(p); + break; + + case MPD_ENTITY_TYPE_SONG: + paint_song_row(w, y, width, selected, highlight, + mpd_entity_get_song(entity), NULL, browser->song_format); + break; + + case MPD_ENTITY_TYPE_PLAYLIST: + playlist = mpd_entity_get_playlist(entity); + p = utf8_to_locale(g_basename(mpd_playlist_get_path(playlist))); + screen_browser_paint_playlist(w, width, selected, p); + g_free(p); + break; + + default: + row_paint_text(w, width, highlight ? COLOR_LIST_BOLD : COLOR_LIST, + selected, ""); + } +} + +void +screen_browser_paint(const struct screen_browser *browser) +{ + list_window_paint2(browser->lw, screen_browser_paint_callback, + browser); +}