From 38880bd748572c2f3b05c6625ab1029ece2483c4 Mon Sep 17 00:00:00 2001 From: Kalle Wallin Date: Mon, 6 Jun 2005 16:59:49 +0000 Subject: [PATCH] Added an experimental artist (browser) screen git-svn-id: https://svn.musicpd.org/ncmpc/trunk@3322 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- configure.ac | 12 ++ src/Makefile.am | 3 +- src/command.c | 8 +- src/command.h | 1 + src/mpdclient.c | 65 +++++++- src/mpdclient.h | 7 + src/ncmpc.h | 3 + src/screen.c | 15 ++ src/screen_artist.c | 389 ++++++++++++++++++++++++++++++++++++++++++++ src/screen_search.c | 2 +- 10 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 src/screen_artist.c diff --git a/configure.ac b/configure.ac index a9929f2..cdcab65 100644 --- a/configure.ac +++ b/configure.ac @@ -171,6 +171,18 @@ if test "x$artist_screen" != "xyes" ; then AC_DEFINE(DISABLE_ARTIST_SCREEN, 1, [Disable artist screen]) fi +dnl artist screen +AC_MSG_CHECKING([whether to include the artist screen]) +AC_ARG_ENABLE([artist-screen], + AC_HELP_STRING([--enable-artist-screen], + [Enable artist screen (EXPERIMENTAL) @<:@default=no@:>@]), + [artist_screen="$enableval"], + [artist_screen=no]) +AC_MSG_RESULT([$artist_screen]) +if test "x$artist_screen" != "xyes" ; then + AC_DEFINE(DISABLE_ARTIST_SCREEN, 1, [Disable artist screen]) +fi + dnl search screen AC_MSG_CHECKING([whether to include the search screen]) AC_ARG_ENABLE([search-screen], diff --git a/src/Makefile.am b/src/Makefile.am index 796ac8d..f686537 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,8 @@ ncmpc_headers = libmpdclient.h mpdclient.h options.h conf.h command.h \ ncmpc_SOURCES = libmpdclient.c main.c mpdclient.c options.c conf.c command.c \ screen.c screen_utils.c screen_play.c screen_file.c \ - screen_search.c screen_help.c screen_keydef.c screen_clock.c \ + screen_artist.c screen_search.c screen_help.c \ + screen_keydef.c screen_clock.c \ list_window.c colors.c support.c wreadln.c strfsong.c utils.c \ $(ncmpc_headers) diff --git a/src/command.c b/src/command.c index 5b235e6..f94481c 100644 --- a/src/command.c +++ b/src/command.c @@ -172,15 +172,19 @@ static command_definition_t cmds[] = /* extra screens */ +#ifdef ENABLE_ARTIST_SCREEN + { {'4', F4, 0 }, 0, CMD_SCREEN_ARTIST, "screen-artist", + N_("Artist screen") }, +#endif #ifdef ENABLE_SEARCH_SCREEN - { {'4', F4, 0 }, 0, CMD_SCREEN_SEARCH, "screen-search", + { {'5', F5, 0 }, 0, CMD_SCREEN_SEARCH, "screen-search", N_("Search screen") }, { {'m', 0, 0 }, 0, CMD_SEARCH_MODE, "search-mode", N_("Change search mode") }, #endif #ifdef ENABLE_CLOCK_SCREEN - { {'5', F5, 0 }, 0, CMD_SCREEN_CLOCK, "screen-clock", + { {'6', F6, 0 }, 0, CMD_SCREEN_CLOCK, "screen-clock", N_("Clock screen") }, #endif diff --git a/src/command.h b/src/command.h index 29e6a06..9a80302 100644 --- a/src/command.h +++ b/src/command.h @@ -47,6 +47,7 @@ typedef enum CMD_SCREEN_NEXT, CMD_SCREEN_PLAY, CMD_SCREEN_FILE, + CMD_SCREEN_ARTIST, CMD_SCREEN_SEARCH, CMD_SCREEN_KEYDEF, CMD_SCREEN_CLOCK, diff --git a/src/mpdclient.c b/src/mpdclient.c index 7cec3c9..03c69f3 100644 --- a/src/mpdclient.c +++ b/src/mpdclient.c @@ -39,6 +39,8 @@ #define MPD_ERROR(c) (c==NULL || c->connection==NULL || c->connection->error) +/* from utils.c */ +extern GList *string_list_free(GList *string_list); /* Error callbacks */ static gint @@ -883,13 +885,12 @@ mpdclient_filelist_get(mpdclient_t *c, gchar *path) } mpdclient_filelist_t * -mpdclient_filelist_search(mpdclient_t *c, int table, gchar *filter) +mpdclient_filelist_search_utf8(mpdclient_t *c, int table, gchar *filter_utf8) { mpdclient_filelist_t *filelist; mpd_InfoEntity *entity; - gchar *filter_utf8 = locale_to_utf8(filter); - D("mpdclient_filelist_filter(%s)\n", filter); + D("mpdclient_filelist_search(%s)\n", filter_utf8); mpd_sendSearchCommand(c->connection, table, filter_utf8); filelist = g_malloc0(sizeof(mpdclient_filelist_t)); @@ -903,17 +904,27 @@ mpdclient_filelist_search(mpdclient_t *c, int table, gchar *filter) } if( mpdclient_finish_command(c) ) - { - g_free(filter_utf8); - return mpdclient_filelist_free(filelist); - } - - g_free(filter_utf8); + return mpdclient_filelist_free(filelist); + filelist->updated = TRUE; return filelist; } + +mpdclient_filelist_t * +mpdclient_filelist_search(mpdclient_t *c, int table, gchar *filter) +{ + mpdclient_filelist_t *filelist; + gchar *filter_utf8 = locale_to_utf8(filter); + + D("mpdclient_filelist_search(%s)\n", filter); + filelist = mpdclient_filelist_search_utf8(c, table, filter_utf8); + g_free(filter_utf8); + + return filelist; +} + mpdclient_filelist_t * mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *filelist) { @@ -954,9 +965,45 @@ mpdclient_filelist_find_song(mpdclient_filelist_t *fl, mpd_Song *song) } +GList * +mpdclient_get_artists_utf8(mpdclient_t *c) +{ + gchar *str = NULL; + GList *list = NULL; + + D("mpdclient_get_artists()\n"); + mpd_sendListCommand(c->connection, MPD_TABLE_ARTIST, NULL); + while( (str=mpd_getNextArtist(c->connection)) ) + { + list = g_list_append(list, (gpointer) str); + } + if( mpdclient_finish_command(c) ) + { + return string_list_free(list); + } + return list; +} +GList * +mpdclient_get_albums_utf8(mpdclient_t *c, gchar *artist_utf8) +{ + gchar *str = NULL; + GList *list = NULL; + D("mpdclient_get_albums(%s)\n", artist_utf8); + mpd_sendListCommand(c->connection, MPD_TABLE_ALBUM, artist_utf8); + while( (str=mpd_getNextAlbum(c->connection)) ) + { + list = g_list_append(list, (gpointer) str); + } + if( mpdclient_finish_command(c) ) + { + return string_list_free(list); + } + + return list; +} diff --git a/src/mpdclient.h b/src/mpdclient.h index 89a2e63..a14811b 100644 --- a/src/mpdclient.h +++ b/src/mpdclient.h @@ -104,6 +104,10 @@ gint mpdclient_cmd_load_playlist_utf8(mpdclient_t *c, gchar *filename_utf8); gint mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename); gint mpdclient_cmd_delete_playlist_utf8(mpdclient_t *c, gchar *filename_utf8); +/* list functions */ +GList *mpdclient_get_artists_utf8(mpdclient_t *c); +GList *mpdclient_get_albums_utf8(mpdclient_t *c, gchar *artist_utf8); + /*** error callbacks *****************************************************/ @@ -161,6 +165,9 @@ mpdclient_filelist_t *mpdclient_filelist_get(mpdclient_t *c, gchar *path); mpdclient_filelist_t *mpdclient_filelist_search(mpdclient_t *c, int table, gchar *path); +mpdclient_filelist_t *mpdclient_filelist_search_utf8(mpdclient_t *c, + int table, + gchar *path); mpdclient_filelist_t *mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *flist); diff --git a/src/ncmpc.h b/src/ncmpc.h index 0c72a09..194d7ac 100644 --- a/src/ncmpc.h +++ b/src/ncmpc.h @@ -5,6 +5,9 @@ #include "config.h" #endif +#ifndef DISABLE_ARTIST_SCREEN +#define ENABLE_ARTIST_SCREEN 1 +#endif #ifndef DISABLE_SEARCH_SCREEN #define ENABLE_SEARCH_SCREEN 1 #endif diff --git a/src/screen.c b/src/screen.c index 0c56a74..b5a1d47 100644 --- a/src/screen.c +++ b/src/screen.c @@ -44,17 +44,20 @@ #define SCREEN_PLAYLIST_ID 0 #define SCREEN_BROWSE_ID 1 +#define SCREEN_ARTIST_ID 2 #define SCREEN_HELP_ID 100 #define SCREEN_KEYDEF_ID 101 #define SCREEN_CLOCK_ID 102 #define SCREEN_SEARCH_ID 103 + /* screens */ extern screen_functions_t *get_screen_playlist(void); extern screen_functions_t *get_screen_browse(void); extern screen_functions_t *get_screen_help(void); extern screen_functions_t *get_screen_search(void); +extern screen_functions_t *get_screen_artist(void); extern screen_functions_t *get_screen_keydef(void); extern screen_functions_t *get_screen_clock(void); @@ -72,6 +75,9 @@ static screen_mode_info_t screens[] = { { SCREEN_PLAYLIST_ID, "playlist", get_screen_playlist }, { SCREEN_BROWSE_ID, "browse", get_screen_browse }, { SCREEN_HELP_ID, "help", get_screen_help }, +#ifdef ENABLE_ARTIST_SCREEN + { SCREEN_ARTIST_ID, "artist", get_screen_artist }, +#endif #ifdef ENABLE_SEARCH_SCREEN { SCREEN_SEARCH_ID, "search", get_screen_search }, #endif @@ -176,6 +182,12 @@ paint_top_window(char *header, mpdclient_t *c, int clear) waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE)); colors_use(w, COLOR_TITLE); waddstr(w, _(":Browse ")); +#ifdef ENABLE_ARTIST_SCREEN + colors_use(w, COLOR_TITLE_BOLD); + waddstr(w, get_key_names(CMD_SCREEN_ARTIST, FALSE)); + colors_use(w, COLOR_TITLE); + waddstr(w, _(":Artist ")); +#endif #ifdef ENABLE_SEARCH_SCREEN colors_use(w, COLOR_TITLE_BOLD); waddstr(w, get_key_names(CMD_SCREEN_SEARCH, FALSE)); @@ -888,6 +900,9 @@ screen_cmd(mpdclient_t *c, command_t cmd) case CMD_SCREEN_SEARCH: switch_screen_mode(SCREEN_SEARCH_ID, c); break; + case CMD_SCREEN_ARTIST: + switch_screen_mode(SCREEN_ARTIST_ID, c); + break; case CMD_SCREEN_KEYDEF: switch_screen_mode(SCREEN_KEYDEF_ID, c); break; diff --git a/src/screen_artist.c b/src/screen_artist.c new file mode 100644 index 0000000..e09d9f0 --- /dev/null +++ b/src/screen_artist.c @@ -0,0 +1,389 @@ +/* + * $Id$ + * + * (c) 2004 by Kalle Wallin + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include "config.h" +#ifndef DISABLE_ARTIST_SCREEN +#include "ncmpc.h" +#include "options.h" +#include "support.h" +#include "mpdclient.h" +#include "utils.h" +#include "strfsong.h" +#include "command.h" +#include "screen.h" +#include "screen_utils.h" +#include "screen_browse.h" + +#define BUFSIZE 1024 + +static char *artist = NULL; +static char *album = NULL; +static list_window_t *lw = NULL; +static mpdclient_filelist_t *filelist = NULL; +static int metalist_length = 0; +static GList *metalist = NULL; +static GList *lw_state_list = NULL; + +/* store current state when entering a subdirectory */ +static void +push_lw_state(void) +{ + list_window_t *tmp = g_malloc(sizeof(list_window_t)); + + memcpy(tmp, lw, sizeof(list_window_t)); + lw_state_list = g_list_prepend(lw_state_list, (gpointer) tmp); +} + +/* get previous state when leaving a directory */ +static void +pop_lw_state(void) +{ + if( lw_state_list ) + { + list_window_t *tmp = lw_state_list->data; + + memcpy(lw, tmp, sizeof(list_window_t)); + g_free(tmp); + lw_state_list->data = NULL; + lw_state_list = g_list_delete_link(lw_state_list, lw_state_list); + } +} + +/* list_window callback */ +static char * +artist_lw_callback(int index, int *highlight, void *data) +{ + static char buf[BUFSIZE]; + char *str, *str_utf8; + + *highlight = 0; + if( (str_utf8=(char *) g_list_nth_data(metalist,index))==NULL ) + return NULL; + + str = utf8_to_locale(str_utf8); + g_snprintf(buf, BUFSIZE, "[%s]", str); + g_free(str); + + return buf; +} + +/* the playlist have been updated -> fix highlights */ +static void +playlist_changed_callback(mpdclient_t *c, int event, gpointer data) +{ + if( filelist==NULL ) + return; + D("screen_artist.c> playlist_callback() [%d]\n", event); + switch(event) + { + case PLAYLIST_EVENT_CLEAR: + clear_highlights(filelist); + break; + default: + sync_highlights(c, filelist); + break; + } +} + +static void +update_metalist(mpdclient_t *c, char *m_artist, char *m_album) +{ + g_free(artist); + g_free(album); + artist = NULL; + album = NULL; + if( metalist ) + metalist = string_list_free(metalist); + if (filelist ) { + mpdclient_remove_playlist_callback(c, playlist_changed_callback); + filelist = mpdclient_filelist_free(filelist); + } + if( m_album ) /* retreive songs... */ + { + artist = m_artist; + album = m_album; + if( album[0] == 0 ) + { + album = g_strdup(_("All tracks")); + filelist = mpdclient_filelist_search_utf8(c, + MPD_TABLE_ARTIST, + artist); + } + else + filelist = mpdclient_filelist_search_utf8(c, + MPD_TABLE_ALBUM, + album); + /* add a dummy entry for ".." */ + filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t)); + entry->entity = NULL; + filelist->list = g_list_insert(filelist->list, entry, 0); + filelist->length++; + /* install playlist callback and fix highlights */ + sync_highlights(c, filelist); + mpdclient_install_playlist_callback(c, playlist_changed_callback); + } + else if( m_artist ) /* retreive albums... */ + { + artist = m_artist; + metalist = mpdclient_get_albums_utf8(c, m_artist); + /* add a dummy entry for ".." */ + metalist = g_list_insert(metalist, g_strdup(".."), 0); + /* add a dummy entry for all songs */ + metalist = g_list_insert(metalist, g_strdup(_("All tracks")), -1); + + } + else /* retreive artists... */ + { + metalist = mpdclient_get_artists_utf8(c); + } + metalist_length = g_list_length(metalist); +} + +static void +init(WINDOW *w, int cols, int rows) +{ + lw = list_window_init(w, cols, rows); + artist = NULL; + album = NULL; +} + +static void +quit(void) +{ + /* clear list window state */ + if( lw_state_list ) + { + GList *list = lw_state_list; + while( list ) + { + g_free(list->data); + list->data = NULL; + list = list->next; + } + g_list_free(lw_state_list); + lw_state_list = NULL; + } + + if( filelist ) + filelist = mpdclient_filelist_free(filelist); + if( metalist ) + metalist = string_list_free(metalist); + g_free(artist); + g_free(album); + artist = NULL; + album = NULL; + list_window_free(lw); +} + +static void +open(screen_t *screen, mpdclient_t *c) +{ + if( metalist==NULL && filelist ==NULL) + update_metalist(c, NULL, NULL); +} + +static void +resize(int cols, int rows) +{ + lw->cols = cols; + lw->rows = rows; +} + +static void +close(void) +{ +} + +static void +paint(screen_t *screen, mpdclient_t *c) +{ + lw->clear = 1; + + if( filelist ) + { + list_window_paint(lw, browse_lw_callback, (void *) filelist); + filelist->updated = FALSE; + } + else if( metalist ) + { + list_window_paint(lw, artist_lw_callback, (void *) metalist); + } + else + { + wmove(lw->w, 0, 0); + wclrtobot(lw->w); + } + wnoutrefresh(lw->w); +} + +static void +update(screen_t *screen, mpdclient_t *c) +{ + if( filelist==NULL || filelist->updated ) + { + paint(screen, c); + return; + } + list_window_paint(lw, browse_lw_callback, (void *) filelist); + wnoutrefresh(lw->w); +} + +static char * +get_title(char *str, size_t size) +{ + char *s1 = artist ? utf8_to_locale(artist) : NULL; + char *s2 = album ? utf8_to_locale(album) : NULL; + + if( album ) + g_snprintf(str, size, _("Artist: %s - %s"), s1, s2); + else if( artist ) + g_snprintf(str, size, _("Artist: %s"), s1); + else + g_snprintf(str, size, _("Artist: [db browser - EXPERIMENTAL]")); + g_free(s1); + g_free(s2); + return str; +} + +static list_window_t * +get_filelist_window() +{ + return lw; +} + +static int +artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd) +{ + switch(cmd) + { + case CMD_PLAY: + if( artist && album ) + { + if( lw->selected==0 ) /* handle ".." */ + { + update_metalist(c, g_strdup(artist), NULL); + list_window_reset(lw); + /* restore previous list window state */ + pop_lw_state(); + } + else + browse_handle_enter(screen, c, lw, filelist); + } + else if ( artist ) + { + if( lw->selected == 0 ) /* handle ".." */ + + { + update_metalist(c, NULL, NULL); + list_window_reset(lw); + /* restore previous list window state */ + pop_lw_state(); + } + else if( lw->selected == metalist_length-1) /* handle "show all" */ + { + update_metalist(c, g_strdup(artist), g_strdup("\0")); + push_lw_state(); + list_window_reset(lw); + } + else /* select album */ + { + char *selected = (char *) g_list_nth_data(metalist, lw->selected); + update_metalist(c, g_strdup(artist), g_strdup(selected)); + push_lw_state(); + list_window_reset(lw); + } + } + else + { + char *selected = (char *) g_list_nth_data(metalist, lw->selected); + update_metalist(c, g_strdup(selected), NULL); + push_lw_state(); + list_window_reset(lw); + } + return 1; + + case CMD_SELECT: + if( browse_handle_select(screen, c, lw, filelist) == 0 ) + { + /* continue and select next item... */ + cmd = CMD_LIST_NEXT; + } + return 1; + + /* continue and update... */ + case CMD_SCREEN_UPDATE: + return 0; + + case CMD_LIST_FIND: + case CMD_LIST_RFIND: + case CMD_LIST_FIND_NEXT: + case CMD_LIST_RFIND_NEXT: + if( filelist ) + return screen_find(screen, c, + lw, filelist->length, + cmd, browse_lw_callback, (void *) filelist); + else if ( metalist ) + return screen_find(screen, c, + lw, metalist_length, + cmd, artist_lw_callback, (void *) metalist); + else + return 1; + + case CMD_MOUSE_EVENT: + return browse_handle_mouse_event(screen,c,lw,filelist); + + default: + if( filelist ) + return list_window_cmd(lw, filelist->length, cmd); + else if( metalist ) + return list_window_cmd(lw, metalist_length, cmd); + } + + return 0; +} + +screen_functions_t * +get_screen_artist(void) +{ + static screen_functions_t functions; + + memset(&functions, 0, sizeof(screen_functions_t)); + functions.init = init; + functions.exit = quit; + functions.open = open; + functions.close = close; + functions.resize = resize; + functions.paint = paint; + functions.update = update; + functions.cmd = artist_cmd; + functions.get_lw = get_filelist_window; + functions.get_title = get_title; + + return &functions; +} + + +#endif /* ENABLE_ARTIST_SCREEN */ diff --git a/src/screen_search.c b/src/screen_search.c index 71329f0..06677bf 100644 --- a/src/screen_search.c +++ b/src/screen_search.c @@ -194,7 +194,7 @@ paint(screen_t *screen, mpdclient_t *c) wnoutrefresh(lw->w); } -void +static void update(screen_t *screen, mpdclient_t *c) { if( filelist==NULL || filelist->updated ) -- 2.30.2