This is a series of 8+ patches, centralizing Mutt screen drawing
inside windows (mutt_window_t structures).

Currently, the screen drawing and cursor positioning logic is
distributed all over the code, resulting in many files having the same
logic of where the help, status, message windows are.  Additionally,
the code directly uses move and mvadd*/mvprint* functions, which means
if the layouts are changed, the row/column computation logic needs to
be changed all over the place.

The patch creates a (very simple) mutt_window_t structure and
functions for moving, addch/str/printw, along with clearing the line.
The windows keep track of where they are on the screen, allowing the
Mutt code to simply position elements relative to the window.

During curses initalization, and when the window is resized, the
window sizes and positions and recomputed.  Also, a new option flags,
R_REFLOW is added for options that need to force a reflow when they are
changed.

-- 
Kevin J. McCarthy
GPG Fingerprint: 8975 A9B3 3AA3 7910 385C  5308 ADEF 7684 8031 6BDA
http://www.8t8.us/configs/gpg-key-transition-statement.txt
# HG changeset patch
# User Kevin McCarthy <ke...@8t8.us>
# Date 1461083906 25200
#      Tue Apr 19 09:38:26 2016 -0700
# Node ID 404cf1094ee708fc85044b95d9f274e9acbc3565
# Parent  9a9c515e09d3c36bf4804958a4a3a66b6f0bc2e2
Add window structures to use for screen layout.

This is a series of 11 patches, centralizing Mutt screen drawing
inside windows (mutt_window_t structures).

Currently, the screen drawing and cursor positioning logic is
distributed all over the code, resulting in many files having the same
logic of where the help, status, message windows are.  Additionally,
the code directly uses move and mvadd*/mvprint* functions, which means
if the layouts are changed, the row/column computation logic needs to
be changed all over the place.

The patch creates a (very simple) mutt_window_t structure and
functions for moving, addch/str/printw, along with clearing the line.
The windows keep track of where they are on the screen, allowing the
Mutt code to simply position elements relative to the window.

During curses initalization, and when the window is resized, the
window sizes and positions and recomputed.  Also, a new option flags,
R_REFLOW is added for options that need to force a reflow when they are changed.

diff --git a/curs_lib.c b/curs_lib.c
--- a/curs_lib.c
+++ b/curs_lib.c
@@ -58,16 +58,21 @@
 
 /* These are used in all other "normal" situations, and are not
  * ignored when setting OPTIGNOREMACROEVENTS
  */
 static size_t UngetCount = 0;
 static size_t UngetLen = 0;
 static event_t *UngetKeyEvents;
 
+mutt_window_t *MuttHelpWindow = NULL;
+mutt_window_t *MuttIndexWindow = NULL;
+mutt_window_t *MuttStatusWindow = NULL;
+mutt_window_t *MuttMessageWindow = NULL;
+
 void mutt_refresh (void)
 {
   /* don't refresh when we are waiting for a child. */
   if (option (OPTKEEPQUIET))
     return;
 
   /* don't refresh in the middle of macros unless necessary */
   if (UngetCount && !option (OPTFORCEREFRESH))
@@ -474,16 +479,126 @@
     }
   }
 
 out:
   if (pos >= progress->size)
     mutt_clear_error ();
 }
 
