From eb88eaecb3055fc5ab3cd3e05f0bc77e68f3942a Mon Sep 17 00:00:00 2001
From: Frederic Culot <calcurse@culot.org>
Date: Sun, 23 Nov 2008 20:38:55 +0000
Subject: Building configuration menu to assign keybindings

---
 src/calcurse.c |  10 ++-
 src/custom.c   | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/custom.h   |   5 +-
 src/help.c     |  44 +++++-----
 src/help.h     |   7 +-
 src/keys.c     | 226 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/keys.h     |  21 ++++-
 src/notify.c   |   4 +-
 src/utils.c    | 104 +++++-------------------
 src/utils.h    |   6 +-
 src/wins.c     |  10 +--
 src/wins.h     |   6 +-
 12 files changed, 541 insertions(+), 151 deletions(-)

(limited to 'src')

diff --git a/src/calcurse.c b/src/calcurse.c
index c3bb3ee..c327af2 100755
--- a/src/calcurse.c
+++ b/src/calcurse.c
@@ -1,4 +1,4 @@
-/*	$calcurse: calcurse.c,v 1.70 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: calcurse.c,v 1.71 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -243,7 +243,7 @@ main (int argc, char **argv)
 
         case KEY_GENERIC_CONFIG_MENU:
 	  erase_status_bar ();
-	  config_bar ();
+	  custom_config_bar ();
 	  while ((key = wgetch (win[STA].p)) != 'q')
 	    {
 	      switch (key)
@@ -272,12 +272,16 @@ main (int argc, char **argv)
 		case 'n':
 		  notify_config_bar ();
 		  break;
+                case 'K':
+                case 'k':
+                  custom_keys_config ();
+                  break;
 		}
 	      wins_reset ();
 	      wins_update ();
 	      do_storage = true;
 	      erase_status_bar ();
-	      config_bar ();
+	      custom_config_bar ();
 	    }
 	  wins_update ();
 	  break;
diff --git a/src/custom.c b/src/custom.c
index 9588692..d532ebb 100755
--- a/src/custom.c
+++ b/src/custom.c
@@ -1,4 +1,4 @@
-/*	$calcurse: custom.c,v 1.25 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: custom.c,v 1.26 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -26,6 +26,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <math.h>
 
 #include "custom.h"
 #include "i18n.h"
@@ -352,7 +353,7 @@ custom_load_conf (conf_t *conf, int background)
 
 /* Draws the configuration bar */
 void
-config_bar (void)
+custom_config_bar (void)
 {
   int smlspc, spc;
 
@@ -365,6 +366,7 @@ config_bar (void)
   mvwprintw (win[STA].p, 0, 2 + spc, "L");
   mvwprintw (win[STA].p, 1, 2 + spc, "C");
   mvwprintw (win[STA].p, 0, 2 + 2 * spc, "N");
+  mvwprintw (win[STA].p, 1, 2 + 2 * spc, "K");  
   custom_remove_attr (win[STA].p, ATTR_HIGHEST);
 
   mvwprintw (win[STA].p, 0, 2 + smlspc, _("Exit"));
@@ -372,7 +374,8 @@ config_bar (void)
   mvwprintw (win[STA].p, 0, 2 + spc + smlspc, _("Layout"));
   mvwprintw (win[STA].p, 1, 2 + spc + smlspc, _("Color"));
   mvwprintw (win[STA].p, 0, 2 + 2 * spc + smlspc, _("Notify"));
-
+  mvwprintw (win[STA].p, 1, 2 + 2 * spc + smlspc, _("Keys"));
+  
   wnoutrefresh (win[STA].p);
   wmove (win[STA].p, 0, 0);
   doupdate ();
@@ -720,38 +723,41 @@ print_general_options (WINDOW *win, conf_t *conf)
   
   y = 0;
   mvwprintw (win, y, XPOS, "[1] %s      ", opt1);
-  print_option_incolor (win, conf->auto_save, y, XPOS + 4 + strlen (opt1));
+  print_bool_option_incolor (win, conf->auto_save, y,
+                             XPOS + 4 + strlen (opt1));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, automatic save is done when quitting)"));
   y += YOFF;
   mvwprintw (win, y, XPOS, "[2] %s      ", opt2);
-  print_option_incolor (win, conf->confirm_quit, y, XPOS + 4 + strlen (opt2));
+  print_bool_option_incolor (win, conf->confirm_quit, y,
+                             XPOS + 4 + strlen (opt2));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, confirmation is required before quitting)"));
   y += YOFF;
   mvwprintw (win, y, XPOS, "[3] %s      ", opt3);
-  print_option_incolor (win, conf->confirm_delete, y, XPOS + 4 + strlen (opt3));
+  print_bool_option_incolor (win, conf->confirm_delete, y,
+                             XPOS + 4 + strlen (opt3));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, confirmation is required "
                "before deleting an event)"));
   y += YOFF;
   mvwprintw (win, y, XPOS, "[4] %s      ", opt4);
-  print_option_incolor (win, conf->skip_system_dialogs, y,
-			XPOS + 4 + strlen (opt4));
+  print_bool_option_incolor (win, conf->skip_system_dialogs, y,
+                             XPOS + 4 + strlen (opt4));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, messages about loaded "
                "and saved data will not be displayed)"));
   y += YOFF;
   mvwprintw (win, y, XPOS, "[5] %s      ", opt5);
-  print_option_incolor (win, conf->skip_progress_bar, y,
-			XPOS + 4 + strlen (opt5));
+  print_bool_option_incolor (win, conf->skip_progress_bar, y,
+                            XPOS + 4 + strlen (opt5));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, progress bar will not be displayed "
                 "when saving data)"));
   y += YOFF;
   mvwprintw (win, y, XPOS, "[6] %s      ", opt6);
