<<< Date Index >>>     <<< Thread Index >>>

[PATCH] Add curses dialogs for sorting choice



Hi,

the attached patch adds mutt_multi_choice_dlg() for getting a choice out of multiple via a dialog rather than a prompt in the status line.

Some notes about it:

1) I'm not a curses export and this patch is untested for slang.

2) For now it uses the status color which probably should be changed.

3) It likely causes trouble for window resizing (see 1 :)

4) Only the sorting choice is making use of it for now. Though I don't think all consumers of mutt_multi_choice() should use it, some more should (or maybe completely obsolete it for consistency? If so, what about 3rd party patches that could use it?)

5) There's no documentation yet. As it respects $ascii_chars, at least its documentation needs to be updated. Maybe it's a good idea to add some words about mutt UI concepts to the manual mentioning these dialogs as well...

Anyway, it's still a proof-of-concept only:

6) Not all calls where a "windowed"-one in curses exists where modified, I don't think we need more than I did for just this patch, but the code would look IMHO better if all relevant calls were adjusted with defaults to stdscr.

7) I don't fully like the way mutt_multi_choice_dlg() gets its arguments especially when thinking about translators. An option could be to add some bloat and do what GUIs usually do: add a "&" modifier to identify the key in the string, e.g. 'by &date' gets split into 'by date' description and the 'd' key. But that would require all keys being present in the description which I'm not sure of.

8) More on arguments: Some sanity checks before accessing the arrays maybe could be useful.

  bye, Rocco