+void mutt_init_windows ()
+{
+  MuttHelpWindow = safe_calloc (sizeof (mutt_window_t), 1);
+  MuttIndexWindow = safe_calloc (sizeof (mutt_window_t), 1);
+  MuttStatusWindow = safe_calloc (sizeof (mutt_window_t), 1);
+  MuttMessageWindow = safe_calloc (sizeof (mutt_window_t), 1);
+
+  mutt_reflow_windows ();
+}
+
+void mutt_free_windows ()
+{
+  FREE (&MuttHelpWindow);
+  FREE (&MuttIndexWindow);
+  FREE (&MuttStatusWindow);
+  FREE (&MuttMessageWindow);
+}
+
+void mutt_reflow_windows (void)
+{
+  if (option (OPTNOCURSES))
+    return;
+
+  dprint (2, (debugfile, "In mutt_reflow_windows\n"));
+
+  if (option (OPTHELP))
+    MuttHelpWindow->rows = 1;
+  else
+    MuttHelpWindow->rows = 0;
+  MuttHelpWindow->cols = COLS;
+  MuttHelpWindow->row_offset = option (OPTSTATUSONTOP) ? LINES - 2 : 0;
+  MuttHelpWindow->col_offset = 0;
+
+  MuttStatusWindow->rows = 1;
+  MuttStatusWindow->cols = COLS;
+  MuttStatusWindow->row_offset = option (OPTSTATUSONTOP) ? 0 : LINES - 2;
+  MuttStatusWindow->col_offset = 0;
+
+  MuttMessageWindow->rows = 1;
+  MuttMessageWindow->cols = COLS;
+  MuttMessageWindow->row_offset = LINES - 1;
+  MuttMessageWindow->col_offset = 0;
+
+  MuttIndexWindow->rows = LINES - MuttHelpWindow->rows - 
MuttStatusWindow->rows -
+                          MuttMessageWindow->rows;
+  MuttIndexWindow->cols = COLS;
+  MuttIndexWindow->row_offset = option (OPTSTATUSONTOP) ? 
MuttStatusWindow->rows :
+                                                          MuttHelpWindow->rows;
+  MuttIndexWindow->col_offset = 0;
+}
+
+int mutt_window_move (mutt_window_t *win, int row, int col)
+{
+  return move (win->row_offset + row, win->col_offset + col);
+}
+
+int mutt_window_mvaddch (mutt_window_t *win, int row, int col, const chtype ch)
+{
+  return mvaddch (win->row_offset + row, win->col_offset + col, ch);
+}
+
+int mutt_window_mvaddstr (mutt_window_t *win, int row, int col, const char 
*str)
+{
+  return mvaddstr (win->row_offset + row, win->col_offset + col, str);
+}
+
+int mutt_window_mvprintw (mutt_window_t *win, int row, int col, const char 
*fmt, ...)
+{
+  va_list ap;
+  int rv;
+
+  if ((rv = mutt_window_move (win, row, col) != ERR))
+  {
+    va_start (ap, fmt);
+    rv = vw_printw (stdscr, fmt, ap);
+    va_end (ap);
+  }
+
+  return rv;
+}
+
+/* Assumes the cursor has already been positioned within the
+ * window.
+ */
+void mutt_window_clrtoeol (mutt_window_t *win)
+{
+  int row, col, curcol;
+
+  if (win->col_offset + win->cols == COLS)
+    clrtoeol ();
+  else
+  {
+    getyx (stdscr, row, col);
+    curcol = col;
+    while (curcol < win->col_offset + win->cols)
+    {
+      addch (' ');
+      curcol++;
+    }
+    move (row, col);
+  }
+}
+
+void mutt_window_clearline (mutt_window_t *win, int row)
+{
+  mutt_window_move (win, row, 0);
+  mutt_window_clrtoeol (win);
+}
+
+
 void mutt_show_error (void)
 {
   if (option (OPTKEEPQUIET))
     return;
   
   SETCOLOR (option (OPTMSGERR) ? MT_COLOR_ERROR : MT_COLOR_MESSAGE);
   mvaddstr(LINES-1, 0, Errorbuf);
   NORMAL_COLOR;
diff --git a/init.c b/init.c
--- a/init.c
+++ b/init.c
@@ -1606,16 +1606,18 @@
   if (p->flags & R_RESORT_SUB)
     set_option (OPTSORTSUBTHREADS);
   if (p->flags & R_RESORT)
     set_option (OPTNEEDRESORT);
   if (p->flags & R_RESORT_INIT)
     set_option (OPTRESORTINIT);
   if (p->flags & R_TREE)
     set_option (OPTREDRAWTREE);
+  if (p->flags & R_REFLOW)
+    mutt_reflow_windows ();
 }
 
 static size_t escape_string (char *dst, size_t len, const char* src)
 {
   char* p = dst;
 
   if (!len)
     return 0;
@@ -2221,16 +2223,18 @@
       if (MuttVars[idx].flags & R_RESORT_SUB)
         set_option (OPTSORTSUBTHREADS);
       if (MuttVars[idx].flags & R_RESORT)
         set_option (OPTNEEDRESORT);
       if (MuttVars[idx].flags & R_RESORT_INIT)
         set_option (OPTRESORTINIT);
       if (MuttVars[idx].flags & R_TREE)
         set_option (OPTREDRAWTREE);
+      if (MuttVars[idx].flags & R_REFLOW)
+        mutt_reflow_windows ();
     }
   }
   return (r);
 }
 
 #define MAXERRS 128
 
 /* reads the specified initialization file.  returns -1 if errors were found
diff --git a/init.h b/init.h
--- a/init.h
+++ b/init.h
@@ -56,16 +56,17 @@
 /* forced redraw/resort types */
 #define R_NONE         0
 #define R_INDEX                (1<<0)
 #define R_PAGER                (1<<1)
 #define R_RESORT       (1<<2)  /* resort the mailbox */
 #define R_RESORT_SUB   (1<<3)  /* resort subthreads */
 #define R_RESORT_INIT  (1<<4)  /* resort from scratch */
 #define R_TREE         (1<<5)  /* redraw the thread tree */