-  print_option_incolor (win, calendar_week_begins_on_monday (), y,
-			XPOS + 4 + strlen (opt6));
+  print_bool_option_incolor (win, calendar_week_begins_on_monday (), y,
+                             XPOS + 4 + strlen (opt6));
   mvwprintw (win, y + 1, XPOS,
 	     _("(if set to YES, monday is the first day of the week, "
                "else it is sunday)"));
@@ -770,11 +776,11 @@ print_general_options (WINDOW *win, conf_t *conf)
   mvwprintw (win, y + 1, XPOS, _("(Format to be used when entering a date: "));
   mvwprintw (win, y + 2, XPOS, _(" 1-mm/dd/yyyy, 2-dd/mm/yyyy, 3-yyyy/mm/dd)"));
 
-  return (y + 3);
+  return y + YOFF;
 }
 
 static void
-general_conf_set_scrsize (scrollwin_t *sw)
+conf_set_scrsize (scrollwin_t *sw)
 {
   sw->win.x = 0;
   sw->win.y = 0;
@@ -802,7 +808,7 @@ custom_general_config (conf_t *conf)
   char *buf = (char *) malloc (BUFSIZ);
 
   clear ();
-  general_conf_set_scrsize (&cwin);
+  conf_set_scrsize (&cwin);
   snprintf (cwin.label, BUFSIZ, _("CalCurse %s | general options"), VERSION);
   wins_scrollwin_init (&cwin);
   wins_show (cwin.win.p, cwin.label);
@@ -819,7 +825,7 @@ custom_general_config (conf_t *conf)
           wins_reset ();
 	  wins_scrollwin_delete (&cwin);
 	  wins_scrollwin_init (&cwin);
-          general_conf_set_scrsize (&cwin);
+          conf_set_scrsize (&cwin);
           wins_show (cwin.win.p, cwin.label);
 	  cwin.first_visible_line = 0;          
 	  delwin (win[STA].p);
@@ -833,10 +839,10 @@ custom_general_config (conf_t *conf)
 	    }
 	  break;
         case KEY_MOVE_DOWN:
-          wins_scrollwin_down (&cwin);
+          wins_scrollwin_down (&cwin, 1);
 	  break;
 	case KEY_MOVE_UP:
-          wins_scrollwin_up (&cwin);
+          wins_scrollwin_up (&cwin, 1);
 	  break;
 	case '1':
 	  conf->auto_save = !conf->auto_save;
@@ -884,3 +890,210 @@ custom_general_config (conf_t *conf)
   free (buf);
   wins_scrollwin_delete (&cwin);
 }
