Code

Added iconv support
[ncmpc.git] / screen.c
1 /* 
2  * $Id: screen.c,v 1.10 2004/03/17 14:50:12 kalle Exp $ 
3  *
4  */
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <time.h>
10 #include <glib.h>
11 #include <ncurses.h>
13 #include "libmpdclient.h"
14 #include "mpc.h"
15 #include "command.h"
16 #include "screen.h"
17 #include "screen_play.h"
18 #include "screen_file.h"
19 #include "screen_help.h"
20 #include "screen_search.h"
22 #define STATUS_MESSAGE_TIMEOUT 3
24 static screen_t *screen = NULL;
26 static void
27 switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
28 {
29   if( new_mode == screen->mode )
30     return;
32  switch(screen->mode)
33     {
34     case SCREEN_PLAY_WINDOW:
35       play_close(screen, c);
36       break;
37     case SCREEN_FILE_WINDOW:
38       file_close(screen, c);
39       break;
40     case SCREEN_SEARCH_WINDOW:
41       search_close(screen, c);
42       break;
43     case SCREEN_HELP_WINDOW:
44       help_close(screen, c);
45       break;
46     }
48  screen->mode = new_mode;
49  screen->painted = 0;
51  switch(screen->mode)
52     {
53     case SCREEN_PLAY_WINDOW:
54       play_open(screen, c);
55       break;
56     case SCREEN_FILE_WINDOW:
57       file_open(screen, c);
58       break;
59     case SCREEN_SEARCH_WINDOW:
60       search_open(screen, c);
61       break;
62     case SCREEN_HELP_WINDOW:
63       help_open(screen, c);
64       break;
65     }
66 }
68 static void
69 paint_top_window(char *header, int volume, int clear)
70 {
71   static int prev_volume = -1;
72   WINDOW *w = screen->top_window.w;
74   if(clear)
75     {
76       wclear(w);
77     }
79   if(prev_volume!=volume || clear)
80     {
81       char buf[12];
83       wattron(w, A_BOLD);
84       mvwaddstr(w, 0, 0, header );
85       wattroff(w, A_BOLD);
86       if( volume==MPD_STATUS_NO_VOLUME )
87         {
88           snprintf(buf, 12, "Volume n/a ");
89         }
90       else
91         {
92           snprintf(buf, 12, "Volume %3d%%", volume); 
93         }
94       mvwaddstr(w, 0, screen->top_window.cols-12, buf);
96       mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
98       wrefresh(w);
99     }
102 static void
103 paint_progress_window(mpd_client_t *c)
105   double p;
106   int width;
108   if( c->status==NULL || !IS_PLAYING(c->status->state) )
109     {
110       mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, 
111                screen->progress_window.cols);
112       wrefresh(screen->progress_window.w);
113       return;
114     }
116   p = ((double) c->status->elapsedTime) / ((double) c->status->totalTime);
117   
118   width = (int) (p * (double) screen->progress_window.cols);
119   
120   mvwhline(screen->progress_window.w, 
121            0, 0,
122            ACS_HLINE, 
123            screen->progress_window.cols);
124   
125   whline(screen->progress_window.w, '=', width-1);
126   
127   mvwaddch(screen->progress_window.w, 0, width-1, 'O');
128   wrefresh(screen->progress_window.w);
131 static void 
132 paint_status_window(mpd_client_t *c)
134   WINDOW *w = screen->status_window.w;
135   mpd_Status *status = c->status;
136   mpd_Song *song   = c->song;
137   int x = 0;
139   if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
140     return;
141   
142   wmove(w, 0, 0);
143   wclrtoeol(w);
144   
145   switch(status->state)
146     {
147     case MPD_STATUS_STATE_STOP:
148       wattron(w, A_BOLD);
149       waddstr(w, "Stopped! ");
150       wattroff(w, A_BOLD);
151       break;
152     case MPD_STATUS_STATE_PLAY:
153       waddstr(w, "Playing:");
154       break;
155     case MPD_STATUS_STATE_PAUSE:
156       wattron(w, A_BOLD);
157       waddstr(w, "Paused:");
158       wattroff(w, A_BOLD);
159       break;
160     default:
161       waddstr(w, "Warning: Music Player Daemon in unknown state!");
162       break;
163     }
164   x += 10;
166   if( IS_PLAYING(status->state) &&  song )
167     {
168       mvwaddstr(w, 0, x, mpc_get_song_name(song));
169     }
170   
172   /* time */
173   if( IS_PLAYING(status->state) )
174     {
175       x = screen->status_window.cols - strlen(screen->buf);
177       if( c->status->repeat )
178         mvwaddstr(w, 0, x-3, "<R>");
179       else
180         mvwaddstr(w, 0, x-3, "   ");
182       snprintf(screen->buf, screen->buf_size, 
183                " [%i:%02i/%i:%02i] ",
184                status->elapsedTime/60, status->elapsedTime%60,
185                status->totalTime/60,   status->totalTime%60 );
186       mvwaddstr(w, 0, x, screen->buf);
187         
188     }
189   
191   wrefresh(w);
196 int
197 screen_exit(void)
199   endwin();
200   if( screen )
201     {
202       screen->playlist = list_window_free(screen->playlist);
203       screen->filelist = list_window_free(screen->filelist);
204       screen->helplist = list_window_free(screen->helplist);
205       free(screen->buf);
206       free(screen);
207       screen = NULL;
208     }
209   return 0;
212 void
213 screen_resized(int sig)
215   screen_exit();
216   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
217     {
218       fprintf(stderr, "Error: Screen to small!\n");
219       exit(EXIT_FAILURE);
220     }
221   screen_init();
224 void 
225 screen_status_message(mpd_client_t *c, char *msg)
227   WINDOW *w = screen->status_window.w;
229   wmove(w, 0, 0);
230   wclrtoeol(w);
231   wattron(w, A_BOLD);
232   waddstr(w, msg);
233   wattroff(w, A_BOLD);
234   wrefresh(w);
235   screen->status_timestamp = time(NULL);
238 int
239 screen_init(void)
241   /* initialize the curses library */
242   initscr();      
243   start_color();
244   use_default_colors();
245   /* tell curses not to do NL->CR/NL on output */
246   nonl();          
247   /* take input chars one at a time, no wait for \n */  
248   cbreak();       
249   /* don't echo input */
250   noecho();    
251   /* set cursor invisible */     
252   curs_set(0);     
253   /* return from getch() without blocking */
254   //  nodelay(stdscr, TRUE); 
255   keypad(stdscr, TRUE);  
256   timeout(100); /*void wtimeout(WINDOW *win, int delay);*/
259   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
260     {
261       fprintf(stderr, "Error: Screen to small!\n");
262       exit(EXIT_FAILURE);
263     }
265   screen = malloc(sizeof(screen_t));
266   memset(screen, 0, sizeof(screen_t));
267   screen->mode = SCREEN_PLAY_WINDOW;
268   screen->cols = COLS;
269   screen->rows = LINES;
270   screen->buf  = malloc(screen->cols);
271   screen->buf_size = screen->cols;
272   screen->painted = 0;
274   /* create top window */
275   screen->top_window.rows = 2;
276   screen->top_window.cols = screen->cols;
277   screen->top_window.w = newwin(screen->top_window.rows, 
278                                   screen->top_window.cols,
279                                   0, 0);
280   leaveok(screen->top_window.w, TRUE);
281   keypad(screen->top_window.w, TRUE);  
283   /* create main window */
284   screen->main_window.rows = screen->rows-4;
285   screen->main_window.cols = screen->cols;
286   screen->main_window.w = newwin(screen->main_window.rows, 
287                                  screen->main_window.cols,
288                                  2, 
289                                  0);
290   screen->playlist = list_window_init( screen->main_window.w,
291                                        screen->main_window.cols,
292                                        screen->main_window.rows );
293   screen->filelist = list_window_init( screen->main_window.w,
294                                        screen->main_window.cols,
295                                        screen->main_window.rows );
296   screen->helplist = list_window_init( screen->main_window.w,
297                                        screen->main_window.cols,
298                                        screen->main_window.rows );
299   leaveok(screen->main_window.w, TRUE);
300   keypad(screen->main_window.w, TRUE);  
302   /* create progress window */
303   screen->progress_window.rows = 1;
304   screen->progress_window.cols = screen->cols;
305   screen->progress_window.w = newwin(screen->progress_window.rows, 
306                                      screen->progress_window.cols,
307                                      screen->rows-2, 
308                                      0);
309   leaveok(screen->progress_window.w, TRUE);
310   
311   /* create status window */
312   screen->status_window.rows = 1;
313   screen->status_window.cols = screen->cols;
314   screen->status_window.w = newwin(screen->status_window.rows, 
315                                    screen->status_window.cols,
316                                    screen->rows-1, 
317                                    0);
318   leaveok(screen->status_window.w, FALSE);
319   keypad(screen->status_window.w, TRUE);  
321   return 0;
324 void 
325 screen_paint(mpd_client_t *c)
327   switch(screen->mode)
328     {
329     case SCREEN_PLAY_WINDOW:
330       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
331       play_paint(screen, c);      
332       break;
333     case SCREEN_FILE_WINDOW:
334       paint_top_window(file_get_header(c), c->status->volume, 1);
335       file_paint(screen, c);      
336       break;
337     case SCREEN_SEARCH_WINDOW:
338       paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 1);
339       search_paint(screen, c);      
340       break;
341     case SCREEN_HELP_WINDOW:
342       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
343       help_paint(screen, c);      
344       break;
345     }
347   paint_progress_window(c);
348   paint_status_window(c);
349   screen->painted = 1;
352 void 
353 screen_update(mpd_client_t *c)
355   if( !screen->painted )
356     return screen_paint(c);
358   switch(screen->mode)
359     {
360     case SCREEN_PLAY_WINDOW:
361       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 0);
362       play_update(screen, c);
363       break;
364     case SCREEN_FILE_WINDOW:
365       paint_top_window(file_get_header(c), c->status->volume, 0);
366       file_update(screen, c);
367       break;
368     case SCREEN_SEARCH_WINDOW:
369       paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 0);
370       search_update(screen, c);
371       break;
372     case SCREEN_HELP_WINDOW:
373       paint_top_window(TOP_HEADER_HELP, c->status->volume, 0);
374       help_update(screen, c);
375       break;
376     }
377   paint_progress_window(c);
378   paint_status_window(c);
381 void 
382 screen_cmd(mpd_client_t *c, command_t cmd)
384   int n;
385   char buf[256];
386   screen_mode_t new_mode = screen->mode;
388   switch(screen->mode)
389     {
390     case SCREEN_PLAY_WINDOW:
391       if( play_cmd(screen, c, cmd) )
392         return;
393       break;
394     case SCREEN_FILE_WINDOW:
395       if( file_cmd(screen, c, cmd) )
396         return;
397       break;
398     case SCREEN_SEARCH_WINDOW:
399       if( search_cmd(screen, c, cmd) )
400         return;
401       break;
402     case SCREEN_HELP_WINDOW:
403       if( help_cmd(screen, c, cmd) )
404         return;
405       break;
406     }
408   switch(cmd)
409     {
410     case CMD_PLAY:
411       mpd_sendPlayCommand(c->connection, screen->playlist->selected);
412       mpd_finishCommand(c->connection);
413       break;
414     case CMD_PAUSE:
415       mpd_sendPauseCommand(c->connection);
416       mpd_finishCommand(c->connection);
417       break;
418     case CMD_STOP:
419       mpd_sendStopCommand(c->connection);
420       mpd_finishCommand(c->connection);
421       break;
422     case CMD_TRACK_NEXT:
423       if( IS_PLAYING(c->status->state) )
424         {
425           mpd_sendNextCommand(c->connection);
426           mpd_finishCommand(c->connection);
427         }
428       break;
429     case CMD_TRACK_PREVIOUS:
430       if( IS_PLAYING(c->status->state) )
431         {
432           mpd_sendPrevCommand(c->connection);
433           mpd_finishCommand(c->connection);
434         }
435       break;
436     case CMD_SHUFFLE:
437       mpd_sendShuffleCommand(c->connection);
438       mpd_finishCommand(c->connection);
439       screen_status_message(c, "Shuffled playlist!");
440       break;
441     case CMD_CLEAR:
442       mpd_sendClearCommand(c->connection);
443       mpd_finishCommand(c->connection);
444       file_clear_highlights(c);
445       screen_status_message(c, "Cleared playlist!");
446       break;
447     case CMD_REPEAT:
448       n = !c->status->repeat;
449       mpd_sendRepeatCommand(c->connection, n);
450       mpd_finishCommand(c->connection);
451       snprintf(buf, 256, "Repeat is %s", n ? "On" : "Off");
452       screen_status_message(c, buf);
453       break;
454     case CMD_RANDOM:
455       n = !c->status->random;
456       mpd_sendRandomCommand(c->connection, n);
457       mpd_finishCommand(c->connection);
458       snprintf(buf, 256, "Random is %s", n ? "On" : "Off");
459       screen_status_message(c, buf);
460       break;
461     case CMD_VOLUME_UP:
462       mpd_sendVolumeCommand(c->connection, 1);
463       mpd_finishCommand(c->connection);
464       if( c->status->volume!=MPD_STATUS_NO_VOLUME )
465         {
466           snprintf(buf, 256, "Volume %d%%", c->status->volume+1); 
467           screen_status_message(c, buf);
468         }
469       break;
470     case CMD_VOLUME_DOWN:
471       mpd_sendVolumeCommand(c->connection, -1);
472       mpd_finishCommand(c->connection);
473       if( c->status->volume!=MPD_STATUS_NO_VOLUME )
474         {
475           snprintf(buf, 256, "Volume %d%%", c->status->volume-1); 
476           screen_status_message(c, buf);
477         }
478       break;
479     case CMD_SCREEN_PREVIOUS:
480       if( screen->mode > SCREEN_PLAY_WINDOW )
481         new_mode = screen->mode - 1;
482       else
483         new_mode = SCREEN_HELP_WINDOW-1;
484       switch_screen_mode(new_mode, c);
485       break;
486     case CMD_SCREEN_NEXT:
487       new_mode = screen->mode + 1;
488       if( new_mode >= SCREEN_HELP_WINDOW )
489         new_mode = SCREEN_PLAY_WINDOW;
490       switch_screen_mode(new_mode, c);
491       break;
492     case CMD_SCREEN_PLAY:
493       switch_screen_mode(SCREEN_PLAY_WINDOW, c);
494       break;
495     case CMD_SCREEN_FILE:
496       switch_screen_mode(SCREEN_FILE_WINDOW, c);
497       break;
498     case CMD_SCREEN_SEARCH:
499       switch_screen_mode(SCREEN_SEARCH_WINDOW, c);
500       break;
501     case CMD_SCREEN_HELP:
502       switch_screen_mode(SCREEN_HELP_WINDOW, c);
503       break;
504     case CMD_QUIT:
505       exit(EXIT_SUCCESS);
506     case CMD_NONE:
507     case CMD_DELETE: 
508     case CMD_SELECT:
509     case CMD_LIST_PREVIOUS:
510     case CMD_LIST_NEXT:
511     case CMD_LIST_FIRST:
512     case CMD_LIST_LAST:
513     case CMD_LIST_NEXT_PAGE:
514     case CMD_LIST_PREVIOUS_PAGE:
515       break;
516     }