+#define R_REFLOW        (1<<6)  /* reflow window layout */
 #define R_BOTH         (R_INDEX | R_PAGER)
 #define R_RESORT_BOTH  (R_RESORT | R_RESORT_SUB)
 
 struct option_t
 {
   char *option;
   short type;
   short flags;
@@ -972,17 +973,17 @@
   ** .pp
   ** When mutt is compiled with either gdbm or bdb4 as the header cache 
backend,
   ** this option changes the database page size.  Too large or too small
   ** values can waste space, memory, or CPU time. The default should be more
   ** or less optimal for most use cases.
   */
 #endif /* HAVE_GDBM || HAVE_DB4 */
 #endif /* USE_HCACHE */
-  { "help",            DT_BOOL, R_BOTH, OPTHELP, 1 },
+  { "help",            DT_BOOL, R_BOTH|R_REFLOW, OPTHELP, 1 },
   /*
   ** .pp
   ** When \fIset\fP, help lines describing the bindings for the major functions
   ** provided by each menu are displayed on the first line of the screen.
   ** .pp
   ** \fBNote:\fP The binding will not be displayed correctly if the
   ** function is bound to a sequence rather than a single keystroke.  Also,
   ** the help line may not be updated if a binding is changed while Mutt is
@@ -3282,17 +3283,17 @@
   ** by prefixing the sequence character with an underscore (``_'') sign.
   ** For example, if you want to display the local hostname in lowercase,
   ** you would use: ``\fC%_h\fP''.
   ** .pp
   ** If you prefix the sequence character with a colon (``:'') character, mutt
   ** will replace any dots in the expansion by underscores. This might be 
helpful
   ** with IMAP folders that don't like dots in folder names.
   */
-  { "status_on_top",   DT_BOOL, R_BOTH, OPTSTATUSONTOP, 0 },
+  { "status_on_top",   DT_BOOL, R_BOTH|R_REFLOW, OPTSTATUSONTOP, 0 },
   /*
   ** .pp
   ** Setting this variable causes the ``status bar'' to be displayed on
   ** the first line of the screen rather than near the bottom. If $$help
   ** is \fIset\fP, too it'll be placed at the bottom.
   */
   { "strict_threads",  DT_BOOL, R_RESORT|R_RESORT_INIT|R_INDEX, 
OPTSTRICTTHREADS, 0 },
   /*
diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -542,16 +542,17 @@
   noecho ();
 #if HAVE_TYPEAHEAD
   typeahead (-1);       /* simulate smooth scrolling */
 #endif
 #if HAVE_META
   meta (stdscr, TRUE);
 #endif
 init_extended_keys();
+  mutt_init_windows ();
 }
 
 #define M_IGNORE  (1<<0)       /* -z */
 #define M_BUFFY   (1<<1)       /* -Z */
 #define M_NOSYSRC (1<<2)       /* -n */
 #define M_RO      (1<<3)       /* -R */
 #define M_SELECT  (1<<4)       /* -y */
 