+
+
+static void
+print_key_incolor (WINDOW *win, char *option, int pos_y, int pos_x)
+{
+  const int color = ATTR_HIGHEST;
+
+  RETURN_IF (!option, _("Undefined option!"));
+  custom_apply_attr (win, color);
+  mvwprintw (win, pos_y, pos_x, "%s ", option);
+  custom_remove_attr (win, color);
+  wnoutrefresh (win);
+}
+
+static int
+print_keys_bindings (WINDOW *win, int selected_row, int selected_elm, int yoff)
+{
+  const int XPOS = 1;
+  const int EQUALPOS = 23;
+  const int KEYPOS = 25;
+  int noelm, action, y;
+
+  noelm = y = 0;
+  for (action = 0; action < NBKEYS; action++)
+    {
+      char actionstr[BUFSIZ];
+      int nbkeys;
+
+      nbkeys = keys_action_count_keys (action);      
+      snprintf (actionstr, BUFSIZ, "%s", keys_get_label (action));
+      if (action == selected_row)
+        custom_apply_attr (win, ATTR_HIGHEST);
+      mvwprintw (win, y, XPOS, "%s ", actionstr);
+      mvwprintw (win, y, EQUALPOS, "=");
+      if (nbkeys == 0)
+        mvwprintw (win, y, KEYPOS, _("undefined"));        
+      if (action == selected_row)
+        custom_remove_attr (win, ATTR_HIGHEST);
+      if (nbkeys > 0)
+        {
+          if (action == selected_row)
+            {
+              char *key;
+              int pos;
+              
+              pos = KEYPOS;
+              while ((key = keys_action_nkey (action, noelm)) != 0)
+                {
+                  if (noelm == selected_elm)
+                    print_key_incolor (win, key, y, pos);
+                  else
+                    mvwprintw (win, y, pos, "%s ", key);                
+                  noelm++;
+                  pos += strlen (key) + 1;
+                }
+            }
+          else
+            {
+              mvwprintw (win, y, KEYPOS, "%s", keys_action_allkeys (action));
+            }
+        }
+      y += yoff;
+    }
+  
+  return noelm;
+}
+
+static void
+custom_keys_config_bar (void)
+{
+  binding_t quit  = {_("Exit"),     KEY_GENERIC_QUIT};
+  binding_t info  = {_("Key info"), KEY_GENERIC_HELP};
+  binding_t add   = {_("Add key"),  KEY_ADD_ITEM};
+  binding_t del   = {_("Del key"),  KEY_DEL_ITEM};
+  binding_t edit  = {_("Edit key"), KEY_EDIT_ITEM};
+  binding_t up    = {_("Up"),       KEY_MOVE_UP};
+  binding_t down  = {_("Down"),     KEY_MOVE_DOWN};
+  binding_t left  = {_("Prev Key"), KEY_MOVE_LEFT};
+  binding_t right = {_("Next Key"), KEY_MOVE_RIGHT};
+    
+  binding_t *binding[] = {
+    &quit, &info, &add, &del, &edit, &up, &down, &left, &right
+  };
+  int binding_size = sizeof (binding) / sizeof (binding[0]);
+
+  keys_display_bindings_bar (win[STA].p, binding, 0, binding_size);
+}
+
+void
+custom_keys_config (void)
+{
+  scrollwin_t kwin;
+  int selrow, selelm, firstrow, lastrow, nbrowelm, nbdisplayed;
+  int keyval, used;
+  char *keystr;
+  WINDOW *grabwin;
+  const int LINESPERKEY = 2;
+  const int LABELLINES = 3;
+  
+  clear ();
+  conf_set_scrsize (&kwin);
+  nbdisplayed = (kwin.win.h - LABELLINES) / LINESPERKEY;
+  snprintf (kwin.label, BUFSIZ, _("CalCurse %s | keys configuration"), VERSION);
+  wins_scrollwin_init (&kwin);
+  wins_show (kwin.win.p, kwin.label);
+  custom_keys_config_bar ();
+  selrow = selelm = 0;
+  nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, LINESPERKEY);
+  kwin.total_lines = NBKEYS * LINESPERKEY;
+  wins_scrollwin_display (&kwin);
+  firstrow = 0;
+  lastrow = firstrow + nbdisplayed - 1;
+  for (;;)
+    {
+      int ch;
+
+      ch = keys_getch (win[STA].p);
+      switch (ch)
+	{
+        case KEY_MOVE_UP:
+          if (selrow > 0)
+            {
+              selrow--;
+              selelm = 0;
+              if (selrow == firstrow)
+                {
+                  firstrow--;
+                  lastrow--;
+                  wins_scrollwin_up (&kwin, LINESPERKEY);
+                }
+            }
+	  break;
+	case KEY_MOVE_DOWN:
+          if (selrow < NBKEYS - 1)
+            {
+              selrow++;
+              selelm = 0;
+              if (selrow == lastrow)
+                {
+                  firstrow++;
+                  lastrow++;
+                  wins_scrollwin_down (&kwin, LINESPERKEY);
+                }
+            }
+	  break;
+        case KEY_MOVE_LEFT:
+          if (selelm > 0)
+            selelm--;
+          break;
+        case KEY_MOVE_RIGHT:
+          if (selelm < nbrowelm - 1)
+            selelm++;
+          break;
+        case KEY_GENERIC_HELP:
+          keys_popup_info (selrow);
+          break;
+        case KEY_ADD_ITEM:
+#define WINROW 10
+#define WINCOL 50
+          do
+            {
+              grabwin = popup (WINROW, WINCOL, (row - WINROW) / 2,
+                               (col - WINCOL) / 2,
+                               _("Press the key you want to assign to:"),
+                               keys_get_label (selrow), 0);
+              keyval = wgetch (grabwin);
+              used = keys_assign_binding (keyval, selrow);
+              if (used)
+                {
+                  keys_e action;
+                  
+                  action = keys_get_action (keyval);
+                  ERROR_MSG (
+                             _("This key is already in use for %s, "
+                               "please choose another one."),
+                             keys_get_label (action));
+                  werase (kwin.pad.p);
+                  nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm,
+                                                  LINESPERKEY);
+                  wins_scrollwin_display (&kwin);
+                }
+              delwin (grabwin);              
+            }
+          while (used);
+          selelm++;
+#undef WINROW
+#undef WINCOL
+          break;
+        case KEY_DEL_ITEM:
+          keystr = keys_action_nkey (selrow, selelm);
+          keyval = keys_str2int (keystr);
+          keys_remove_binding (keyval, selrow);
+          if (selelm > 0)
+            selelm--;
+          break;
+        case KEY_EDIT_ITEM:
+          break;
+        case KEY_GENERIC_QUIT:
+          wins_scrollwin_delete (&kwin);
+          return;
+	}
+      custom_keys_config_bar ();
+      werase (kwin.pad.p);
+      nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, LINESPERKEY);
+      wins_scrollwin_display (&kwin);
+    }
+}
diff --git a/src/custom.h b/src/custom.h
index 4c21284..470eadf 100755
--- a/src/custom.h
+++ b/src/custom.h
@@ -1,4 +1,4 @@
-/*	$calcurse: custom.h,v 1.12 2008/04/12 21:14:03 culot Exp $	*/
+/*	$calcurse: custom.h,v 1.13 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -76,11 +76,12 @@ void custom_init_attr (void);
 void custom_apply_attr (WINDOW *, int);
 void custom_remove_attr (WINDOW *, int);
 void custom_load_conf (conf_t *, int);
-void config_bar (void);
+void custom_config_bar (void);
 void layout_config (void);
 void custom_color_config (void);
 void custom_color_theme_name (char *);
 void custom_confwin_init (window_t *, char *);
 void custom_general_config (conf_t *);
+void custom_keys_config (void);
 
 #endif /* CALCURSE_CUSTOM_H */
diff --git a/src/help.c b/src/help.c
index 067d24a..9d1f735 100755
--- a/src/help.c
+++ b/src/help.c
@@ -1,4 +1,4 @@
-/*	$calcurse: help.c,v 1.30 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: help.c,v 1.31 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -82,19 +82,19 @@ get_help_lines (char *text)
  * Write the desired help text inside the help pad, and return the number
  * of lines that were written. 
  */
-static int
-write_help_pad (window_t *win, help_page_t *hpage)
+int
+help_write_pad (window_t *win, char *title, char *text)
 {
   int nl_title = 0;
   int nl_text = 0;
 
-  nl_text = get_help_lines (hpage->text);
-  nl_title = get_help_lines (hpage->title);
+  nl_text = get_help_lines (text);
+  nl_title = get_help_lines (title);
   erase_window_part (win->p, 0, 0, BUFSIZ, win->w);
   custom_apply_attr (win->p, ATTR_HIGHEST);
-  mvwprintw (win->p, 0, 0, "%s", hpage->title);
+  mvwprintw (win->p, 0, 0, "%s", title);
   custom_remove_attr (win->p, ATTR_HIGHEST);
-  mvwprintw (win->p, nl_title, 0, "%s", hpage->text);
+  mvwprintw (win->p, nl_title, 0, "%s", text);
   return (nl_text + nl_title);
 }
 
