Code

Addded support for the mpd update command (CMD_DB_UPDATE)
[ncmpc.git] / src / screen_play.c
1 /* 
2  * (c) 2004 by Kalle Wallin (kaw@linux.se)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  */
19 #include <stdlib.h>
20 #include <string.h>
21 #include <glib.h>
22 #include <ncurses.h>
24 #include "config.h"
25 #include "options.h"
26 #include "support.h"
27 #include "libmpdclient.h"
28 #include "mpc.h"
29 #include "command.h"
30 #include "screen.h"
31 #include "screen_utils.h"
32 #include "screen_file.h"
33 #include "screen_play.h"
35 #ifdef DEBUG
36 #define D(x) x
37 #else
38 #define D(x)
39 #endif
41 #define BUFSIZE 256
43 static list_window_t *lw = NULL;
45 static char *
46 list_callback(int index, int *highlight, void *data)
47 {
48   mpd_client_t *c = (mpd_client_t *) data;
49   mpd_Song *song;
51   *highlight = 0;
52   if( (song=mpc_playlist_get_song(c, index)) == NULL )
53     {
54       return NULL;
55     }
57   if( index==c->song_id && !IS_STOPPED(c->status->state) )
58     {
59       *highlight = 1;
60     }
62   return mpc_get_song_name(song);
63 }
65 static int
66 center_playing_item(screen_t *screen, mpd_client_t *c)
67 {
68   int length = c->playlist_length;
69   int offset = lw->selected-lw->start;
70   
71   if( !lw || length<lw->rows || IS_STOPPED(c->status->state) )
72     return 0;
74   /* try to center the song that are playing */
75   lw->start = c->song_id-(lw->rows/2);
76   if( lw->start+lw->rows > length )
77     lw->start = length-lw->rows;
78   if( lw->start<0 )
79     lw->start=0;
81   /* make sure the cursor is in the window */
82   lw->selected = lw->start+offset;
83   list_window_check_selected(lw, length);
85   lw->clear = 1;
86   lw->repaint = 1;
88   return 0;
89 }
91 static int
92 handle_save_playlist(screen_t *screen, mpd_client_t *c)
93 {
94   char *filename, *filename_utf8;
96   filename=screen_getstr(screen->status_window.w, "Save playlist as: ");
97   filename=trim(filename);
98   if( filename==NULL || filename[0]=='\0' )
99     return -1;
100   /* convert filename to utf-8 */
101   filename_utf8 = locale_to_utf8(filename);
102   /* send save command to mpd */
103   mpd_sendSaveCommand(c->connection, filename_utf8);
104   mpd_finishCommand(c->connection);
105   g_free(filename_utf8);
106   /* handle errors */
107   if( mpc_error(c))
108     {
109       if(  mpc_error_str(c) )
110         {
111           char *str = utf8_to_locale(mpc_error_str(c));
112           screen_status_message(str);
113           g_free(str);
114         }
115       else
116         screen_status_printf("Error: Unable to save playlist as %s", filename);
117       mpd_clearError(c->connection);
118       beep();
119       return -1;
120     }
121   /* success */
122   screen_status_printf("Saved %s", filename);
123   g_free(filename);
124   /* update the file list if it has been initalized */
125   if( c->filelist )
126     {
127       list_window_t *file_lw = get_filelist_window();
129       mpc_update_filelist(c);
130       list_window_check_selected(file_lw, c->filelist_length);
131     }
132   return 0;
135 static void
136 play_init(WINDOW *w, int cols, int rows)
138   lw = list_window_init(w, cols, rows);
141 static void
142 play_resize(int cols, int rows)
144   lw->cols = cols;
145   lw->rows = rows;
149 static void
150 play_exit(void)
152   list_window_free(lw);
155 static char *
156 play_title(void)
158   return (TOP_HEADER_PREFIX "Playlist");
161 static void
162 play_paint(screen_t *screen, mpd_client_t *c)
163
164   lw->clear = 1;
166   list_window_paint(lw, list_callback, (void *) c);
167   wnoutrefresh(lw->w);
170 static void
171 play_update(screen_t *screen, mpd_client_t *c)
173   if( options.auto_center )
174     {
175       static int prev_song_id = 0;
176       
177       if( prev_song_id != c->song_id )  
178         {
179           center_playing_item(screen, c);
180           prev_song_id = c->song_id;
181         }
182     }
184   if( c->playlist_updated )
185     {
186       if( lw->selected >= c->playlist_length )
187         lw->selected = c->playlist_length-1;
188       if( lw->start    >= c->playlist_length )
189         list_window_reset(lw);
191       play_paint(screen, c);
192       c->playlist_updated = 0;
193     }
194   else if( lw->repaint || 1)
195     {
196       list_window_paint(lw, list_callback, (void *) c);
197       wnoutrefresh(lw->w);
198       lw->repaint = 0;
199     }
202 static int
203 play_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
205   switch(cmd)
206     {
207     case CMD_DELETE:
208       playlist_delete_song(c, lw->selected);
209       return 1;
210     case CMD_SAVE_PLAYLIST:
211       handle_save_playlist(screen, c);
212       return 1;
213     case CMD_SCREEN_UPDATE:
214       center_playing_item(screen, c);
215       return 1;
216     case CMD_LIST_MOVE_UP:
217       playlist_move_song(c, lw->selected, lw->selected-1);
218       break;
219     case CMD_LIST_MOVE_DOWN:
220       playlist_move_song(c, lw->selected, lw->selected+1);
221       break;
222     case CMD_LIST_FIND:
223     case CMD_LIST_RFIND:
224     case CMD_LIST_FIND_NEXT:
225     case CMD_LIST_RFIND_NEXT:
226       return screen_find(screen, c, 
227                          lw, c->playlist_length,
228                          cmd, list_callback);
229     default:
230       break;
231     }
232   return list_window_cmd(lw, c->playlist_length, cmd) ;
237 static list_window_t *
238 play_lw(void)
240   return lw;
243 int 
244 play_get_selected(void)
246   return lw->selected;
249 int
250 playlist_move_song(mpd_client_t *c, int old_index, int new_index)
252   int index1, index2;
253   GList *item1, *item2;
254   gpointer data1, data2;
256   if( old_index==new_index || new_index<0 || new_index>=c->playlist_length )
257     return -1;
259   /* send the move command to mpd */
260   mpd_sendMoveCommand(c->connection, old_index, new_index);
261   mpd_finishCommand(c->connection);
262   if( mpc_error(c) )
263     return -1;
265   index1 = MIN(old_index, new_index);
266   index2 = MAX(old_index, new_index);
267   item1 = g_list_nth(c->playlist, index1);
268   item2 = g_list_nth(c->playlist, index2);
269   data1 = item1->data;
270   data2 = item2->data;
272   /* move the second item */
273   D(fprintf(stderr, "move second item [%d->%d]...\n", index2, index1));
274   c->playlist = g_list_remove(c->playlist, data2);
275   c->playlist = g_list_insert_before(c->playlist, item1, data2);
277   /* move the first item */
278   if( index2-index1 >1 )
279     {
280       D(fprintf(stderr, "move first item [%d->%d]...\n", index1, index2));
281       item2 = g_list_nth(c->playlist, index2);
282       c->playlist = g_list_remove(c->playlist, data1);
283       c->playlist = g_list_insert_before(c->playlist, item2, data1);
284     }
285   
286   /* increment the playlist id, so we dont retrives a new playlist */
287   c->playlist_id++;
289   /* make shure the playlist is repainted */
290   lw->clear = 1;
291   lw->repaint = 1;
293   /* keep song selected */
294   lw->selected = new_index;
296   return 0;
299 int
300 playlist_add_song(mpd_client_t *c, mpd_Song *song)
302   if( !song || !song->file )
303     return -1;
305   /* send the add command to mpd */
306   mpd_sendAddCommand(c->connection, song->file);
307   mpd_finishCommand(c->connection);
308   if( mpc_error(c) )
309     return -1;
311   /* add the song to playlist */
312   c->playlist = g_list_append(c->playlist, (gpointer) mpd_songDup(song));
313   c->playlist_length++;
315   /* increment the playlist id, so we dont retrives a new playlist */
316   c->playlist_id++;
318   /* make shure the playlist is repainted */
319   lw->clear = 1;
320   lw->repaint = 1;
322   /* set selected highlight in the browse screen */
323   file_set_highlight(c, song, 1);
325   return 0;
328 int
329 playlist_delete_song(mpd_client_t *c, int index)
331   mpd_Song *song = mpc_playlist_get_song(c, index);
333   if( !song )
334     return -1;
336   /* send the delete command to mpd */
337   mpd_sendDeleteCommand(c->connection, index);
338   mpd_finishCommand(c->connection); 
339   if( mpc_error(c) )
340     return -1;
342   /* print a status message */
343   screen_status_printf("Removed \'%s\' from playlist!",
344                        mpc_get_song_name(song));
345   /* clear selected highlight in the browse screen */
346   file_set_highlight(c, song, 0);
348   /* increment the playlist id, so we dont retrives a new playlist */
349   c->playlist_id++;
351   /* remove references to the song */
352   if( c->song == song )
353     {
354       c->song = NULL;
355       c->song_id = -1;
356     }
357   
358   /* remove the song from the playlist */
359   c->playlist = g_list_remove(c->playlist, (gpointer) song);
360   c->playlist_length = g_list_length(c->playlist);
361   mpd_freeSong(song);
363   /* make shure the playlist is repainted */
364   lw->clear = 1;
365   lw->repaint = 1;
366   list_window_check_selected(lw, c->playlist_length);
368   return 0;
372 screen_functions_t *
373 get_screen_playlist(void)
375   static screen_functions_t functions;
377   memset(&functions, 0, sizeof(screen_functions_t));
378   functions.init   = play_init;
379   functions.exit   = play_exit;
380   functions.open   = NULL;
381   functions.close  = NULL;
382   functions.resize = play_resize;
383   functions.paint  = play_paint;
384   functions.update = play_update;
385   functions.cmd    = play_cmd;
386   functions.get_lw = play_lw;
387   functions.get_title = play_title;
389   return &functions;