--
:wq!
diff --git a/commands.c b/commands.c
index 85a67b2..7840a2c 100644
--- a/commands.c
+++ b/commands.c
@@ -502,11 +502,21 @@ void mutt_print_message (HEADER *h)
 int mutt_select_sort (int reverse)
 {
   int method = Sort; /* save the current method in case of abort */
-
-  switch (mutt_multi_choice (reverse ?
-                            _("Rev-Sort 
(d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: ") :
-                            _("Sort 
(d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: "),
-                            _("dfrsotuzcp")))
+  const char* choices[] = {
+    N_("by date"),
+    N_("by sender"),
+    N_("by receiver"),
+    N_("by subject"),
+    N_("by recipient"),
+    N_("by thread"),
+    N_("don't sort"),
+    N_("by size"),
+    N_("by score"),
+    N_("by spam status")
+  };
+
+  switch (mutt_multi_choice_dlg (10, reverse ? _("Reverse sort...") : 
_("Sort..."),
+                            choices, _("dfrsotuzcp")))
   {
   case -1: /* abort - don't resort */
     return -1;
diff --git a/curs_lib.c b/curs_lib.c
index c800456..0722492 100644
--- a/curs_lib.c
+++ b/curs_lib.c
@@ -48,8 +48,12 @@ size_t UngetCount = 0;
 static size_t UngetBufLen = 0;
 static event_t *KeyEvent;
 
-void mutt_refresh (void)
+void mutt_wrefresh (WINDOW *win)
 {
+
+  if (win == NULL)
+    win = stdscr;
+
   /* don't refresh when we are waiting for a child. */
   if (option (OPTKEEPQUIET))
     return;
@@ -59,7 +63,7 @@ void mutt_refresh (void)
     return;
 
   /* else */
-  refresh ();
+  wrefresh (win);
 }
 
 /* Make sure that the next refresh does a full refresh.  This could be
@@ -76,11 +80,14 @@ void mutt_need_hard_redraw (void)
   }
 }
 
-event_t mutt_getch (void)
+event_t mutt_wgetch (WINDOW* win)
 {
   int ch;
   event_t err = {-1, OP_NULL }, ret;
 
+  if (win == NULL)
+    win = stdscr;
+
   if (!option(OPTUNBUFFEREDINPUT) && UngetCount)
     return (KeyEvent[--UngetCount]);
 
@@ -92,7 +99,7 @@ event_t mutt_getch (void)
   ch = KEY_RESIZE;
   while (ch == KEY_RESIZE)
 #endif /* KEY_RESIZE */
-    ch = getch ();
+    ch = wgetch (win);
   mutt_allow_interrupt (0);
 
   if (SigInt)
@@ -582,18 +589,16 @@ void mutt_curs_set (int cursor)
 }
 #endif
 
-int mutt_multi_choice (char *prompt, char *letters)
+static int get_choice (WINDOW *win, const char *letters)
 {
   event_t ch;
   int choice;
   char *p;
 
-  mvaddstr (LINES - 1, 0, prompt);
-  clrtoeol ();
   FOREVER
   {
-    mutt_refresh ();
-    ch  = mutt_getch ();
+    mutt_wrefresh (win);
+    ch  = mutt_wgetch (win);
     if (ch.ch == -1 || CI_is_return (ch.ch))
     {
       choice = -1;
@@ -616,11 +621,88 @@ int mutt_multi_choice (char *prompt, char *letters)
     }
     BEEP ();
   }
+  return choice;
+}
+
+int mutt_multi_choice (const char *prompt, const char *letters)
+{
+  int choice;
+
+  mvaddstr (LINES - 1, 0, prompt);
+  clrtoeol ();
+  choice = get_choice (stdscr, letters);
   CLEARLINE (LINES - 1);
   mutt_refresh ();
   return choice;
 }
 
+int mutt_multi_choice_dlg (int cnt, const char* title, const char **prompts, 
const char *letters)
+{
+  int choice;
+  WINDOW* win;
+  int w = 0, h, x, y, tpos, i;
+  size_t tw,ta;
+  const char* abort;
+
+  abort = _("abort");
+
+  /* find longest string */
+  ta = mutt_strwidth (abort);
+  tw = mutt_strwidth (title);
+  w = tw = ta > tw ? ta : tw;
+  for (i = 0; i < cnt; i++)
+  {
+    /* +4 for adding 'XX - ' to prompt */
+    size_t l = mutt_strwidth (prompts[i]) + 5;
+    if (l > w)
+      w = l;
+  }
+
+  /* window: +2 rows for and +4 cols for border, 1 row for abort */
+  h = cnt + 3;
+  x = (COLS - w) / 2;
+  y = (LINES - h) / 2;
+
+  /* create window with default ACS or ascii chars */
+  win = newwin (h, w + 4, y, x);
+  wbkgd (win, ColorDefs[MT_COLOR_STATUS]);
+  if (option (OPTASCIICHARS))
+    wborder (win, '|', '|', '-', '-', '+', '+', '+', '+');
+  else
+    box (win, 0, 0);
+
+  /* overwrite part of top border with space+title+space */
+  tpos = (w + 4 - tw) / 2;
+  mvwaddch (win, 0, tpos - 1, ' ');
+  mvwaddstr (win, 0, tpos, title);
+  mvwaddch (win, 0, tpos + tw, ' ');
+
+  /* add choices, use _() as we usually use N_() to init INTL array */
+  for (i = 0; i < cnt; i++)
+  {
+    wmove (win, 1 + i, 1);
+    waddch (win, ' ');
+    waddch (win, letters[i]);
+    waddstr (win, "  - ");
+    mutt_wpaddstr (win, w - 5, _(prompts[i]));
+  }
+
+  wmove (win, 1 + i, 1);
+  mvwaddstr (win, i + 1, 1, " ^G - ");
+  mutt_wpaddstr (win, w - 5, abort);
+
+  doupdate();
+
+  choice = get_choice (win, letters);
+
+  delwin (win);
+  /* we have to use some force in order to make the window
+   * disappear even when cancelled with ^G */
+  touchwin (stdscr);
+  doupdate ();
+  return choice;
+}
+
 /*
  * addwch would be provided by an up-to-date curses library
  */
@@ -785,11 +867,11 @@ void mutt_format_s_tree (char *dest,
 }
 
 /*
- * mutt_paddstr (n, s) is almost equivalent to
- * mutt_format_string (bigbuf, big, n, n, FMT_LEFT, ' ', s, big, 0), addstr 
(bigbuf)
+ * mutt_wpaddstr (w, n, s) is almost equivalent to
+ * mutt_format_string (bigbuf, big, n, n, FMT_LEFT, ' ', s, big, 0), waddstr 
(w, bigbuf)
  */
 
-void mutt_paddstr (int n, const char *s)
+void mutt_wpaddstr (WINDOW* win, int n, const char *s)
 {
   wchar_t wc;
   int w;
@@ -797,6 +879,9 @@ void mutt_paddstr (int n, const char *s)
   size_t len = mutt_strlen (s);
   mbstate_t mbstate;
 
+  if (win == NULL)
+    win = stdscr;
+
   memset (&mbstate, 0, sizeof (mbstate));
   for (; len && (k = mbrtowc (&wc, s, len, &mbstate)); s += k, len -= k)
   {
@@ -814,12 +899,12 @@ void mutt_paddstr (int n, const char *s)
     {
       if (w > n)
        break;
-      addnstr ((char *)s, k);
+      waddnstr (win, (char *)s, k);
       n -= w;
     }
   }
   while (n-- > 0)
-    addch (' ');
+    waddch (win, ' ');
 }
 
 /*
diff --git a/mutt_curses.h b/mutt_curses.h
index 536f8a3..bd7b31c 100644
--- a/mutt_curses.h
+++ b/mutt_curses.h
@@ -93,14 +93,22 @@ void mutt_curs_set (int);
 #define CI_is_return(c) ((c) == '\r' || (c) == '\n')
 #endif
 
-event_t mutt_getch (void);
+event_t mutt_wgetch (WINDOW *);
+#define mutt_getch()           mutt_wgetch (stdscr)
 
 void mutt_endwin (const char *);
 void mutt_flushinp (void);
-void mutt_refresh (void);
+
+void mutt_wrefresh (WINDOW *);
+#define mutt_refresh()         mutt_wrefresh (stdscr)
 void mutt_resize_screen (void);
 void mutt_ungetch (int, int);
 void mutt_need_hard_redraw (void);
+void mutt_wpaddstr (WINDOW *, int, const char *);
+#define mutt_paddstr(N,S)      mutt_wpaddstr (stdscr, N, S)
+
+int mutt_multi_choice_dlg (int cnt, const char *title, const char **prompt, 
const char *letters);
+int mutt_multi_choice (const char *prompt, const char *letters);
 
 /* ----------------------------------------------------------------------------
  * Support for color
diff --git a/protos.h b/protos.h
index 2b944e4..fb2d2b8 100644
--- a/protos.h
+++ b/protos.h
@@ -222,7 +222,6 @@ void mutt_message_to_7bit (BODY *, FILE *);
 #define mutt_mktemp(a) _mutt_mktemp (a, __FILE__, __LINE__)
 void _mutt_mktemp (char *, const char *, int);
 void mutt_normalize_time (struct tm *);
-void mutt_paddstr (int, const char *);
 void mutt_parse_mime_message (CONTEXT *ctx, HEADER *);
 void mutt_parse_part (FILE *, BODY *);
 void mutt_perror (const char *);
@@ -323,7 +322,6 @@ int mutt_lookup_mime_type (BODY *, const char *);
 int mutt_match_rx_list (const char *, RX_LIST *);
 int mutt_match_spam_list (const char *, SPAM_LIST *, char *, int);
 int mutt_messages_in_thread (CONTEXT *, HEADER *, int);
-int mutt_multi_choice (char *prompt, char *letters);
 int mutt_needs_mailcap (BODY *);
 int mutt_num_postponed (int);
 int mutt_parse_bind (BUFFER *, BUFFER *, unsigned long, BUFFER *);