@@ -102,21 +102,21 @@ write_help_pad (window_t *win, help_page_t *hpage)
  * Create and init help screen and its pad, which is used to make the scrolling
  * faster. 
  */
-static void
-help_wins_init (scrollwin_t *hwin)
+void
+help_wins_init (scrollwin_t *hwin, int x, int y, int h, int w)
 {
   const int PADOFFSET = 4;
   const int TITLELINES = 3;
 
-  hwin->win.x = 0;
-  hwin->win.y = 0;
-  hwin->win.h = (notify_bar ()) ? row - 3 : row - 2;
-  hwin->win.w = col;
+  hwin->win.x = x;
+  hwin->win.y = y;
+  hwin->win.h = h;
+  hwin->win.w = w;
 
   hwin->pad.x = PADOFFSET;
   hwin->pad.y = TITLELINES;
   hwin->pad.h = BUFSIZ;
-  hwin->pad.w = col - 2 * PADOFFSET + 1;
+  hwin->pad.w = hwin->win.w - 2 * PADOFFSET + 1;
 
   snprintf (hwin->label, BUFSIZ, _("Calcurse %s | help"), VERSION);
   wins_scrollwin_init (hwin);
@@ -132,11 +132,11 @@ help_wins_reinit (scrollwin_t *hwin)
 {
   wins_scrollwin_delete (hwin);
   wins_get_config ();
-  help_wins_init (hwin);
+  help_wins_init (hwin, 0, 0, (notify_bar ()) ? row - 3 : row - 2, col);
 }
 
 /* Reset the screen, needed when resizing terminal for example. */
-static void
+void
 help_wins_reset (scrollwin_t *hwin)
 {
   endwin ();
@@ -596,7 +596,7 @@ help_screen (void)
       "Send your feedback or comments to : calcurse@culot.org\n"
       "Calcurse home page : http://culot.org/calcurse");
 
-  help_wins_init (&hwin);
+  help_wins_init (&hwin, 0, 0, (notify_bar ()) ? row - 3 : row - 2, col);
   page = oldpage = HELP_MAIN;
   need_resize = 0;
   
@@ -611,16 +611,17 @@ help_screen (void)
           wins_get_config ();
 	  help_wins_reset (&hwin);
 	  hwin.first_visible_line = 0;
-	  hwin.total_lines = write_help_pad (&hwin.pad, &hscr[oldpage]);
+	  hwin.total_lines = help_write_pad (&hwin.pad, hscr[oldpage].title,
+                                             hscr[oldpage].text);
 	  need_resize = 1;
 	  break;
 
 	case KEY_GENERIC_SCROLL_DOWN:
-          wins_scrollwin_down (&hwin);
+          wins_scrollwin_down (&hwin, 1);
 	  break;
 
 	case KEY_GENERIC_SCROLL_UP:
-          wins_scrollwin_up (&hwin);
+          wins_scrollwin_up (&hwin, 1);
 	  break;
 
 	default:
@@ -628,7 +629,8 @@ help_screen (void)
 	  if (page != NOPAGE)
 	    {
 	      hwin.first_visible_line = 0;
-	      hwin.total_lines = write_help_pad (&hwin.pad, &hscr[page]);
+	      hwin.total_lines = help_write_pad (&hwin.pad, hscr[page].title,
+                                                 hscr[page].text);
 	      oldpage = page;
 	    }
 	  break;
diff --git a/src/help.h b/src/help.h
index 2753137..7d76c8d 100755
--- a/src/help.h
+++ b/src/help.h
@@ -1,4 +1,4 @@
-/*	$calcurse: help.h,v 1.5 2008/04/12 21:14:03 culot Exp $	*/
+/*	$calcurse: help.h,v 1.6 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -27,6 +27,8 @@
 #ifndef CALCURSE_HELP_H
 #define CALCURSE_HELP_H
 
+#include "wins.h"
+
 typedef struct
 {
   char *title;
@@ -35,5 +37,8 @@ typedef struct
 help_page_t;
 
 void help_screen (void);
+void help_wins_init (scrollwin_t *, int, int, int, int);
+void help_wins_reset (scrollwin_t *);
+int  help_write_pad (window_t *, char *, char *);
 
 #endif /* CALCURSE_HELP_H */
diff --git a/src/keys.c b/src/keys.c
index 4f8f9bc..bef1e9d 100755
--- a/src/keys.c
+++ b/src/keys.c
@@ -1,4 +1,4 @@
-/*	$calcurse: keys.c,v 1.3 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: keys.c,v 1.4 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -25,9 +25,11 @@
  */
 
 #include <string.h>
+#include <math.h>
 
 #include "i18n.h"
 #include "utils.h"
+#include "custom.h"
 #include "keys.h"
 
 #define MAXKEYVAL     256
@@ -104,7 +106,9 @@ dump_intro (FILE *fd)
       "# To define bindings which use the CONTROL key, prefix the key with "
       "'C-'.\n"
       "# The escape and horizontal Tab key can be specified using the 'ESC'\n"
-      "# and 'TAB' keyword, respectively.\n");
+      "# and 'TAB' keyword, respectively.\n#\n"
+      "# A description of what each ACTION keyword is used for is available\n"
+      "# from calcurse online configuration menu.\n");
 
   fprintf (fd, "%s\n", intro);
 }