@@ -854,16 +855,17 @@
     }
   }
 
   if (sendflags & SENDPOSTPONED)
   {
     if (!option (OPTNOCURSES))
       mutt_flushinp ();
     ci_send_message (SENDPOSTPONED, NULL, NULL, NULL, NULL);
+    mutt_free_windows ();
     mutt_endwin (NULL);
   }
   else if (subject || msg || sendflags || draftFile || includeFile || attach ||
           optind < argc)
   {
     FILE *fin = NULL;
     FILE *fout = NULL;
     char buf[LONG_STRING];
@@ -1143,17 +1145,20 @@
     /* !edit_infile && draftFile will leave the tempfile around */
     if (tempfile)
     {
       unlink (tempfile);
       FREE (&tempfile);
     }
 
     if (!option (OPTNOCURSES))
+    {
+      mutt_free_windows ();
       mutt_endwin (NULL);
+    }
 
     if (rv)
       exit(1);
   }
   else
   {
     if (flags & M_BUFFY)
     {
@@ -1212,13 +1217,14 @@
     }
 #ifdef USE_IMAP
     imap_logout_all ();
 #endif
 #ifdef USE_SASL
     mutt_sasl_done ();
 #endif
     mutt_free_opts ();
+    mutt_free_windows ();
     mutt_endwin (Errorbuf);
   }
 
   exit (0);
 }
diff --git a/mutt_curses.h b/mutt_curses.h
--- a/mutt_curses.h
+++ b/mutt_curses.h
@@ -156,16 +156,41 @@
 void mutt_progress_init (progress_t* progress, const char *msg,
                         unsigned short flags, unsigned short inc,
                         long size);
 /* If percent is positive, it is displayed as percentage, otherwise
  * percentage is calculated from progress->size and pos if progress
  * was initialized with positive size, otherwise no percentage is shown */
 void mutt_progress_update (progress_t* progress, long pos, int percent);
 
+/* Windows for different parts of the screen */
+typedef struct
+{
+  int rows;
+  int cols;
+  int row_offset;
+  int col_offset;
+} mutt_window_t;
+
+extern mutt_window_t *MuttHelpWindow;
+extern mutt_window_t *MuttIndexWindow;
+extern mutt_window_t *MuttStatusWindow;
+extern mutt_window_t *MuttMessageWindow;
+
+void mutt_init_windows (void);
+void mutt_free_windows (void);
+void mutt_reflow_windows (void);
+int mutt_window_move (mutt_window_t *, int row, int col);
+int mutt_window_mvaddch (mutt_window_t *, int row, int col, const chtype ch);
+int mutt_window_mvaddstr (mutt_window_t *, int row, int col, const char *str);
+int mutt_window_mvprintw (mutt_window_t *, int row, int col, const char *fmt, 
...);
+void mutt_window_clrtoeol (mutt_window_t *);
+void mutt_window_clearline (mutt_window_t *, int row);
+
+
 static inline int mutt_term_width(short wrap)
 {
   if (wrap < 0)
     return COLS > -wrap ? COLS + wrap : COLS;
   else if (wrap)
     return wrap < COLS ? wrap : COLS;
   else
     return COLS;
diff --git a/resize.c b/resize.c
--- a/resize.c
+++ b/resize.c
@@ -71,9 +71,10 @@
   delwin (stdscr);
   SLsmg_reset_smg ();
   SLsmg_init_smg ();
   stdscr = newwin (0, 0, 0, 0);
   keypad (stdscr, TRUE);
 #else
   resizeterm (SLtt_Screen_Rows, SLtt_Screen_Cols);
 #endif
+  mutt_reflow_windows ();
 }

Attachment: signature.asc
Description: PGP signature

Reply via email to