Code

3012fa31ae668494f3126b78bffd67c271f9a119
[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 <stdarg.h>
9 #include <string.h>
10 #include <time.h>
11 #include <glib.h>
12 #include <ncurses.h>
14 #include "libmpdclient.h"
15 #include "mpc.h"
16 #include "command.h"
17 #include "screen.h"
18 #include "screen_play.h"
19 #include "screen_file.h"
20 #include "screen_help.h"
21 #include "screen_search.h"
23 #define STATUS_MESSAGE_TIMEOUT 3
24 #define STATUS_LINE_MAX_SIZE   512
26 static screen_t *screen = NULL;
28 static void
29 switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
30 {
31   if( new_mode == screen->mode )
32     return;
34  switch(screen->mode)
35     {
36     case SCREEN_PLAY_WINDOW:
37       play_close(screen, c);
38       break;
39     case SCREEN_FILE_WINDOW:
40       file_close(screen, c);
41       break;
42     case SCREEN_SEARCH_WINDOW:
43       search_close(screen, c);
44       break;
45     case SCREEN_HELP_WINDOW:
46       help_close(screen, c);
47       break;
48     }
50  screen->mode = new_mode;
51  screen->painted = 0;
53  switch(screen->mode)
54     {
55     case SCREEN_PLAY_WINDOW:
56       play_open(screen, c);
57       break;
58     case SCREEN_FILE_WINDOW:
59       file_open(screen, c);
60       break;
61     case SCREEN_SEARCH_WINDOW:
62       search_open(screen, c);
63       break;
64     case SCREEN_HELP_WINDOW:
65       help_open(screen, c);
66       break;
67     }
68 }
70 static void
71 paint_top_window(char *header, int volume, int clear)
72 {
73   static int prev_volume = -1;
74   WINDOW *w = screen->top_window.w;
76   if(clear)
77     {
78       wclear(w);
79     }
81   if(prev_volume!=volume || clear)
82     {
83       char buf[12];
85       wattron(w, A_BOLD);
86       mvwaddstr(w, 0, 0, header );
87       wattroff(w, A_BOLD);
88       if( volume==MPD_STATUS_NO_VOLUME )
89         {
90           snprintf(buf, 12, "Volume n/a ");
91         }
92       else
93         {
94           snprintf(buf, 12, "Volume %3d%%", volume); 
95         }
96       mvwaddstr(w, 0, screen->top_window.cols-12, buf);
98       mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
100       wrefresh(w);
101     }
104 static void
105 paint_progress_window(mpd_client_t *c)
107   double p;
108   int width;
110   if( c->status==NULL || !IS_PLAYING(c->status->state) )
111     {
112       mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, 
113                screen->progress_window.cols);
114       wrefresh(screen->progress_window.w);
115       return;
116     }
118   p = ((double) c->status->elapsedTime) / ((double) c->status->totalTime);
119   
120   width = (int) (p * (double) screen->progress_window.cols);
121   
122   mvwhline(screen->progress_window.w, 
123            0, 0,
124            ACS_HLINE, 
125            screen->progress_window.cols);
126   
127   whline(screen->progress_window.w, '=', width-1);
128   
129   mvwaddch(screen->progress_window.w, 0, width-1, 'O');
130   wrefresh(screen->progress_window.w);
133 static void 
134 paint_status_window(mpd_client_t *c)
136   WINDOW *w = screen->status_window.w;
137   mpd_Status *status = c->status;
138   mpd_Song *song   = c->song;
139   int x = 0;
141   if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
142     return;
143   
144   wmove(w, 0, 0);
145   wclrtoeol(w);
146   
147   switch(status->state)
148     {
149     case MPD_STATUS_STATE_STOP:
150       wattron(w, A_BOLD);
151       waddstr(w, "Stopped! ");
152       wattroff(w, A_BOLD);
153       break;
154     case MPD_STATUS_STATE_PLAY:
155       waddstr(w, "Playing:");
156       break;
157     case MPD_STATUS_STATE_PAUSE:
158       wattron(w, A_BOLD);
159       waddstr(w, "Paused:");
160       wattroff(w, A_BOLD);
161       break;
162     default:
163       waddstr(w, "Warning: Music Player Daemon in unknown state!");
164       break;
165     }
166   x += 10;
168   if( IS_PLAYING(status->state) &&  song )
169     {
170       mvwaddstr(w, 0, x, mpc_get_song_name(song));
171     }
172   
174   /* time */
175   if( IS_PLAYING(status->state) )
176     {
177       x = screen->status_window.cols - strlen(screen->buf);
179       snprintf(screen->buf, screen->buf_size, 
180                " [%i:%02i/%i:%02i] ",
181                status->elapsedTime/60, status->elapsedTime%60,
182                status->totalTime/60,   status->totalTime%60 );
183       mvwaddstr(w, 0, x, screen->buf);
184         
185     }
186 #if 1
187   else if( c->status->state == MPD_STATUS_STATE_STOP )
188     {
189       time_t timep;
190       x = screen->status_window.cols - strlen(screen->buf);
191       
192       time(&timep);
193       //strftime(screen->buf, screen->buf_size, "%X ",  localtime(&timep));
194       strftime(screen->buf, screen->buf_size, "%R ",  localtime(&timep));
195       mvwaddstr(w, 0, x, screen->buf);
196     }
197 #endif
198   
200   wrefresh(w);
205 int
206 screen_exit(void)
208   endwin();
209   if( screen )
210     {
211       screen->playlist = list_window_free(screen->playlist);
212       screen->filelist = list_window_free(screen->filelist);
213       screen->helplist = list_window_free(screen->helplist);
214       free(screen->buf);
215       free(screen->findbuf);
216       free(screen);
217       screen = NULL;
218     }
219   return 0;
222 void
223 screen_resized(int sig)
225   screen_exit();
226   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
227     {
228       fprintf(stderr, "Error: Screen to small!\n");
229       exit(EXIT_FAILURE);
230     }
231   screen_init();
234 void 
235 screen_status_message(char *msg)
237   WINDOW *w = screen->status_window.w;
239   wmove(w, 0, 0);
240   wclrtoeol(w);
241   wattron(w, A_BOLD);
242   waddstr(w, msg);
243   wattroff(w, A_BOLD);
244   wrefresh(w);
245   screen->status_timestamp = time(NULL);
248 void 
249 screen_status_printf(char *format, ...)
251   char buffer[STATUS_LINE_MAX_SIZE];
252   va_list ap;
253   
254   va_start(ap,format);
255   vsnprintf(buffer,sizeof(buffer),format,ap);
256   va_end(ap);
257   screen_status_message(buffer);
260 int
261 screen_init(void)
263   /* initialize the curses library */
264   initscr();      
265   start_color();
266   use_default_colors();
267   /* tell curses not to do NL->CR/NL on output */
268   nonl();          
269   /* take input chars one at a time, no wait for \n */  
270   cbreak();       
271   /* don't echo input */
272   noecho();    
273   /* set cursor invisible */     
274   curs_set(0);     
275   /* return from getch() without blocking */
276   //  nodelay(stdscr, TRUE); 
277   keypad(stdscr, TRUE);  
278   timeout(100); /*void wtimeout(WINDOW *win, int delay);*/
281   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
282     {
283       fprintf(stderr, "Error: Screen to small!\n");
284       exit(EXIT_FAILURE);
285     }
287   screen = malloc(sizeof(screen_t));
288   memset(screen, 0, sizeof(screen_t));
289   screen->mode = SCREEN_PLAY_WINDOW;
290   screen->cols = COLS;
291   screen->rows = LINES;
292   screen->buf  = malloc(screen->cols);
293   screen->buf_size = screen->cols;
294   screen->findbuf = NULL;
295   screen->painted = 0;
297   /* create top window */
298   screen->top_window.rows = 2;
299   screen->top_window.cols = screen->cols;
300   screen->top_window.w = newwin(screen->top_window.rows, 
301                                   screen->top_window.cols,
302                                   0, 0);
303   leaveok(screen->top_window.w, TRUE);
304   keypad(screen->top_window.w, TRUE);  
306   /* create main window */
307   screen->main_window.rows = screen->rows-4;
308   screen->main_window.cols = screen->cols;
309   screen->main_window.w = newwin(screen->main_window.rows, 
310                                  screen->main_window.cols,
311                                  2, 
312                                  0);
313   screen->playlist = list_window_init( screen->main_window.w,
314                                        screen->main_window.cols,
315                                        screen->main_window.rows );
316   screen->filelist = list_window_init( screen->main_window.w,
317                                        screen->main_window.cols,
318                                        screen->main_window.rows );
319   screen->helplist = list_window_init( screen->main_window.w,
320                                        screen->main_window.cols,
321                                        screen->main_window.rows );
322   leaveok(screen->main_window.w, TRUE);
323   keypad(screen->main_window.w, TRUE);  
325   /* create progress window */
326   screen->progress_window.rows = 1;
327   screen->progress_window.cols = screen->cols;
328   screen->progress_window.w = newwin(screen->progress_window.rows, 
329                                      screen->progress_window.cols,
330                                      screen->rows-2, 
331                                      0);
332   leaveok(screen->progress_window.w, TRUE);
333   
334   /* create status window */
335   screen->status_window.rows = 1;
336   screen->status_window.cols = screen->cols;
337   screen->status_window.w = newwin(screen->status_window.rows, 
338                                    screen->status_window.cols,
339                                    screen->rows-1, 
340                                    0);
341   leaveok(screen->status_window.w, FALSE);
342   keypad(screen->status_window.w, TRUE);  
344   return 0;
347 void 
348 screen_paint(mpd_client_t *c)
350   switch(screen->mode)
351     {
352     case SCREEN_PLAY_WINDOW:
353       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
354       play_paint(screen, c);      
355       break;
356     case SCREEN_FILE_WINDOW:
357       paint_top_window(file_get_header(c), c->status->volume, 1);
358       file_paint(screen, c);      
359       break;
360     case SCREEN_SEARCH_WINDOW:
361       paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 1);
362       search_paint(screen, c);      
363       break;
364     case SCREEN_HELP_WINDOW:
365       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
366       help_paint(screen, c);      
367       break;
368     }
370   paint_progress_window(c);
371   paint_status_window(c);
372   screen->painted = 1;
375 void 
376 screen_update(mpd_client_t *c)
378   if( !screen->painted )
379     return screen_paint(c);
381   switch(screen->mode)
382     {
383     case SCREEN_PLAY_WINDOW:
384       paint_top_window(TOP_HEADER_PLAY, c->status->volume, 0);
385       play_update(screen, c);
386       break;
387     case SCREEN_FILE_WINDOW:
388       paint_top_window(file_get_header(c), c->status->volume, 0);
389       file_update(screen, c);
390       break;
391     case SCREEN_SEARCH_WINDOW:
392       paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 0);
393       search_update(screen, c);
394       break;
395     case SCREEN_HELP_WINDOW:
396       paint_top_window(TOP_HEADER_HELP, c->status->volume, 0);
397       help_update(screen, c);
398       break;
399     }
400   paint_progress_window(c);
401   paint_status_window(c);
404 void 
405 screen_cmd(mpd_client_t *c, command_t cmd)
407   int n;
408   //  char buf[256];
409   screen_mode_t new_mode = screen->mode;
411   switch(screen->mode)
412     {
413     case SCREEN_PLAY_WINDOW:
414       if( play_cmd(screen, c, cmd) )
415         return;
416       break;
417     case SCREEN_FILE_WINDOW:
418       if( file_cmd(screen, c, cmd) )
419         return;
420       break;
421     case SCREEN_SEARCH_WINDOW:
422       if( search_cmd(screen, c, cmd) )
423         return;
424       break;
425     case SCREEN_HELP_WINDOW:
426       if( help_cmd(screen, c, cmd) )
427         return;
428       break;
429     }
431   switch(cmd)
432     {
433     case CMD_PLAY:
434       mpd_sendPlayCommand(c->connection, screen->playlist->selected);
435       mpd_finishCommand(c->connection);
436       break;
437     case CMD_PAUSE:
438       mpd_sendPauseCommand(c->connection);
439       mpd_finishCommand(c->connection);
440       break;
441     case CMD_STOP:
442       mpd_sendStopCommand(c->connection);
443       mpd_finishCommand(c->connection);
444       break;
445     case CMD_TRACK_NEXT:
446       if( IS_PLAYING(c->status->state) )
447         {
448           mpd_sendNextCommand(c->connection);
449           mpd_finishCommand(c->connection);
450         }
451       break;
452     case CMD_TRACK_PREVIOUS:
453       if( IS_PLAYING(c->status->state) )
454         {
455           mpd_sendPrevCommand(c->connection);
456           mpd_finishCommand(c->connection);
457         }
458       break;
459     case CMD_SHUFFLE:
460       mpd_sendShuffleCommand(c->connection);
461       mpd_finishCommand(c->connection);
462       screen_status_message("Shuffled playlist!");
463       break;
464     case CMD_CLEAR:
465       mpd_sendClearCommand(c->connection);
466       mpd_finishCommand(c->connection);
467       file_clear_highlights(c);
468       screen_status_message("Cleared playlist!");
469       break;
470     case CMD_REPEAT:
471       n = !c->status->repeat;
472       mpd_sendRepeatCommand(c->connection, n);
473       mpd_finishCommand(c->connection);
474       screen_status_printf("Repeat is %s", n ? "On" : "Off");
475       break;
476     case CMD_RANDOM:
477       n = !c->status->random;
478       mpd_sendRandomCommand(c->connection, n);
479       mpd_finishCommand(c->connection);
480       screen_status_printf("Random is %s", n ? "On" : "Off");
481       break;
482     case CMD_VOLUME_UP:
483       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
484         {
485           c->status->volume=c->status->volume+1;
486           mpd_sendSetvolCommand(c->connection, c->status->volume  );
487           mpd_finishCommand(c->connection);
488           screen_status_printf("Volume %d%%", c->status->volume);
489         }
490       break;
491     case CMD_VOLUME_DOWN:
492       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
493         {
494           c->status->volume=c->status->volume-1;
495           mpd_sendSetvolCommand(c->connection, c->status->volume  );
496           mpd_finishCommand(c->connection);
497           screen_status_printf("Volume %d%%", c->status->volume);
498         }
499       break;
500     case CMD_SCREEN_PREVIOUS:
501       if( screen->mode > SCREEN_PLAY_WINDOW )
502         new_mode = screen->mode - 1;
503       else
504         new_mode = SCREEN_HELP_WINDOW-1;
505       switch_screen_mode(new_mode, c);
506       break;
507     case CMD_SCREEN_NEXT:
508       new_mode = screen->mode + 1;
509       if( new_mode >= SCREEN_HELP_WINDOW )
510         new_mode = SCREEN_PLAY_WINDOW;
511       switch_screen_mode(new_mode, c);
512       break;
513     case CMD_SCREEN_PLAY:
514       switch_screen_mode(SCREEN_PLAY_WINDOW, c);
515       break;
516     case CMD_SCREEN_FILE:
517       switch_screen_mode(SCREEN_FILE_WINDOW, c);
518       break;
519     case CMD_SCREEN_SEARCH:
520       switch_screen_mode(SCREEN_SEARCH_WINDOW, c);
521       break;
522     case CMD_SCREEN_HELP:
523       switch_screen_mode(SCREEN_HELP_WINDOW, c);
524       break;
525     case CMD_QUIT:
526       exit(EXIT_SUCCESS);
527     case CMD_LIST_FIND:
528     case CMD_LIST_FIND_NEXT:
529     case CMD_NONE:
530     case CMD_DELETE: 
531     case CMD_SELECT:
532     case CMD_LIST_PREVIOUS:
533     case CMD_LIST_NEXT:
534     case CMD_LIST_FIRST:
535     case CMD_LIST_LAST:
536     case CMD_LIST_NEXT_PAGE:
537     case CMD_LIST_PREVIOUS_PAGE:
538       break;
539     }