@@ -144,7 +148,7 @@ keys_get_label (keys_e key)
   return keydef[key].label;
 }
 
-static int
+keys_e
 keys_get_action (int pressed)
 {
   if (pressed < 0 || pressed > MAXKEYVAL)
@@ -256,7 +260,9 @@ keys_str2int (char *key)
     return (int)key[0];
   else
     {
-      if (!strncmp (key, CONTROL_KEY.str, CONTROL_KEY.len))
+      if (key[0] == '^')
+        return CTRL ((int)key[1]);
+      else if (!strncmp (key, CONTROL_KEY.str, CONTROL_KEY.len))
         return CTRL ((int)key[CONTROL_KEY.len]);
       else if (!strncmp (key, TAB_KEY.str, TAB_KEY.len))
         return TAB;
@@ -270,13 +276,50 @@ keys_str2int (char *key)
 char *
 keys_int2str (int key)
 {
-  return keyname (key);
+  switch (key)
+    {
+    case TAB:
+      return "TAB";
+    case ESCAPE:
+      return "ESC";
+    default:
+      return keyname (key);
+    }
+}
+
+int
+keys_action_count_keys (keys_e action)
+{
+  struct key_str_s *key;
+  int i;
+
+  i = 0;
+  for (key = keys[action]; key; key = key->next)
+    i++;
+
+  return i;
 }
 
 char *
 keys_action_firstkey (keys_e action)
 {
-  return (keys[action] != NULL) ? keys[action]->str : NULL; 
+  return (keys[action] != NULL) ? keys[action]->str : "XXX"; 
+}
+
+char *
+keys_action_nkey (keys_e action, int keynum)
+{
+  struct key_str_s *key;
+  int i;
+
+  i = 0;
+  for (key = keys[action]; key; key = key->next)
+    {
+      if (i == keynum)
+        return key->str;
+      i++;
+    }
+  return (char *)0;
 }
 
 char *
@@ -298,3 +341,174 @@ keys_action_allkeys (keys_e action)
 
   return keystr;
 }
+
+/* Need this to display keys properly inside status bar. */
+static char *
+keys_format_label (char *key, int keylen)
+{
+  static char fmtkey[BUFSIZ];
+  const int len = strlen (key);
+  char *dot = ".";
+  int i;
+
+  if (keylen > BUFSIZ)
+    return (char *)0;
+
+  bzero (fmtkey, sizeof (fmtkey));
+  if (len == 0)
+    snprintf (fmtkey, sizeof (fmtkey), "?");
+  else if (len <= keylen)
+    {
+      for (i = 0; i < keylen - len; i++)
+        fmtkey[i] = ' ';
+      strncat (fmtkey, key, keylen);
+    }
+  else
+    {
+      for (i = 0; i < keylen - 1; i++)
+        fmtkey[i] = key[i];
+      strncat (fmtkey, dot, strlen (dot));
+    }
+  return fmtkey;
+}
+
+void
+keys_display_bindings_bar (WINDOW *win, binding_t **binding, int first_key,
+                           int last_key)
+{
+  int i, j, cmdlen, space_between_cmds;
+
+  /* Total length of a command. */
+  cmdlen =  KEYS_KEYLEN + 1 + KEYS_LABELEN;
+  space_between_cmds = floor (col / KEYS_CMDS_PER_LINE - cmdlen);
+  cmdlen += space_between_cmds;
+  
+  j = 0;
+  erase_status_bar ();
+  for (i = first_key; i < last_key; i += 2)
+    {
+      char key[KEYS_KEYLEN + 1], *fmtkey;
+      const int KEY_POS = j * cmdlen;
+      const int LABEL_POS = j * cmdlen + KEYS_KEYLEN + 1;
+
+      strncpy (key, keys_action_firstkey (binding[i]->action), KEYS_KEYLEN);
+      fmtkey = keys_format_label (key, KEYS_KEYLEN);
+      custom_apply_attr (win, ATTR_HIGHEST);
+      mvwprintw (win, 0, KEY_POS, fmtkey);
+      if (i + 1 != last_key)
+        {
+          strncpy (key, keys_action_firstkey (binding[i + 1]->action),
+                   KEYS_KEYLEN);
+          fmtkey = keys_format_label (key, KEYS_KEYLEN);
+          mvwprintw (win, 1, KEY_POS, fmtkey);
+        }
+      custom_remove_attr (win, ATTR_HIGHEST);
+      mvwprintw (win, 0, LABEL_POS, binding[i]->label);
+      if (i + 1 != last_key)
+	mvwprintw (win, 1, LABEL_POS, binding[i + 1]->label);
+      j++;
+    }
+  wnoutrefresh (win);
+}
+
+/*
+ * Display information about the given key.
+ * (could not add the keys descriptions to keydef variable, because of i18n).
+ */
+void
+keys_popup_info (keys_e key)
+{
+  char *info[NBKEYS];
+  WINDOW *infowin;
+  
+  info[KEY_GENERIC_ESCAPE] =
+    _("Cancel the ongoing action.");
+  info[KEY_GENERIC_CREDITS] =
+    _("Print general information about calcurse's authors, license, etc.");
+  info[KEY_GENERIC_HELP] =
+    _("Display hints whenever some help screens are available.");
+  info[KEY_GENERIC_QUIT] =
+    _("Exit from the current menu, or quit calcurse.");
+  info[KEY_GENERIC_SAVE] =
+    _("Save calcurse data.");
+  info[KEY_GENERIC_CHANGE_VIEW] =
+    _("Select next panel in calcurse main screen.");
+  info[KEY_GENERIC_IMPORT] =
+    _("Import data from an external file.");
+  info[KEY_GENERIC_EXPORT] =
+    _("Export data to a new file format.");
+  info[KEY_GENERIC_GOTO] =
+    _("Select the day to go to.");
+  info[KEY_GENERIC_OTHER_CMD] =
+    _("Show next possible actions inside status bar.");
+  info[KEY_GENERIC_CONFIG_MENU] =
+    _("Enter the configuration menu.");
+  info[KEY_GENERIC_REDRAW] =
+    _("Redraw calcurse's screen.");
+  info[KEY_GENERIC_ADD_APPT] =
+    _("Add an appointment, whichever panel is currently selected.");
+  info[KEY_GENERIC_ADD_TODO] =
+    _("Add a todo item, whichever panel is currently selected.");
+  info[KEY_GENERIC_NEXT_DAY] =
+    _("Move to next day in calendar, whichever panel is currently selected.");
+  info[KEY_GENERIC_PREV_DAY] =
+    _("Move to previous day in calendar, whichever panel is currently "
+      "selected.");
+  info[KEY_GENERIC_NEXT_WEEK] =
+    _("Move to next week in calendar, whichever panel is currently selected.");
+  info[KEY_GENERIC_PREV_WEEK] =
+    _("Move to previous week in calendar, whichever panel is currently "
+      "selected");
+  info[KEY_GENERIC_SCROLL_DOWN] =
+    _("Scroll window down (e.g. when displaying text inside a popup window).");
+  info[KEY_GENERIC_SCROLL_UP] =
+    _("Scroll window up (e.g. when displaying text inside a popup window).");
+  info[KEY_GENERIC_GOTO_TODAY] =
+    _("Go to today, whichever panel is selected.");
+  info[KEY_MOVE_RIGHT] =
+    _("Move to the right.");
+  info[KEY_MOVE_LEFT] =
+    _("Move to the left.");
+  info[KEY_MOVE_DOWN] =
+    _("Move down.");
+  info[KEY_MOVE_UP] =
+    _("Move up.");
+  info[KEY_START_OF_WEEK] =
+    _("Select the first day of the current week when inside the calendar "
+      "panel.");
+  info[KEY_END_OF_WEEK] =
+    _("Select the last day of the current week when inside the calendar "
+      "panel.");
+  info[KEY_ADD_ITEM] =
+    _("Add an item to the currently selected panel.");
+  info[KEY_DEL_ITEM] =
+    _("Delete the currently selected item.");
+  info[KEY_EDIT_ITEM] =
+    _("Edit the currently seleted item.");
+  info[KEY_VIEW_ITEM] =
+    _("Display the currently selected item inside a popup window.");
+  info[KEY_FLAG_ITEM] =
+    _("Flag the currently selected item as important.");
+  info[KEY_REPEAT_ITEM] =
+    _("Repeat an item");
+  info[KEY_EDIT_NOTE] =
+    _("Attach (or edit if one exists) a note to the currently selected item");
+  info[KEY_VIEW_NOTE] =
+    _("View the note attached to the currently selected item.");
+  info[KEY_RAISE_PRIORITY] =
+    _("Raise a task priority inside the todo panel.");
+  info[KEY_LOWER_PRIORITY] =
+    _("Lower a task priority inside the todo panel.");    
+    
+  if (key < 0 || key > NBKEYS)
+    return;
+
+#define WINROW 10
+#define WINCOL (col - 4)
+  infowin = popup (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2,
+                   keydef[key].label, info[key], 1);
+  keys_getch (infowin);
+  delwin (infowin);
+#undef WINROW
+#undef WINCOL
+}
diff --git a/src/keys.h b/src/keys.h
index ef9faa4..4928def 100755
--- a/src/keys.h
+++ b/src/keys.h
@@ -1,4 +1,4 @@
-/*	$calcurse: keys.h,v 1.3 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: keys.h,v 1.4 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -28,10 +28,13 @@
 #define CALCURSE_KEYS_H
 
 #define CTRLVAL   0x1F
-#define TAB       9
+#define CTRL(x)                 ((x) & CTRLVAL)
+#define ESCAPE		        27
+#define TAB       		9
 
-#define CTRL(x)         ((x) & CTRLVAL)
-#define ESCAPE		27
+#define KEYS_KEYLEN		3 /* length of each keybinding */  
+#define KEYS_LABELEN		8 /* length of command description */
+#define KEYS_CMDS_PER_LINE	6 /* max number of commands per line */
 
 typedef enum
   {
@@ -79,15 +82,25 @@ typedef enum
   }
 keys_e;
 
+typedef struct {
+  char    *label;
+  keys_e   action;
+} binding_t;
+
 void    keys_init (void);
 void    keys_dump_defaults (char *);
 char   *keys_get_label (keys_e);
+keys_e  keys_get_action (int);
 keys_e  keys_getch (WINDOW *win);
 int     keys_assign_binding (int, keys_e);
 void    keys_remove_binding (int, keys_e);
 int     keys_str2int (char *);
 char   *keys_int2str (int);
+int     keys_action_count_keys (keys_e);
 char   *keys_action_firstkey (keys_e);
+char   *keys_action_nkey (keys_e, int);
 char   *keys_action_allkeys (keys_e);
+void    keys_display_bindings_bar (WINDOW *, binding_t **, int, int);
+void    keys_popup_info (keys_e);
 
 #endif /* CALCURSE_KEYS_H */
diff --git a/src/notify.c b/src/notify.c
index 7c1108a..67f96db 100755
--- a/src/notify.c
+++ b/src/notify.c
@@ -1,4 +1,4 @@
-/*	$calcurse: notify.c,v 1.28 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: notify.c,v 1.29 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -479,7 +479,7 @@ notify_print_options (WINDOW *optwin, int col)
   x = x_pos + x_offset + l;
   mvwprintw (optwin, y_pos, x_pos, "[1] %s", opt[SHOW].name);
   erase_window_part (optwin, x, y_pos, maxcol, y_pos);
-  print_option_incolor (optwin, nbar->show, y_pos, x);
+  print_bool_option_incolor (optwin, nbar->show, y_pos, x);
   mvwprintw (optwin, y_pos + 1, x_pos, opt[SHOW].desc);
 
   for (i = 1; i < NB_OPT; i++)
diff --git a/src/utils.c b/src/utils.c
index caec3af..2b8e5e1 100755
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.c,v 1.53 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: utils.c,v 1.54 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -45,12 +45,6 @@
 #define NB_TOD_CMDS	30	/* same thing while in todo view */
 #define TOTAL_CMDS	NB_CAL_CMDS + NB_APP_CMDS + NB_TOD_CMDS
 #define CMDS_PER_LINE	6	/* max number of commands per line */  
-#define KEY_LENGTH	4	/* length of each keybinding + one space */
-
-typedef struct {
-  char    *label;
-  keys_e   action;
-} binding_t;
 
 static unsigned status_page;
 
@@ -122,10 +116,7 @@ warnbox (const char *msg)
     return;
   strncpy (displmsg, msg, MSGLEN);
   warnwin = popup (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2,
-                   "/!\\");
-  custom_apply_attr (warnwin, ATTR_HIGHEST);
-  mvwprintw (warnwin, 5, (WINCOL - strlen (displmsg)) / 2, "%s", displmsg);
-  custom_remove_attr (warnwin, ATTR_HIGHEST);
+                   "/!\\", displmsg, 1);
   wrefresh (warnwin);
   keys_getch (warnwin);
   delwin (warnwin);
