Code

included patch from Jonathan Fors
[ncmpc.git] / src / screen.c
index 76d04fa2241cbc48fdff03a543475fddf555ae74..72bdaff36247abf03e1d211db075b38d2fbace58 100644 (file)
@@ -31,6 +31,7 @@
 #include "ncmpc.h"
 #include "support.h"
 #include "mpdclient.h"
+#include "utils.h"
 #include "command.h"
 #include "options.h"
 #include "colors.h"
 #include "screen.h"
 #include "screen_utils.h"
 
-#define ENABLE_STATUS_LINE_CLOCK
-#define ENABLE_SCROLLING
+#define MAX_SONGNAME_LENGTH   512
+
+#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
 
-#define CROSSFADE_TIME 10
 
-#define STATUS_MESSAGE_TIMEOUT 3
-#define STATUS_LINE_MAX_SIZE   512
 
 /* 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);
+
+typedef screen_functions_t * (*screen_get_mode_functions_fn_t) (void);
+
+typedef struct
+{
+  gint id;
+  gchar *name;
+  screen_get_mode_functions_fn_t get_mode_functions;
+} screen_mode_info_t;
+
 
+static screen_mode_info_t screens[] = {
+  { SCREEN_PLAYLIST_ID, "playlist", get_screen_playlist },
+  { SCREEN_BROWSE_ID,   "browse",   get_screen_browse },
+#ifdef ENABLE_ARTIST_SCREEN
+  { SCREEN_ARTIST_ID,   "artist",   get_screen_artist },
+#endif
+  { SCREEN_HELP_ID,     "help",     get_screen_help },
+#ifdef ENABLE_SEARCH_SCREEN
+  { SCREEN_SEARCH_ID,   "search",   get_screen_search },
+#endif
 #ifdef ENABLE_KEYDEF_SCREEN
-extern screen_functions_t *get_screen_keydef(void);
+  { SCREEN_KEYDEF_ID,   "keydef",   get_screen_keydef },
 #endif
 #ifdef ENABLE_CLOCK_SCREEN
-extern screen_functions_t *get_screen_clock(void);
+  { SCREEN_CLOCK_ID,    "clock",    get_screen_clock },
 #endif
+  { G_MAXINT, NULL,      NULL }
+};
 
 static gboolean welcome = TRUE;
 static screen_t *screen = NULL;
@@ -65,11 +96,40 @@ static screen_functions_t *mode_fn = NULL;
 static int seek_id = -1;
 static int seek_target_time = 0;
 
+gint
+screen_get_id(char *name)
+{
+  gint i=0;
+
+  while( screens[i].name )
+    {
+      if( strcmp(name, screens[i].name) == 0 ) 
+       return screens[i].id;
+      i++;
+    }
+  return -1;
+}
+
+static gint 
+lookup_mode(gint id)
+{
+  gint i=0;
+
+  while( screens[i].name )
+    {
+      if( screens[i].id == id )
+       return i;
+      i++;
+    }
+  return -1;
+}
 
 static void
-switch_screen_mode(screen_mode_t new_mode, mpdclient_t *c)
+switch_screen_mode(gint id, mpdclient_t *c)
 {
-  if( new_mode == screen->mode )
+  gint new_mode;
+
+  if( id == screens[screen->mode].id )
     return;
 
   /* close the old mode */
@@ -77,45 +137,52 @@ switch_screen_mode(screen_mode_t new_mode, mpdclient_t *c)
     mode_fn->close();
 
   /* get functions for the new mode */
