X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fscreen_browser.c;h=6c802f6e87aaa2a0654a0ce7b42c2d88d4598cdb;hb=d0d23a29f2f710e39ae14be009656f7fc2c30560;hp=6f29bd70ae04567b776d8f23834c54faf2308c07;hpb=129559ceb21d87bf474580fea3a3d1afa49c208b;p=ncmpc.git diff --git a/src/screen_browser.c b/src/screen_browser.c index 6f29bd7..6c802f6 100644 --- a/src/screen_browser.c +++ b/src/screen_browser.c @@ -1,28 +1,41 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2009 The Music Player Daemon Project + * (c) 2004-2010 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 "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 @@ -32,54 +45,25 @@ #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) { 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_same_song(c, song) >= 0) + if (playlist_get_index_from_same_song(playlist, + song) >= 0) entry->flags |= HIGHLIGHT; else entry->flags &= ~HIGHLIGHT; @@ -87,76 +71,46 @@ sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl) } } -/* the playlist has 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, G_GNUC_UNUSED char **second_column, 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; + const struct filelist_entry *entry; + const struct mpd_entity *entity; - if (idx >= filelist_length(fl)) - return NULL; + assert(fl != NULL); + assert(idx < filelist_length(fl)); entry = filelist_get(fl, idx); assert(entry != NULL); entity = entry->entity; -#ifndef NCMPC_MINI - *highlight = (entry->flags & HIGHLIGHT) != 0; -#else - *highlight = false; -#endif if( entity == NULL ) - return "[..]"; - - if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) { - mpd_Directory *dir = entity->info.directory; - char *directory = utf8_to_locale(g_basename(dir->path)); + return ".."; - 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; } @@ -165,75 +119,101 @@ browser_lw_callback(unsigned idx, bool *highlight, G_GNUC_UNUSED char **second_c } static bool -load_playlist(mpdclient_t *c, const mpd_PlaylistFile *plf) +load_playlist(struct mpdclient *c, const struct mpd_playlist *playlist) { - char *filename = utf8_to_locale(plf->path); + struct mpd_connection *connection = mpdclient_get_connection(c); - if (mpdclient_cmd_load_playlist(c, plf->path) == 0) + if (connection == NULL) + return false; + + 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); + g_free(filename); + + c->events |= MPD_IDLE_QUEUE; + } else + mpdclient_handle_error(c); + return true; } static bool -enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry) +enqueue_and_play(struct mpdclient *c, struct filelist_entry *entry) { - int idx; - mpd_InfoEntity *entity = entry->entity; - mpd_Song *song = entity->info.song; + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return false; -#ifndef NCMPC_MINI - if (!(entry->flags & HIGHLIGHT)) { -#endif - if (mpdclient_cmd_add(c, song) == 0) { - char buf[BUFSIZE]; + const struct mpd_song *song = mpd_entity_get_song(entry->entity); + int id; #ifndef NCMPC_MINI - entry->flags |= HIGHLIGHT; + if (!(entry->flags & HIGHLIGHT)) + id = -1; + else #endif - strfsong(buf, BUFSIZE, options.list_format, song); - screen_status_printf(_("Adding \'%s\' to playlist"), buf); - mpdclient_update(c); /* get song id */ - } else + 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; + } + #ifndef NCMPC_MINI - } + entry->flags |= HIGHLIGHT; #endif + strfsong(buf, BUFSIZE, options.list_format, song); + screen_status_printf(_("Adding \'%s\' to queue"), buf); + } + + if (!mpd_run_play_id(connection, id)) { + mpdclient_handle_error(c); + return false; + } - idx = playlist_get_index_from_same_song(c, song); - mpdclient_cmd_play(c, idx); return true; } struct filelist_entry * browser_get_selected_entry(const struct screen_browser *browser) { + struct list_window_range range; + + list_window_get_range(browser->lw, &range); + if (browser->filelist == NULL || - browser->lw->selected_start < browser->lw->selected_end || - browser->lw->selected >= filelist_length(browser->filelist)) + range.end <= range.start || + range.end > range.start + 1 || + range.start >= filelist_length(browser->filelist)) return NULL; - return filelist_get(browser->filelist, browser->lw->selected); + return filelist_get(browser->filelist, range.start); } -static struct mpd_InfoEntity * +static const struct mpd_entity * browser_get_selected_entity(const struct screen_browser *browser) { - struct filelist_entry *entry = browser_get_selected_entry(browser); + const struct filelist_entry *entry = browser_get_selected_entry(browser); return entry != NULL ? entry->entity : NULL; } -static struct mpd_song * +static const struct mpd_song * browser_get_selected_song(const struct screen_browser *browser) { - struct mpd_InfoEntity *entity = browser_get_selected_entity(browser); + const struct mpd_entity *entity = browser_get_selected_entity(browser); - return entity != NULL && entity->type == MPD_INFO_ENTITY_TYPE_SONG - ? entity->info.song + return entity != NULL && + mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG + ? mpd_entity_get_song(entity) : NULL; } @@ -248,10 +228,10 @@ browser_get_index(const struct screen_browser *browser, unsigned 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_entry(browser); - mpd_InfoEntity *entity; + struct mpd_entity *entity; if (entry == NULL) return false; @@ -260,66 +240,68 @@ browser_handle_enter(struct screen_browser *browser, mpdclient_t *c) if (entity == NULL) return false; - if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) - return load_playlist(c, entity->info.playlistFile); - 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; } 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->entity->info.playlistFile); + 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; + 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, dir->path) == 0) { - char *tmp = utf8_to_locale(dir->path); + 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"), tmp); + screen_status_printf(_("Adding \'%s\' to queue"), tmp); g_free(tmp); } 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"), 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_same_song(c, song)) >= 0) + while ((idx = playlist_get_index_from_same_song(&c->playlist, + song)) >= 0) mpdclient_cmd_delete(c, idx); #endif } @@ -328,55 +310,44 @@ 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 list_window_range range; struct filelist_entry *entry; + bool success = false; - if (browser->lw->range_selection) { - for (unsigned i = browser->lw->selected_start; - i <= browser->lw->selected_end; i++) { - entry = browser_get_index(browser, i); - - if (entry != NULL && entry->entity != NULL) - browser_select_entry(c, entry, TRUE); - } - return false; - } else { - entry = browser_get_selected_entry(browser); - - if (entry == NULL || entry->entity == NULL) - return false; + list_window_get_range(browser->lw, &range); + for (unsigned i = range.start; i < range.end; ++i) { + entry = browser_get_index(browser, i); - return browser_select_entry(c, entry, TRUE); + if (entry != NULL && entry->entity != NULL) + success = 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 list_window_range range; struct filelist_entry *entry; + bool success = false; - if (browser->lw->range_selection) { - for (unsigned i = browser->lw->selected_start; - i <= browser->lw->selected_end; i++) { - entry = browser_get_index(browser, i); + list_window_get_range(browser->lw, &range); + for (unsigned i = range.start; i < range.end; ++i) { + entry = browser_get_index(browser, i); - if (entry != NULL && entry->entity != NULL) - browser_select_entry(c, entry, FALSE); - } - return false; - } else { - entry = browser_get_selected_entry(browser); - - if (entry == NULL || entry->entity == NULL) - return false; - - return browser_select_entry(c, entry, FALSE); + if (entry != NULL && entry->entity != NULL) + success = browser_select_entry(c, entry, FALSE) || + success; } + + 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; @@ -393,24 +364,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) +browser_handle_mouse_event(struct screen_browser *browser, struct mpdclient *c) { 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)) + list_window_mouse(browser->lw, bstate, row)) return 1; - 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) @@ -424,47 +388,33 @@ browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c) } #endif +static void +screen_browser_paint_callback(WINDOW *w, unsigned i, unsigned y, + unsigned width, bool selected, void *data); + bool browser_cmd(struct screen_browser *browser, struct mpdclient *c, command_t cmd) { - struct mpd_song *song; - - switch (cmd) { - case CMD_PLAY: - browser_handle_enter(browser, c); - 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; + const struct mpd_song *song; - /* call list_window_cmd to go to the next item */ - break; + if (browser->filelist == NULL) + return false; - case CMD_SELECT_ALL: - browser_handle_select_all(browser, c); + if (list_window_cmd(browser->lw, cmd)) return true; + switch (cmd) { 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; case CMD_LIST_JUMP: - screen_jump(browser->lw, browser_lw_callback, browser->filelist); + screen_jump(browser->lw, browser_lw_callback, + screen_browser_paint_callback, browser->filelist); return true; #ifdef HAVE_GETMOUSE @@ -483,14 +433,6 @@ browser_cmd(struct screen_browser *browser, return true; #endif - case CMD_LOCATE: - song = browser_get_selected_song(browser); - if (song == NULL) - return false; - - screen_file_goto_song(c, song); - return true; - #ifdef ENABLE_LYRICS_SCREEN case CMD_SCREEN_LYRICS: song = browser_get_selected_song(browser); @@ -508,9 +450,124 @@ browser_cmd(struct screen_browser *browser, break; } - if (list_window_cmd(browser->lw, filelist_length(browser->filelist), - cmd)) + if (!mpdclient_is_connected(c)) + return false; + + switch (cmd) { + 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, void *data) +{ + const struct filelist *fl = (const struct filelist *) data; + const struct filelist_entry *entry; + const struct mpd_entity *entity; + bool highlight; + const struct mpd_directory *directory; + const struct mpd_playlist *playlist; + char *p; + + assert(fl != NULL); + assert(i < filelist_length(fl)); + + entry = filelist_get(fl, i); + assert(entry != NULL); + + entity = entry->entity; + if (entity == NULL) { + screen_browser_paint_directory(w, width, selected, ".."); + return; + } + +#ifndef NCMPC_MINI + highlight = (entry->flags & HIGHLIGHT) != 0; +#else + highlight = false; +#endif + + switch (mpd_entity_get_type(entity)) { + 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); + 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->filelist); +}