@@ -172,24 +163,30 @@ erase_window_part (WINDOW *win, int first_col, int first_row, int last_col,
 
 /* draws a popup window */
 WINDOW *
-popup (int pop_row, int pop_col, int pop_y, int pop_x, char *pop_lab)
+popup (int pop_row, int pop_col, int pop_y, int pop_x, char *title, char *msg,
+       int hint)
 {
-  char *txt_pop = _("Press any key to continue...");
+  char *any_key = _("Press any key to continue...");
   char label[BUFSIZ];
   WINDOW *popup_win;
+  const int MSGXPOS = 5;
 
   popup_win = newwin (pop_row, pop_col, pop_y, pop_x);
   keypad (popup_win, TRUE);
   custom_apply_attr (popup_win, ATTR_HIGHEST);
   box (popup_win, 0, 0);
-  snprintf (label, BUFSIZ, "%s", pop_lab);
+  snprintf (label, BUFSIZ, "%s", title);
   wins_show (popup_win, label);
-  mvwprintw (popup_win, pop_row - 2, pop_col - (strlen (txt_pop) + 1), "%s",
-	     txt_pop);
+  if (msg)
+    mvwprintw (popup_win, MSGXPOS, (pop_col - strlen (msg)) / 2, "%s", msg);
+  if (hint)
+    mvwprintw (popup_win, pop_row - 2, pop_col - (strlen (any_key) + 1), "%s",
+               any_key);
   custom_remove_attr (popup_win, ATTR_HIGHEST);
-  wnoutrefresh (popup_win);
+  wrefresh (popup_win);
   doupdate ();
-  return (popup_win);
+  
+  return popup_win;
 }
 
 /* prints in middle of a panel */
@@ -442,32 +439,6 @@ is_all_digit (char *string)
   return (all_digit);
 }
 