-  switch(new_mode)
+  new_mode = lookup_mode(id);
+  if( new_mode>=0 && screens[new_mode].get_mode_functions )
     {
-    case SCREEN_PLAY_WINDOW:
-      mode_fn = get_screen_playlist();
-      break;
-    case SCREEN_FILE_WINDOW:
-      mode_fn = get_screen_browse();
-      break;
-    case SCREEN_HELP_WINDOW:
-      mode_fn = get_screen_help();
-      break;
-#ifdef ENABLE_KEYDEF_SCREEN
-    case SCREEN_KEYDEF_WINDOW:
-      mode_fn = get_screen_keydef();
-      break;
-#endif
-#ifdef ENABLE_CLOCK_SCREEN
-    case SCREEN_CLOCK_WINDOW:
-      mode_fn = get_screen_clock();
-      break;
-#endif
-
-    default:
-      break;
+      D("switch_screen(%s)\n", screens[new_mode].name );
+      mode_fn = screens[new_mode].get_mode_functions();
+      screen->mode = new_mode;
     }
 
- screen->mode = new_mode;
- screen->painted = 0;
+  screen->painted = 0;
+  
+  /* open the new mode */
+  if( mode_fn && mode_fn->open )
+    mode_fn->open(screen, c);
 
- /* open the new mode */
- if( mode_fn && mode_fn->open )
-   mode_fn->open(screen, c);
+}
 
+static void
+screen_next_mode(mpdclient_t *c, int offset)
+{
+  int max = g_strv_length(options.screen_list);
+  int current, next;
+  int i;
+
+  /* find current screen */
+  current = -1;
+  i = 0;
+  while( options.screen_list[i] )
+    {
+      if( strcmp(options.screen_list[i], screens[screen->mode].name) == 0 )
+       current = i;
+      i++;
+    }
+  next = current + offset;
+  if( next<0 )
+    next = max-1;
+  else if( next>=max )
+    next = 0;
+
+  D("current mode: %d:%d    next:%d\n", current, max, next);
+  switch_screen_mode(screen_get_id(options.screen_list[next]), c);
 }
 
 static void
 paint_top_window(char *header, mpdclient_t *c, int clear)
 {
-  char flags[4];
+  char flags[5];
   static int prev_volume = -1;
   static int prev_header_len = -1;
   WINDOW *w = screen->top_window.w;
@@ -154,28 +221,40 @@ paint_top_window(char *header, mpdclient_t *c, int clear)
          colors_use(w, COLOR_TITLE_BOLD);
          waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
          colors_use(w, COLOR_TITLE);
-         waddstr(w, _(":Browse"));
+         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));
+         colors_use(w, COLOR_TITLE);
+         waddstr(w, _(":Search  "));
+#endif
        }
       if( c->status->volume==MPD_STATUS_NO_VOLUME )
        {
-         snprintf(buf, 32, _("Volume n/a "));
+         g_snprintf(buf, 32, _("Volume n/a "));
        }
       else
        {
-         snprintf(buf, 32, _(" Volume %d%%"), c->status->volume); 
+         g_snprintf(buf, 32, _(" Volume %d%%"), c->status->volume); 
        }
       colors_use(w, COLOR_TITLE);
       mvwaddstr(w, 0, screen->top_window.cols-strlen(buf), buf);
 
       flags[0] = 0;
       if( c->status->repeat )
-       strcat(flags, "r");
+       g_strlcat(flags, "r", sizeof(flags));
       if( c->status->random )
-       strcat(flags, "z");
+       g_strlcat(flags, "z", sizeof(flags));;
       if( c->status->crossfade )
-       strcat(flags, "x");
+       g_strlcat(flags, "x", sizeof(flags));
       if( c->status->updatingDb )
-       strcat(flags, "U");
+       g_strlcat(flags, "U", sizeof(flags));
       colors_use(w, COLOR_LINE);
       mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
       if( flags[0] )
@@ -227,14 +306,14 @@ paint_status_window(mpdclient_t *c)
   WINDOW *w = screen->status_window.w;
   mpd_Status *status = c->status;
   mpd_Song *song   = c->song;
-  int elapsedTime = c->status->elapsedTime;
+  int elapsedTime = 0;
   char *str = NULL;
+  char *timestr = NULL;
   int x = 0;
 
