1 /*
2 * $Id$
3 *
4 * (c) 2004 by Kalle Wallin <kaw@linux.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <ncurses.h>
27 #include "config.h"
28 #include "ncmpc.h"
29 #include "options.h"
30 #include "support.h"
31 #include "mpdclient.h"
32 #include "strfsong.h"
33 #include "command.h"
34 #include "screen.h"
35 #include "screen_utils.h"
37 #define MAX_SONG_LENGTH 512
39 static list_window_t *lw = NULL;
41 static void
42 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
43 {
44 D("screen_play.c> playlist_callback() [%d]\n", event);
45 switch(event)
46 {
47 case PLAYLIST_EVENT_DELETE:
48 break;
49 case PLAYLIST_EVENT_MOVE:
50 lw->selected = *((int *) data);
51 break;
52 default:
53 break;
54 }
55 /* make shure the playlist is repainted */
56 lw->clear = 1;
57 lw->repaint = 1;
58 list_window_check_selected(lw, c->playlist.length);
59 }
61 static char *
62 list_callback(int index, int *highlight, void *data)
63 {
64 static char songname[MAX_SONG_LENGTH];
65 mpdclient_t *c = (mpdclient_t *) data;
66 mpd_Song *song;
68 *highlight = 0;
69 if( (song=playlist_get_song(c, index)) == NULL )
70 {
71 return NULL;
72 }
74 if( c->song && song->id==c->song->id && !IS_STOPPED(c->status->state) )
75 {
76 *highlight = 1;
77 }
78 strfsong(songname, MAX_SONG_LENGTH, LIST_FORMAT, song);
79 return songname;
80 }
82 static int
83 center_playing_item(screen_t *screen, mpdclient_t *c)
84 {
85 int length = c->playlist.length;
86 int offset = lw->selected-lw->start;
87 int index;
89 if( !lw || !c->song || length<lw->rows || IS_STOPPED(c->status->state) )
90 return 0;
92 /* try to center the song that are playing */
93 index = playlist_get_index(c, c->song);
94 D("Autocenter song id:%d pos:%d index:%d\n", c->song->id,c->song->pos,index);
95 lw->start = index-(lw->rows/2);
96 if( lw->start+lw->rows > length )
97 lw->start = length-lw->rows;
98 if( lw->start<0 )
99 lw->start=0;
101 /* make sure the cursor is in the window */
102 lw->selected = lw->start+offset;
103 list_window_check_selected(lw, length);
105 lw->clear = 1;
106 lw->repaint = 1;
108 return 0;
109 }
111 static int
112 handle_save_playlist(screen_t *screen, mpdclient_t *c, char *name)
113 {
114 gchar *filename;
115 gint error;
117 if( name==NULL )
118 {
119 /* query the user for a filename */
120 filename=screen_getstr(screen->status_window.w, _("Save playlist as: "));
121 filename=trim(filename);
122 }
123 else
124 {
125 filename=g_strdup(name);
126 }
127 if( filename==NULL || filename[0]=='\0' )
128 return -1;
129 /* send save command to mpd */
130 D("Saving playlist as \'%s \'...\n", filename);
131 if( (error=mpdclient_cmd_save_playlist(c, filename)) )
132 {
133 gint code = GET_ACK_ERROR_CODE(error);
135 if( code == MPD_ACK_ERROR_EXIST )
136 {
137 char buf[256];
138 int key;
140 snprintf(buf, 256, _("Replace %s [%s/%s] ? "), filename, YES, NO);
141 key = tolower(screen_getch(screen->status_window.w, buf));
142 if( key == YES[0] )
143 {
144 char *filename_utf8 = locale_to_utf8(filename);
146 if( mpdclient_cmd_delete_playlist(c, filename_utf8) )
147 {
148 g_free(filename);
149 g_free(filename_utf8);
150 return -1;
151 }
152 g_free(filename_utf8);
153 error = handle_save_playlist(screen, c, filename);
154 g_free(filename);
155 return error;
156 }
157 screen_status_printf(_("Aborted!"));
158 }
159 g_free(filename);
160 return -1;
161 }
162 /* success */
163 screen_status_printf(_("Saved %s"), filename);
164 g_free(filename);
165 return 0;
166 }
168 static void
169 play_init(WINDOW *w, int cols, int rows)
170 {
171 lw = list_window_init(w, cols, rows);
172 }
174 static void
175 play_open(screen_t *screen, mpdclient_t *c)
176 {
177 static gboolean install_cb = TRUE;
179 if( install_cb )
180 {
181 mpdclient_install_playlist_callback(c, playlist_changed_callback);
182 install_cb = FALSE;
183 }
184 }
186 static void
187 play_resize(int cols, int rows)
188 {
189 lw->cols = cols;
190 lw->rows = rows;
191 }
194 static void
195 play_exit(void)
196 {
197 list_window_free(lw);
198 }
200 static char *
201 play_title(char *str, size_t size)
202 {
203 if( strcmp(options.host, "localhost") == 0 )
204 return _("Playlist");
206 snprintf(str, size, _("Playlist on %s"), options.host);
208 return str;
209 }
211 static void
212 play_paint(screen_t *screen, mpdclient_t *c)
213 {
214 lw->clear = 1;
216 list_window_paint(lw, list_callback, (void *) c);
217 wnoutrefresh(lw->w);
218 }
220 static void
221 play_update(screen_t *screen, mpdclient_t *c)
222 {
223 if( options.auto_center )
224 {
225 static int prev_song_id = 0;
227 if( c->song && prev_song_id != c->song->id )
228 {
229 center_playing_item(screen, c);
230 prev_song_id = c->song->id;
231 }
232 }
234 if( c->playlist.updated )
235 {
236 if( lw->selected >= c->playlist.length )
237 lw->selected = c->playlist.length-1;
238 if( lw->start >= c->playlist.length )
239 list_window_reset(lw);
241 play_paint(screen, c);
242 c->playlist.updated = FALSE;
243 }
244 else if( lw->repaint || 1)
245 {
246 list_window_paint(lw, list_callback, (void *) c);
247 wnoutrefresh(lw->w);
248 lw->repaint = 0;
249 }
250 }
252 static int
253 play_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
254 {
255 switch(cmd)
256 {
257 case CMD_PLAY:
258 mpdclient_cmd_play(c, lw->selected);
259 return 1;
260 case CMD_DELETE:
261 mpdclient_cmd_delete(c, lw->selected);
262 return 1;
263 case CMD_SAVE_PLAYLIST:
264 handle_save_playlist(screen, c, NULL);
265 return 1;
266 case CMD_SCREEN_UPDATE:
267 center_playing_item(screen, c);
268 return 1;
269 case CMD_LIST_MOVE_UP:
270 mpdclient_cmd_move(c, lw->selected, lw->selected-1);
271 return 1;
272 case CMD_LIST_MOVE_DOWN:
273 mpdclient_cmd_move(c, lw->selected, lw->selected+1);
274 return 1;
275 case CMD_LIST_FIND:
276 case CMD_LIST_RFIND:
277 case CMD_LIST_FIND_NEXT:
278 case CMD_LIST_RFIND_NEXT:
279 return screen_find(screen, c,
280 lw, c->playlist.length,
281 cmd, list_callback);
282 default:
283 break;
284 }
285 return list_window_cmd(lw, c->playlist.length, cmd) ;
286 }
290 static list_window_t *
291 play_lw(void)
292 {
293 return lw;
294 }
297 screen_functions_t *
298 get_screen_playlist(void)
299 {
300 static screen_functions_t functions;
302 memset(&functions, 0, sizeof(screen_functions_t));
303 functions.init = play_init;
304 functions.exit = play_exit;
305 functions.open = play_open;
306 functions.close = NULL;
307 functions.resize = play_resize;
308 functions.paint = play_paint;
309 functions.update = play_update;
310 functions.cmd = play_cmd;
311 functions.get_lw = play_lw;
312 functions.get_title = play_title;
314 return &functions;
315 }