-/* Need this to display keys properly inside status bar. */
-static char *
-format_key (char *key)
-{
-  static char fmtkey[KEY_LENGTH];
-  
-  switch (strlen (key))
-    {
-    case 0:
-      snprintf (fmtkey, KEY_LENGTH, "  ?");
-    case 1:
-      snprintf (fmtkey, KEY_LENGTH, "  %s", key);
-      break;
-    case 2:
-      snprintf (fmtkey, KEY_LENGTH, " %s", key);
-      break;
-    case 3:
-      snprintf (fmtkey, KEY_LENGTH, "%s", key);
-      break;
-    default:
-      snprintf (fmtkey, KEY_LENGTH, "%c%c.", key[0], key[1]);
-      /* NOTREACHED */
-    }
-  return fmtkey;
-}
-
 /* 
  * Draws the status bar. 
  * To add a keybinding, insert a new binding_t item, add it in the *binding
@@ -479,7 +450,7 @@ status_bar (void)
 {
 #define NB_PANELS	3	/* 3 panels: CALENDAR, APPOINTMENT, TODO */
   window_e which_pan;
-  int cmd_length, space_between_cmds, start, end, i, j;
+  int start, end;
   const int pos[NB_PANELS + 1] =
       { 0, NB_CAL_CMDS, NB_CAL_CMDS + NB_APP_CMDS, TOTAL_CMDS };
 
@@ -533,44 +504,11 @@ status_bar (void)
     &gnweek, &gpweek, &togo, &othr, &today, &conf, &appt, &todo, &crdts, &othr
   };
 
-#define LABEL_LENGTH	8	/* length of command description */  
-  /* Total length of a command. */
-  cmd_length = KEY_LENGTH + LABEL_LENGTH;
-  space_between_cmds = floor (col / CMDS_PER_LINE - cmd_length);
-  cmd_length += space_between_cmds;
-
   /* Drawing the keybinding with attribute and label without. */
-  erase_status_bar ();
   which_pan = wins_slctd ();