-  if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
+  if( time(NULL) - screen->status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
     return;
-  
-  
+   
   wmove(w, 0, 0);
   wclrtoeol(w);
   colors_use(w, COLOR_STATUS_BOLD);
@@ -263,20 +342,33 @@ paint_status_window(mpdclient_t *c)
   if( IS_PLAYING(status->state) || IS_PAUSED(status->state) )
     {
       if( status->totalTime > 0 )
-       {
-         if( seek_id == c->song->id )
+        {
+       
+       /*checks the conf to see whether to display elapsed or remaining time */
+       if(!strcmp(options.timedisplay_type,"elapsed"))
+          {
+             timestr= " [%i:%02i/%i:%02i]";        
+             elapsedTime = c->status->elapsedTime;
+          }
+        else if(!strcmp(options.timedisplay_type,"remaining"))
+          {
+            timestr= " [-%i:%02i/%i:%02i]";        
+            elapsedTime = (c->status->totalTime - c->status->elapsedTime);
+          }  
+       if( c->song && seek_id == c->song->id )
            elapsedTime = seek_target_time;
-         snprintf(screen->buf, screen->buf_size, 
-                  " [%i:%02i/%i:%02i]",
+       /*write out the time*/
+         g_snprintf(screen->buf, screen->buf_size, 
+                  timestr,
                   elapsedTime/60, elapsedTime%60,
                   status->totalTime/60,   status->totalTime%60 );
        }
       else
        {
-         snprintf(screen->buf, screen->buf_size,  " [%d kbps]", status->bitRate );
+         g_snprintf(screen->buf, screen->buf_size,  
+                    " [%d kbps]", status->bitRate );
        }
     }
-#ifdef ENABLE_STATUS_LINE_CLOCK
   else
     {
       time_t timep;
@@ -284,34 +376,32 @@ paint_status_window(mpdclient_t *c)
       time(&timep);
       strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
     }
-#endif
 
   /* display song */
   if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) )
     {
-      char songname[STATUS_LINE_MAX_SIZE];
+      char songname[MAX_SONGNAME_LENGTH];
       int width = COLS-x-strlen(screen->buf);
 
       if( song )
-       strfsong(songname, STATUS_LINE_MAX_SIZE, STATUS_FORMAT, song);
+       strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
       else
        songname[0] = '\0';
 
       colors_use(w, COLOR_STATUS);
-#ifdef ENABLE_SCROLLING
+      /* scroll if the song name is to long */
       if( strlen(songname) > width )
        {
          static  scroll_state_t st = { 0, 0 };
          char *tmp = strscroll(songname, " *** ", width, &st);
 
-         strcpy(songname, tmp);
+         g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
          g_free(tmp);    
        }
-#endif
       mvwaddnstr(w, 0, x, songname, width);
     } 
 
-  /* distplay time string */
+  /* display time string */
   if( screen->buf[0] )
     {
       x = screen->status_window.cols - strlen(screen->buf);
@@ -322,43 +412,29 @@ paint_status_window(mpdclient_t *c)
   wnoutrefresh(w);
 }
 
-GList *
-screen_free_string_list(GList *list)
-{
-  GList *l = g_list_first(list);
-  
-  while(l)
-    {
-      g_free(l->data);
-      l->data = NULL;
-      l=l->next;
-    }
-  g_list_free(list);
-  return NULL;
-}
-
 int
 screen_exit(void)
 {
   endwin();
   if( screen )
     {
-      GList *list = g_list_first(screen->screen_list);
+      gint i;
 
       /* close and exit all screens (playlist,browse,help...) */
-      while( list )
+      i=0;
+      while( screens[i].get_mode_functions )
        {
-         screen_functions_t *mode_fn = list->data;
+         screen_functions_t *mode_fn = screens[i].get_mode_functions();
 
          if( mode_fn && mode_fn->close )
            mode_fn->close();
          if( mode_fn && mode_fn->exit )
            mode_fn->exit();
-         list->data = NULL;
-         list=list->next;
+
+         i++;
        }
-      g_list_free(screen->screen_list);
-      screen_free_string_list(screen->find_history);
+     
+      string_list_free(screen->find_history);
       g_free(screen->buf);
       g_free(screen->findbuf);
       
@@ -371,7 +447,7 @@ screen_exit(void)
 void
 screen_resize(void)
 {
-  GList *list;
+  gint i;
 
   D("Resize rows %d->%d, cols %d->%d\n",screen->rows,LINES,screen->cols,COLS);
   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
@@ -410,15 +486,16 @@ screen_resize(void)
   g_free(screen->buf);
   screen->buf = g_malloc(screen->cols);
 
-  list = g_list_first(screen->screen_list);
-  while( list )
+  /* close and exit all screens (playlist,browse,help...) */
+  i=0;
+  while( screens[i].get_mode_functions )
     {
-      screen_functions_t *mode_fn = list->data;
+      screen_functions_t *mode_fn = screens[i].get_mode_functions();
 
       if( mode_fn && mode_fn->resize )
        mode_fn->resize(screen->main_window.cols, screen->main_window.rows);
 
-      list=list->next;
+      i++;
     }
 
   /* ? - without this the cursor becomes visible with aterm & Eterm */
@@ -444,19 +521,20 @@ screen_status_message(char *msg)
 void 
 screen_status_printf(char *format, ...)
 {
-  char buffer[STATUS_LINE_MAX_SIZE];
+  char *msg;
   va_list ap;
   
   va_start(ap,format);
-  vsnprintf(buffer,sizeof(buffer),format,ap);
+  msg = g_strdup_vprintf(format,ap);
   va_end(ap);
-  screen_status_message(buffer);
+  screen_status_message(msg);
+  g_free(msg);
 }
 
 int
 screen_init(mpdclient_t *c)
 {
-  GList *list;
+  gint i;
 
   /* initialize the curses library */
   initscr();
@@ -465,7 +543,9 @@ screen_init(mpdclient_t *c)
   /* tell curses not to do NL->CR/NL on output */
   nonl();          
   /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
+#ifdef ENABLE_RAW_MODE
   raw();
+#endif
   /* don't echo input */
   noecho();    
   /* set cursor invisible */     
@@ -474,7 +554,11 @@ screen_init(mpdclient_t *c)
   keypad(stdscr, TRUE);  
   /* return from getch() without blocking */
   timeout(SCREEN_TIMEOUT);
-  
+  /* initialize mouse support */
+#ifdef HAVE_GETMOUSE
+  if( options.enable_mouse )
+    mousemask(ALL_MOUSE_EVENTS, NULL);
+#endif
 
   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
     {
@@ -484,7 +568,7 @@ screen_init(mpdclient_t *c)
 
   screen = g_malloc(sizeof(screen_t));
   memset(screen, 0, sizeof(screen_t));
-  screen->mode = SCREEN_PLAY_WINDOW;
+  screen->mode = 0;
   screen->cols = COLS;
   screen->rows = LINES;
   screen->buf  = g_malloc(screen->cols);
@@ -547,41 +631,32 @@ screen_init(mpdclient_t *c)
     }
 
   /* initialize screens */
-  screen->screen_list = NULL;
-  screen->screen_list = g_list_append(screen->screen_list, 
-                                     (gpointer) get_screen_playlist());
-  screen->screen_list = g_list_append(screen->screen_list, 
-                                     (gpointer) get_screen_browse());
-  screen->screen_list = g_list_append(screen->screen_list, 
-                                     (gpointer) get_screen_help());
-#ifdef ENABLE_KEYDEF_SCREEN
-  screen->screen_list = g_list_append(screen->screen_list, 
-                                     (gpointer) get_screen_keydef());
-#endif
-#ifdef ENABLE_CLOCK_SCREEN
-  screen->screen_list = g_list_append(screen->screen_list, 
-                                     (gpointer) get_screen_clock());
-#endif
-
-  list = screen->screen_list;
-  while( list )
+  i=0;
+  while( screens[i].get_mode_functions )
     {
-      screen_functions_t *fn = list->data;
-      
+      screen_functions_t *fn = screens[i].get_mode_functions();
+
       if( fn && fn->init )
        fn->init(screen->main_window.w, 
                 screen->main_window.cols,
                 screen->main_window.rows);
-      
-      list = list->next;
+
+      i++;
     }
 
+#if 0
+  /* broken */
+  mode_fn = NULL;
+  switch_screen_mode(screen_get_id(options.screen_list[0]), c);
+#else
   mode_fn = get_screen_playlist();
+#endif
+
   if( mode_fn && mode_fn->open )
     mode_fn->open(screen, c);
 
   /* initialize wreadln */
-  wrln_resize_callback = screen_resize;
+  wrln_wgetch = my_wgetch;
   wrln_max_history_length = 16;
 
   return 0;
@@ -590,13 +665,20 @@ screen_init(mpdclient_t *c)
 void 
 screen_paint(mpdclient_t *c)
 {
-  /* paint the title/header window */
+  char *title = NULL;
+
   if( mode_fn && mode_fn->get_title )
-    paint_top_window(mode_fn->get_title(screen->buf,screen->buf_size), c, 1);
+    title = mode_fn->get_title(screen->buf,screen->buf_size);
+
+  D("screen_paint(%s)\n", title);
+  /* paint the title/header window */
+  if( title )
+    paint_top_window(title, c, 1);
   else
     paint_top_window("", c, 1);
 
   /* paint the main window */
+  wclear(screen->main_window.w);
   if( mode_fn && mode_fn->paint )
     mode_fn->paint(screen, c);
   
@@ -702,11 +784,52 @@ screen_idle(mpdclient_t *c)
   seek_id = -1;
 }
 
+#ifdef HAVE_GETMOUSE
+int
+screen_get_mouse_event(mpdclient_t *c,
+                      list_window_t *lw, int lw_length, 
+                      unsigned long *bstate, int *row)
+{
+  MEVENT event;
+
+  /* retreive the mouse event from ncurses */
+  getmouse(&event);
+  D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
+  /* calculate the selected row in the list window */
+  *row = event.y - screen->top_window.rows;
+  /* copy button state bits */
+  *bstate = event.bstate;
+  /* if button 2 was pressed switch screen */
+  if( event.bstate & BUTTON2_CLICKED )
+    {
+      screen_cmd(c, CMD_SCREEN_NEXT);
+      return 1;
+    }
+  /* if the even occured above the list window move up */
+  if( *row<0 && lw )
+    {
+      if( event.bstate & BUTTON3_CLICKED )
+       list_window_first(lw);
+      else
+       list_window_previous_page(lw);
+      return 1;
+    }
+   /* if the even occured below the list window move down */
+  if( *row>=lw->rows && lw )
+    {
+      if( event.bstate & BUTTON3_CLICKED )
+       list_window_last(lw, lw_length);
+      else
+       list_window_next_page(lw, lw_length);
+      return 1;
+    } 
+  return 0;
+}
+#endif
+
 void 
 screen_cmd(mpdclient_t *c, command_t cmd)
 {
-  screen_mode_t new_mode = screen->mode;
-
   screen->input_timestamp = time(NULL);
   screen->last_cmd = cmd;
   welcome = FALSE;
@@ -733,11 +856,13 @@ screen_cmd(mpdclient_t *c, command_t cmd)
              seek_id = c->song->id;
              seek_target_time = c->status->elapsedTime;
            }
-         seek_target_time++;
+         seek_target_time+=options.seek_time;
          if( seek_target_time < c->status->totalTime )
            break;
-         seek_target_time=0;
+         seek_target_time = c->status->totalTime;
+         /* seek_target_time=0; */
        }
+      break;
       /* fall through... */
     case CMD_TRACK_NEXT:
       if( !IS_STOPPED(c->status->state) )
@@ -751,7 +876,7 @@ screen_cmd(mpdclient_t *c, command_t cmd)
              seek_id = c->song->id;
              seek_target_time = c->status->elapsedTime;
            }
-         seek_target_time--;
+         seek_target_time-=options.seek_time;
          if( seek_target_time < 0 )
            seek_target_time=0;
        }
@@ -775,12 +900,15 @@ screen_cmd(mpdclient_t *c, command_t cmd)
       mpdclient_cmd_random(c, !c->status->random);
       break;
     case CMD_CROSSFADE:
-      mpdclient_cmd_crossfade(c, c->status->crossfade ? 0 : CROSSFADE_TIME);
+      if(  c->status->crossfade )
+       mpdclient_cmd_crossfade(c, 0);
+      else
+       mpdclient_cmd_crossfade(c, options.crossfade_time);     
       break;
     case CMD_DB_UPDATE:
       if( !c->status->updatingDb )
        {
-         if( mpdclient_cmd_db_update(c)==0 )
+         if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
            screen_status_printf(_("Database update started!"));
        }
       else
@@ -806,41 +934,36 @@ screen_cmd(mpdclient_t *c, command_t cmd)
                           _("Auto center mode: On") :
                           _("Auto center mode: Off"));
       break;
+    case CMD_SCREEN_UPDATE:
+      screen->painted = 0;
+      break;
     case CMD_SCREEN_PREVIOUS:
-      if( screen->mode > SCREEN_PLAY_WINDOW )
-       new_mode = screen->mode - 1;
-      else
-       new_mode = SCREEN_HELP_WINDOW-1;
-      switch_screen_mode(new_mode, c);
+      screen_next_mode(c, -1);
       break;
     case CMD_SCREEN_NEXT:
-      new_mode = screen->mode + 1;
-      if( new_mode >= SCREEN_HELP_WINDOW )
-       new_mode = SCREEN_PLAY_WINDOW;
-      switch_screen_mode(new_mode, c);
+      screen_next_mode(c, 1);
       break;
     case CMD_SCREEN_PLAY:
-      switch_screen_mode(SCREEN_PLAY_WINDOW, c);
+      switch_screen_mode(SCREEN_PLAYLIST_ID, c);
       break;
     case CMD_SCREEN_FILE:
-      switch_screen_mode(SCREEN_FILE_WINDOW, c);
+      switch_screen_mode(SCREEN_BROWSE_ID, c);
+      break;
+    case CMD_SCREEN_HELP:
+      switch_screen_mode(SCREEN_HELP_ID, c);
       break;
     case CMD_SCREEN_SEARCH:
-      switch_screen_mode(SCREEN_SEARCH_WINDOW, c);
+      switch_screen_mode(SCREEN_SEARCH_ID, c);
       break;
-    case CMD_SCREEN_HELP:
-      switch_screen_mode(SCREEN_HELP_WINDOW, c);
+    case CMD_SCREEN_ARTIST:
+      switch_screen_mode(SCREEN_ARTIST_ID, c);
       break;
-#ifdef ENABLE_KEYDEF_SCREEN 
     case CMD_SCREEN_KEYDEF:
-      switch_screen_mode(SCREEN_KEYDEF_WINDOW, c);
+      switch_screen_mode(SCREEN_KEYDEF_ID, c);
       break;
-#endif
-#ifdef ENABLE_CLOCK_SCREEN 
     case CMD_SCREEN_CLOCK:
-      switch_screen_mode(SCREEN_CLOCK_WINDOW, c);
+      switch_screen_mode(SCREEN_CLOCK_ID, c);
       break;
-#endif
     case CMD_QUIT:
       exit(EXIT_SUCCESS);
     default: