ncurses 6.1 - patch 20180303
[ncurses.git] / test / movewindow.c
index e807a8a064b558ca6534efc447fea4408a7ee69d..b8e9e049602dcf0298a27ae3c60a418a6e20e44d 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 2006-2008,2010 Free Software Foundation, Inc.              *
+ * Copyright (c) 2006-2013,2017 Free Software Foundation, Inc.              *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
  * authorization.                                                           *
  ****************************************************************************/
 /*
- * $Id: movewindow.c,v 1.23 2010/05/01 19:11:55 tom Exp $
+ * $Id: movewindow.c,v 1.46 2017/12/23 21:36:59 tom Exp $
  *
  * Demonstrate move functions for windows and derived windows from the curses
  * library.
  *
- * Thomas Dickey - 2006/2/11
+ * Author: Thomas E. Dickey
  */
 /*
 derwin
 mvderwin
 subwin
 mvwin
+
+TODO:
+    add command to reset subwindow's origin to coincide with parent.
+    add command to delete subwindow (check if it has subwindows though)
  */
 
 #include <test.priv.h>
-#include <stdarg.h>
+
+#if HAVE_MVDERWIN && HAVE_MVWIN
+
+#include <popup_msg.h>
 
 #ifdef HAVE_XCURSES
 #undef derwin
 #endif
 
-#ifdef NCURSES_VERSION
+#if defined(NCURSES_VERSION) || defined(PDCURSES)
 #define CONST_FMT const
 #else
 #define CONST_FMT              /* nothing */
@@ -75,6 +82,14 @@ static void tail_line(CONST_FMT char *fmt,...) GCC_PRINTFLIKE(1, 2);
 static unsigned num_windows;
 static FRAME *all_windows;
 