-  start = pos[which_pan] + 2 * CMDS_PER_LINE * (status_page - 1);
-  end = MIN (start + 2 * CMDS_PER_LINE, pos[which_pan + 1]);
-  j = 0;
-  for (i = start; i < end; i += 2)
-    {
-      char key[KEY_LENGTH], *fmtkey;
-
-      strncpy (key, keys_action_firstkey (binding[i]->action), KEY_LENGTH);
-      fmtkey = format_key (key);
-      custom_apply_attr (win[STA].p, ATTR_HIGHEST);
-      mvwprintw (win[STA].p, 0, j * cmd_length, fmtkey);
-      if (i + 1 != end)
-        {
-          strncpy (key, keys_action_firstkey (binding[i + 1]->action),
-                   KEY_LENGTH);
-          fmtkey = format_key (key);
-          mvwprintw (win[STA].p, 1, j * cmd_length, fmtkey);
-        }
-      custom_remove_attr (win[STA].p, ATTR_HIGHEST);
-      mvwprintw (win[STA].p, 0, j * cmd_length + KEY_LENGTH,
-		 binding[i]->label);
-      if (i + 1 != end)
-	mvwprintw (win[STA].p, 1, j * cmd_length + KEY_LENGTH,
-		   binding[i + 1]->label);
-      j++;
-    }
-  wnoutrefresh (win[STA].p);
-#undef LABEL_LENGTH
-#undef NB_PANELS
+  start = pos[which_pan] + 2 * KEYS_CMDS_PER_LINE * (status_page - 1);
+  end = MIN (start + 2 * KEYS_CMDS_PER_LINE, pos[which_pan + 1]);
+  keys_display_bindings_bar (win[STA].p, binding, start, end);
 }
 
 long
@@ -810,7 +748,7 @@ item_in_popup (char *saved_a_start, char *saved_a_end, char *msg,
   const int padl = winl - 2, padw = winw - margin_left;
 
   pad = newpad (padl, padw);
-  popup_win = popup (winl, winw, 1, 2, pop_title);
+  popup_win = popup (winl, winw, 1, 2, pop_title, (char *)0, 1);
   if (strncmp (pop_title, _("Appointment"), 11) == 0)
     {
       mvwprintw (popup_win, margin_top, margin_left, "- %s -> %s",
@@ -923,7 +861,7 @@ mystrtol (const char *str)
 
 /* Print the given option value with appropriate color. */
 void
-print_option_incolor (WINDOW *win, bool option, int pos_y, int pos_x)
+print_bool_option_incolor (WINDOW *win, bool option, int pos_y, int pos_x)
 {
   int color = 0;
   char option_value[BUFSIZ] = "";
diff --git a/src/utils.h b/src/utils.h
index 13f8057..3f4cd0a 100755
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.h,v 1.38 2008/11/16 17:42:53 culot Exp $	*/
+/*	$calcurse: utils.h,v 1.39 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -118,7 +118,7 @@ void    warnbox (const char *);
 void    status_mesg (char *, char *);
 void    erase_status_bar (void);
 void    erase_window_part (WINDOW *, int, int, int, int);
-WINDOW *popup (int, int, int, int, char *);
+WINDOW *popup (int, int, int, int, char *, char *, int);
 void    print_in_middle (WINDOW *, int, int, int, char *);
 int     getstring (WINDOW *, char *, int, int, int);
 int     updatestring (WINDOW *, char **, int, int);
@@ -141,7 +141,7 @@ long    get_today (void);
 long    now (void);
 char   *mycpy (const char *);
 long    mystrtol (const char *);
-void    print_option_incolor (WINDOW *, bool, int, int);
+void    print_bool_option_incolor (WINDOW *, bool, int, int);
 char   *new_tempfile (const char *, int);
 void    erase_note (char **, erase_flag_e);
 int     parse_date (char *, int, int *, int *, int *);
diff --git a/src/wins.c b/src/wins.c
index f76bc36..b15d5b4 100755
--- a/src/wins.c
+++ b/src/wins.c
@@ -1,4 +1,4 @@
-/*	$calcurse: wins.c,v 1.17 2008/09/20 12:47:06 culot Exp $	*/
+/*	$calcurse: wins.c,v 1.18 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -170,18 +170,18 @@ wins_scrollwin_display (scrollwin_t *sw)
 }
 
 void
-wins_scrollwin_up (scrollwin_t *sw)
+wins_scrollwin_up (scrollwin_t *sw, int amount)
 {
   if (sw->first_visible_line > 0)
-    sw->first_visible_line--;
+    sw->first_visible_line -= amount;
 }
 
 void
-wins_scrollwin_down (scrollwin_t *sw)
+wins_scrollwin_down (scrollwin_t *sw, int amount)
 {
   if (sw->total_lines
       > (sw->first_visible_line + sw->win.h - sw->pad.y - 1))
-    sw->first_visible_line++;
+    sw->first_visible_line += amount;
 }
 
 /* 
diff --git a/src/wins.h b/src/wins.h
index b23c28f..415d479 100755
--- a/src/wins.h
+++ b/src/wins.h
@@ -1,4 +1,4 @@
-/*	$calcurse: wins.h,v 1.9 2008/04/19 09:22:14 culot Exp $	*/
+/*	$calcurse: wins.h,v 1.10 2008/11/23 20:38:56 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -72,8 +72,8 @@ void         wins_init (void);
 void         wins_scrollwin_init (scrollwin_t *);
 void         wins_scrollwin_delete (scrollwin_t *);
 void         wins_scrollwin_display (scrollwin_t *);
-void         wins_scrollwin_up (scrollwin_t *);
-void         wins_scrollwin_down (scrollwin_t *);
+void         wins_scrollwin_up (scrollwin_t *, int);
+void         wins_scrollwin_down (scrollwin_t *, int);
 void         wins_reinit (void);
 void         wins_show (WINDOW *, char *);
 void         wins_get_config (void);
-- 
cgit v1.2.3-70-g09d2