+static void
+failed(const char *s)
+{
+    perror(s);
+    endwin();
+    ExitProgram(EXIT_FAILURE);
+}
+
 static void
 message(int lineno, CONST_FMT char *fmt, va_list argp)
 {
@@ -122,7 +137,12 @@ tail_line(CONST_FMT char *fmt,...)
  * Arrow keys move cursor, return location at current on non-arrow key.
  */
 static PAIR *
-selectcell(WINDOW *parent, int uli, int ulj, int lri, int lrj)
+selectcell(WINDOW *parent,
+          WINDOW *child,
+          int uli, int ulj,
+          int lri, int lrj,
+          bool relative,
+          bool * more)
 {
     static PAIR res;           /* result cell */
     int si = lri - uli + 1;    /* depth of the select area */
@@ -131,27 +151,49 @@ selectcell(WINDOW *parent, int uli, int ulj, int lri, int lrj)
 
     res.y = uli;
     res.x = ulj;
+
+    if (child != 0) {
+       if (relative) {
+           getparyx(child, i, j);
+       } else {
+           getbegyx(child, i, j);
+           i -= uli + getbegy(parent);
+           j -= ulj + getbegx(parent);
+       }
+    }
+
+    if (more)
+       *more = FALSE;
+
     for (;;) {
-       tail_line("Upper left [%2d,%2d] Lower right [%2d,%2d] -> %d,%d",
+       bool moved = FALSE;
+
+       tail_line("Upper left [%2d,%2d] Lower right [%2d,%2d] -> %d,%d -> %d,%d",
                  uli, ulj,
                  lri, lrj,
+                 i, j,
                  uli + i, ulj + j);
        wmove(parent, uli + i, ulj + j);
 
        switch (wgetch(parent)) {
        case KEY_UP:
            i += si - 1;
+           moved = TRUE;
            break;
        case KEY_DOWN:
            i++;
+           moved = TRUE;
            break;
        case KEY_LEFT:
            j += sj - 1;
+           moved = TRUE;
            break;
        case KEY_RIGHT:
            j++;
+           moved = TRUE;
            break;
        case QUIT:
+           /* FALLTHRU */
        case ESCAPE:
            return ((PAIR *) 0);
 #ifdef NCURSES_MOUSE_VERSION
@@ -161,22 +203,45 @@ selectcell(WINDOW *parent, int uli, int ulj, int lri, int lrj)
 
                getmouse(&event);
                if (event.y > uli && event.x > ulj) {
-                   i = event.y - uli;
-                   j = event.x - ulj;
+                   if (parent != stdscr) {
+                       i = event.y - getbegy(parent) - uli;
+                       j = event.x - getbegx(parent) - ulj;
+                   } else {
+                       i = event.y - uli;
+                       j = event.x - ulj;
+                   }
                } else {
                    beep();
                    break;
                }
            }
-           /* FALLTHRU */
 #endif
+           /* FALLTHRU */
        default:
            res.y = uli + i;
            res.x = ulj + j;
            return (&res);
        }
-       i %= si;
-       j %= sj;
+
+       if (si <= 0)
+           i = 0;
+       else
+           i %= si;
+
+       if (sj <= 0)
+           j = 0;
+       else
+           j %= sj;
+
+       /*
+        * If the caller can handle continuous movement, return the result.
+        */
+       if (moved && more) {
+           *more = TRUE;
+           res.y = uli + i;
+           res.x = ulj + j;
+           return (&res);
+       }
     }
 }
 
@@ -194,12 +259,20 @@ getwindow(WINDOW *parent, PAIR * ul, PAIR * lr)
     bool result = FALSE;
 
     head_line("Use arrows to move cursor, anything else to mark corner 1");
-    if ((tmp = selectcell(parent, min_line, min_col, max_line, max_col)) != 0) {
+    if ((tmp = selectcell(parent, 0,
+                         min_line, min_col,
+                         max_line, max_col,
+                         FALSE,
+                         (bool *) 0)) != 0) {
        *ul = *tmp;
        MvWAddCh(parent, ul->y, ul->x, '*');
 
        head_line("Use arrows to move cursor, anything else to mark corner 2");
-       if ((tmp = selectcell(parent, ul->y, ul->x, max_line, max_col)) != 0) {
+       if ((tmp = selectcell(parent, 0,
+                             ul->y, ul->x,
+                             max_line, max_col,
+                             FALSE,
+                             (bool *) 0)) != 0) {
            *lr = *tmp;
            MvWAddCh(parent, lr->y, lr->x, '*');
            wmove(parent, lr->y, lr->x);
@@ -252,6 +325,8 @@ add_window(WINDOW *parent, WINDOW *child)
     keypad(child, TRUE);
     if (need > have) {
        all_windows = typeRealloc(FRAME, need, all_windows);
+       if (!all_windows)
+           failed("add_window");
     }
     all_windows[num_windows].parent = parent;
     all_windows[num_windows].child = child;
@@ -311,7 +386,7 @@ next_window(WINDOW *win)
     int n = window2num(win);
 
     if (n++ >= 0) {
-       result = all_windows[n % num_windows].child;
+       result = all_windows[(unsigned) n % num_windows].child;
        wmove(result, 0, 0);
        wrefresh(result);
     }
@@ -326,8 +401,8 @@ prev_window(WINDOW *win)
 
     if (n-- >= 0) {
        if (n < 0)
-           n = num_windows - 1;
-       result = all_windows[n % num_windows].child;
+           n = (int) (num_windows - 1);
+       result = all_windows[(unsigned) n % num_windows].child;
        wmove(result, 0, 0);
        wrefresh(result);
     }
@@ -341,10 +416,7 @@ recur_move_window(WINDOW *parent, int dy, int dx)
 
     for (n = 0; n < num_windows; ++n) {
        if (all_windows[n].parent == parent) {
-           int y0, x0;
-
-           getbegyx(all_windows[n].child, y0, x0);
-           mvwin(all_windows[n].child, y0 + dy, x0 + dx);
+           mvwin(all_windows[n].child, dy, dx);
            recur_move_window(all_windows[n].child, dy, dx);
        }
     }
@@ -366,20 +438,24 @@ move_window(WINDOW *win, bool recur)
        int min_line = top ? LINE_MIN : 0;
        int max_line = top ? LINE_MAX : getmaxy(parent);
        PAIR *tmp;
+       bool more;
 
        head_line("Select new position for %swindow", top ? "" : "sub");
 
-       if ((tmp = selectcell(parent,
-                             min_line, min_col,
-                             max_line, max_col)) != 0) {
+       while ((tmp = selectcell(parent,
+                                win,
+                                min_line, min_col,
+                                max_line, max_col,
+                                FALSE,
+                                &more)) != 0) {
            int y0, x0;
            getbegyx(parent, y0, x0);
            /*
-            * Note:  Moving a subwindow has the effect of moving a viewport
-            * around the screen.  The parent window retains the contents of
-            * the subwindow in the original location, but the viewport will
-            * show the contents (again) at the new location.  So it will look
-            * odd when testing.
+            * Moving a subwindow has the effect of moving a viewport around
+            * the screen.  The parent window retains the contents of the
+            * subwindow in the original location, but the viewport will show
+            * the contents (again) at the new location.  So it will look odd
+            * when testing.
             */
            if (mvwin(win, y0 + tmp->y, x0 + tmp->x) != ERR) {
                if (recur) {
@@ -388,45 +464,69 @@ move_window(WINDOW *win, bool recur)
                refresh_all(win);
                doupdate();
                result = TRUE;
+           } else {
+               result = FALSE;
            }
+           if (!more)
+               break;
        }
     }
+    head_line("done");
     return result;
 }
 
+static void
+show_derwin(WINDOW *win)
+{
+    int pary, parx, maxy, maxx;
+
+    getmaxyx(win, maxy, maxx);
+    getparyx(win, pary, parx);
+
+    head_line("Select new position for derived window at %d,%d (%d,%d)",
+             pary, parx, maxy, maxx);
+}
+
 /*
  * test mvderwin().
  */
 static bool
-move_subwin(WINDOW *win)
+move_derwin(WINDOW *win)
 {
     WINDOW *parent = parent_of(win);
     bool result = FALSE;
 
     if (parent != 0) {
        bool top = (parent == stdscr);
-       if (!top) {
-           int min_col = top ? COL_MIN : 0;
-           int max_col = top ? COL_MAX : getmaxx(parent);
-           int min_line = top ? LINE_MIN : 0;
-           int max_line = top ? LINE_MAX : getmaxy(parent);
-           PAIR *tmp;
-
-           head_line("Select new position for subwindow");
-
-           if ((tmp = selectcell(parent,
-                                 min_line, min_col,
-                                 max_line, max_col)) != 0) {
-               int y0, x0;
-               getbegyx(parent, y0, x0);
-               if (mvderwin(win, y0 + tmp->y, x0 + tmp->x) != ERR) {
-                   refresh_all(win);
-                   doupdate();
-                   result = TRUE;
-               }
+       int min_col = top ? COL_MIN : 0;
+       int max_col = top ? COL_MAX : getmaxx(parent);
+       int min_line = top ? LINE_MIN : 0;
+       int max_line = top ? LINE_MAX : getmaxy(parent);
+       PAIR *tmp;
+       bool more;
+
+       show_derwin(win);
+       while ((tmp = selectcell(parent,
+                                win,
+                                min_line, min_col,
+                                max_line, max_col,
+                                TRUE,
+                                &more)) != 0) {
+           if (mvderwin(win, tmp->y, tmp->x) != ERR) {
+               refresh_all(win);
+               doupdate();
+               repaint_one(win);
+               doupdate();
+               result = TRUE;
+               show_derwin(win);
+           } else {
+               flash();
            }
+           if (!more)
+               break;
        }
     }
+    head_line("done");
     return result;
 }
 
@@ -449,6 +549,28 @@ fill_window(WINDOW *win, chtype ch)
     wrefresh(win);
 }
 
+static void
+fill_with_pattern(WINDOW *win)
+{
+    int y, x;
+    int y0, x0;
+    int y1, x1;
+    int ch = 'a';
+
+    getyx(win, y0, x0);
+    getmaxyx(win, y1, x1);
+    for (y = 0; y < y1; ++y) {
+       for (x = 0; x < x1; ++x) {
+           MvWAddCh(win, y, x, (chtype) ch);
+           if (++ch > 'z')
+               ch = 'a';
+       }
+    }
+    wsyncdown(win);
+    wmove(win, y0, x0);
+    wrefresh(win);
+}
+
 #define lines_of(ul,lr)        (lr.y - ul.y + 1)
 #define cols_of(ul,lr) (lr.x - ul.x + 1)
 #define pair_of(ul)    ul.y, ul.x
@@ -519,36 +641,35 @@ show_help(WINDOW *current)
        int     key;
        CONST_FMT char * msg;
     } help[] = {
-       { '?',          "Show this screen" },
+       { HELP_KEY_1,   "Show this screen" },
        { 'b',          "Draw a box inside the current window" },
        { 'c',          "Create a new window" },
        { 'd',          "Create a new derived window" },
+       { 'D',          "Move derived window (moves viewport)" },
        { 'f',          "Fill the current window with the next character" },
+       { 'F',          "Fill the current window with a pattern" },
        { 'm',          "Move the current window" },
        { 'M',          "Move the current window (and its children)" },
        { 'q',          "Quit" },
        { 's',          "Create a new subwindow" },
-       { 't',          "Move the current subwindow (moves content)" },
        { CTRL('L'),    "Repaint all windows, doing current one last" },
        { CTRL('N'),    "Cursor to next window" },
        { CTRL('P'),    "Cursor to previous window" },
     };
     /* *INDENT-ON* */
 
-    WINDOW *mywin = newwin(LINES, COLS, 0, 0);
-    int row;
+    char **msgs = typeCalloc(char *, SIZEOF(help) + 1);
+    size_t n;
 
-    for (row = 0; row < LINES - 2 && row < (int) SIZEOF(help); ++row) {
-       wmove(mywin, row + 1, 1);
-       wprintw(mywin, "%s", keyname(help[row].key));
-       wmove(mywin, row + 1, 20);
-       wprintw(mywin, "%s", help[row].msg);
+    for (n = 0; n < SIZEOF(help); ++n) {
+       msgs[n] = typeMalloc(char, 21 + strlen(help[n].msg));
+       sprintf(msgs[n], "%-20s%s", keyname(help[n].key), help[n].msg);
+    }
+    popup_msg2(current, msgs);
+    for (n = 0; n < SIZEOF(help); ++n) {
+       free(msgs[n]);
     }
-    box_inside(mywin);
-    wmove(mywin, 1, 1);
-    wgetch(mywin);
-    delwin(mywin);
-    refresh_all(current);
+    free(msgs);
 }
 
 int
@@ -571,8 +692,12 @@ main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
 #endif /* NCURSES_MOUSE_VERSION */
 
     while (!done && (ch = wgetch(current_win)) != ERR) {
+       int y, x;
+
+       getyx(current_win, y, x);
+
        switch (ch) {
-       case '?':
+       case HELP_KEY_1:
            show_help(current_win);
            break;
        case 'b':
@@ -584,9 +709,18 @@ main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
        case 'd':
            current_win = create_my_derwin(current_win);
            break;
+       case 'D':
+           if (!move_derwin(current_win)) {
+               tail_line("error");
+               continue;
+           }
+           break;
        case 'f':
            fill_window(current_win, (chtype) wgetch(current_win));
            break;
+       case 'F':
+           fill_with_pattern(current_win);
+           break;
        case 'm':
        case 'M':
            if (!move_window(current_win, (ch == 'M'))) {
@@ -600,12 +734,6 @@ main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
        case 's':
            current_win = create_my_subwin(current_win);
            break;
-       case 't':
-           if (!move_subwin(current_win)) {
-               tail_line("error");
-               continue;
-           }
-           break;
        case CTRL('L'):
            refresh_all(current_win);
            break;
@@ -621,6 +749,7 @@ main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
            /* want to allow deleting a window also */
 #endif
        default:
+           wmove(current_win, y, x);
            tail_line("unrecognized key (use '?' for help)");
            beep();
            continue;
@@ -635,5 +764,16 @@ main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
        wmove(current_win, 0, 0);
     }
     endwin();
+#if NO_LEAKS
+    free(all_windows);
+#endif
     ExitProgram(EXIT_SUCCESS);
 }
+#else
+int
+main(void)
+{
+    printf("This program requires the curses mvderwin and mvwin functions\n");
+    ExitProgram(EXIT_FAILURE);
+}
+#endif