]> granicus.if.org Git - nethack/commitdiff
curses ">>" (terse "--More--")
authorPatR <rankin@nethack.org>
Fri, 5 Apr 2019 00:55:40 +0000 (17:55 -0700)
committerPatR <rankin@nethack.org>
Fri, 5 Apr 2019 00:55:40 +0000 (17:55 -0700)
I've noticed many instances of the game pausing and not being sure why,
then pressing <space> and having it resume.  The curses interface had
a tendency to put its equivalent of the --More-- prompt, >>, somewhere
where that wasn't visible, either off the right hand edge (possibly) or
underneath the window borders if those were enabled.  Especially the
very last one it issues prior to exit.  (An extra one compared to tty
behavior.)

This ended up being a pretty substantial overhaul of message window
handling.  I wouldn't be surprised if it has off-by-one errors which
happen to be paired up and cancel each other out.  ">>" is still drawn
in orange if guicolor is on, now in inverse video when that is off.
If it happens to be drawn at the same screen location in consecutive
instances, the first ">" will toggle between blink and not blink so
that there'll be no doubt as to whether the keypress registered when
dismissing it (moot if the text preceding it is different but there's
no attempt to be smart enough to check that, just screen placement).

doc/fixes36.2
include/wincurs.h
win/curses/cursdial.c
win/curses/cursmain.c
win/curses/cursmesg.c
win/curses/cursmesg.h
win/curses/cursmisc.c

index 788d819bfc9e540706dae370c4d03faac56bbe55..68709069d8c33fe2d4a38b8c9c276bedbdd640e7 100644 (file)
@@ -1,4 +1,4 @@
-$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.297 $ $NHDT-Date: 1554411130 2019/04/04 20:52:10 $
+$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.298 $ $NHDT-Date: 1554425733 2019/04/05 00:55:33 $
 
 This fixes36.2 file is here to capture information about updates in the 3.6.x
 lineage following the release of 3.6.1 in April 2018. Please note, however,
@@ -536,6 +536,8 @@ curses: if player pressed ESC at More>> prompt to suppress remaining messages
        for the current move and then hero got another move on the same turn,
        messages and most prompts would stay suppressed during that extra move
 curses: don't let MSGTYPE=hide block prompts from being shown
+curses: the --More-- prompt (">>") wasn't always placed in a visible location,
+       especially when window borders were displayed
 vms: add compile of isaac64.c to Makefile.src and vmsbuild.com
 vms+curses: add compile support but it is known to fail to build
 
index 1dc6400d57ac75ea8686b02177f175e47c63395d..18b3be289452f49b6de3832fab8a537add4acdc7 100644 (file)
@@ -213,6 +213,7 @@ extern void curses_cleanup(void);
 /* cursmesg.c */
 
 extern void curses_message_win_puts(const char *message, boolean recursed);
+extern void curses_got_input(void);
 extern int curses_block(boolean require_tab); /* for MSGTYPE=STOP */
 extern int curses_more(void);
 extern void curses_clear_unhighlight_message_window(void);
index 062400b93e501687188ec726ce27427cb9ab11f2..fd5385b9095cce4991c8068d2790144990f5b455 100644 (file)
@@ -17,8 +17,6 @@
 #define strncasecmp strncmpi
 #endif
 
-extern long curs_mesg_suppress_turn; /* from cursmesg.c */
-
 /*
  * Note:
  *
@@ -127,7 +125,7 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer)
 
     /* if messages were being suppressed for the remainder of the turn,
        re-activate them now that input is being requested */
-    curs_mesg_suppress_turn = -1;
+    curses_got_input();
 
     if (buffer >= (int) sizeof input)
          buffer = (int) sizeof input - 1;
@@ -212,7 +210,7 @@ curses_character_input_dialog(const char *prompt, const char *choices,
 
     /* if messages were being suppressed for the remainder of the turn,
        re-activate them now that input is being requested */
-    curs_mesg_suppress_turn = -1;
+    curses_got_input();
 
     if (invent || (moves > 1)) {
         curses_get_window_size(MAP_WIN, &map_height, &map_width);
index c3cceb1f7090f7763714f725db3d0581a14fb45e..9757e111a7821675dbc2164208752cbf1418966b 100644 (file)
@@ -232,6 +232,7 @@ curses_get_nh_event()
 
     if (do_reset) {
         getmaxyx(base_term, term_rows, term_cols);
+        curses_got_input(); /* reset More>> */
         /* status_initialize, create_main_windows, last_messages, doredraw */
         curs_reset_windows(TRUE, TRUE);
     }
@@ -689,9 +690,6 @@ curses_nhgetch()
 {
     int ch;
 
-    /* if messages are being suppressed, reenable them */
-    curs_mesg_suppress_turn = -1;
-
     curses_prehousekeeping();
     ch = curses_read_char();
     curses_posthousekeeping();
index 2c1decb9a97f7b032204bfa126042fe6e648cb70..656dce57d37c63c324bca9eccb5e47fda98b1d6d 100644 (file)
@@ -9,10 +9,14 @@
 #include "cursmesg.h"
 #include <ctype.h>
 
+/*
+ * Note: references to "More>>" mean ">>", the curses rendition of "--More--".
+ */
+
 /* player can type ESC at More>> prompt to avoid seeing more messages
    for the current move; but hero might get more than one move per turn,
    so the input routines need to be able to cancel this */
-long curs_mesg_suppress_turn = -1; /* also used in cursdial.c && cursmain.c */
+long curs_mesg_suppress_turn = -1;
 
 /* Message window routines for curses interface */
 
@@ -31,30 +35,30 @@ static void directional_scroll(winid wid, int nlines);
 static void mesg_add_line(const char *mline);
 static nhprev_mesg *get_msg_line(boolean reverse, int mindex);
 
-static int turn_lines = 1;
+static int turn_lines = 0;
 static int mx = 0;
 static int my = 0;              /* message window text location */
 static nhprev_mesg *first_mesg = NULL;
 static nhprev_mesg *last_mesg = NULL;
 static int max_messages;
 static int num_messages = 0;
+static int last_messages = 0;
 
 /* Write string to the message window.  Attributes set by calling function. */
 
 void
 curses_message_win_puts(const char *message, boolean recursed)
 {
-    int height, width, linespace;
+    int height, width, border_space, linespace;
     char *tmpstr;
     WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
-    boolean border = curses_window_has_border(MESSAGE_WIN);
-    int message_length = strlen(message);
-    int border_space = 0;
+    boolean bold, border = curses_window_has_border(MESSAGE_WIN);
+    int message_length = (int) strlen(message);
 
 #if 0
     /*
      * This was useful when curses used genl_putmsghistory() but is not
-     * needed now that it has its own curses_putmsghistory() that's
+     * needed now that it has its own curses_putmsghistory() which is
      * capable of putting something into the ^P recall history without
      * displaying it at the same time.
      */
@@ -69,17 +73,11 @@ curses_message_win_puts(const char *message, boolean recursed)
     }
 
     curses_get_window_size(MESSAGE_WIN, &height, &width);
-    if (border) {
-        border_space = 1;
-        if (mx < 1) {
-            mx = 1;
-        }
-        if (my < 1) {
-            my = 1;
-        }
-    }
-
-    linespace = ((width + border_space) - 3) - mx;
+    border_space = (border ? 1 : 0);
+    if (mx < border_space)
+        mx = border_space;
+    if (my < border_space)
+        my = border_space;
 
     if (strcmp(message, "#") == 0) {    /* Extended command or Count: */
         if ((strcmp(toplines, "#") != 0)
@@ -90,7 +88,6 @@ curses_message_win_puts(const char *message, boolean recursed)
             my--;
             strcpy(toplines, message);
         }
-
         return;
     }
 
@@ -99,88 +96,142 @@ curses_message_win_puts(const char *message, boolean recursed)
         mesg_add_line(message);
     }
 
+    linespace = width - 3 - (mx - border_space);
+
     if (linespace < message_length) {
-        if (my >= (height - 1 + border_space)) {
+        if (my - border_space >= height - 1) {
             /* bottom of message win */
-            if ((turn_lines > height) || (height == 1)) {
+            if (++turn_lines >= height) { /* || height == 1) */
                 /* Pause until key is hit - Esc suppresses any further
                    messages that turn */
                 if (curses_more() == '\033') {
                     curs_mesg_suppress_turn = moves;
                     return;
                 }
+                /* turn_lines reset to 0 by more()->block()->got_input() */
             } else {
                 scroll_window(MESSAGE_WIN);
-                turn_lines++;
             }
         } else {
             if (mx != border_space) {
                 my++;
                 mx = border_space;
+                ++turn_lines;
             }
         }
     }
 
-    if (height > 1) {
+    bold = (height > 1 && !last_messages);
+    if (bold)
         curses_toggle_color_attr(win, NONE, A_BOLD, ON);
-    }
 
-    if ((mx == border_space) && ((message_length + 2) > width)) {
+    /* will this message fit as-is or do we need to split it? */
+    if (mx == border_space && message_length > width - 2) {
+        /* split needed */
         tmpstr = curses_break_str(message, (width - 2), 1);
-        mvwprintw(win, my, mx, "%s", tmpstr);
-        mx += strlen(tmpstr);
-        if (strlen(tmpstr) < (size_t) (width - 2)) {
-            mx++;
-        }
+        mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr);
+        /* one space to separate first part of message from rest [is this
+           actually useful?] */
+        if (mx < width - 2)
+            ++mx;
         free(tmpstr);
-        if (height > 1) {
+        if (bold)
             curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
-        }
         tmpstr = curses_str_remainder(message, (width - 2), 1);
         curses_message_win_puts(tmpstr, TRUE);
         free(tmpstr);
     } else {
-        mvwprintw(win, my, mx, "%s", message);
-        curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
-        mx += message_length + 1;
+        mvwprintw(win, my, mx, "%s", message), mx += message_length;
+        /* two spaces to separate this message from next one if they happen
+           to fit on the same line; (FIXME:  it would be better if this was
+           done at start of next message rather than end of this one since
+           it impacts placement of "More>>") */
+        if (mx < width - 2) {
+            if (++mx < width - 2)
+                ++mx;
+        }
+        if (bold)
+            curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
     }
     wrefresh(win);
 }
 
+void
+curses_got_input(void)
+{
+    /* if messages are being suppressed, reenable them */
+    curs_mesg_suppress_turn = -1;
+
+    /* misleadingly named; represents number of lines delivered since
+       player was sure to have had a chance to read them; if player
+       has just given input then there aren't any such lines right;
+       that includes responding to More>> even though it stays same turn */
+    turn_lines = 0;
+}
 
 int
 curses_block(boolean noscroll) /* noscroll - blocking because of msgtype
                                 * = stop/alert else blocking because
                                 * window is full, so need to scroll after */
 {
-    int height, width, ret = 0;
+    static const char resp[] = " \r\n\033"; /* space, enter, esc */
+    static int prev_x = -1, prev_y = -1, blink = 0;
+    int height, width, moreattr, oldcrsr, ret = 0,
+        brdroffset = curses_window_has_border(MESSAGE_WIN) ? 1 : 0;
     WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
-    const char *resp = " \r\n\033"; /* space, enter, esc */
-
-    /* if messages are being suppressed, reenable them */
-    curs_mesg_suppress_turn = -1;
 
     curses_get_window_size(MESSAGE_WIN, &height, &width);
-    curses_toggle_color_attr(win, MORECOLOR, NONE, ON);
-    mvwprintw(win, my, mx, ">>");
-    curses_toggle_color_attr(win, MORECOLOR, NONE, OFF);
+    if (mx - brdroffset > width - 3) { /* -3: room for ">>_" */
+        if (my - brdroffset < height - 1)
+            ++my, mx = brdroffset;
+        else
+            mx = width - 3 + brdroffset;
+    }
+    /* if ">>" (--More--) is being rendered at the same spot as before,
+       toggle attributes so that the first '>' starts blinking if it wasn't
+       or stops blinking if it was */
+    if (mx == prev_x && my == prev_y) {
+        blink = 1 - blink;
+    } else {
+        prev_x = mx, prev_y = my;
+        blink = 0;
+    }
+    moreattr = !iflags.wc2_guicolor ? A_REVERSE : NONE;
+    curses_toggle_color_attr(win, MORECOLOR, moreattr, ON);
+    if (blink) {
+        wattron(win, A_BLINK);
+        mvwprintw(win, my, mx, ">"), mx += 1;
+        wattroff(win, A_BLINK);
+        waddstr(win, ">"), mx += 1;
+    } else {
+        mvwprintw(win, my, mx, ">>"), mx += 2;
+    }
+    curses_toggle_color_attr(win, MORECOLOR, moreattr, OFF);
     wrefresh(win);
-    /* msgtype=stop should require space/enter rather than
-     * just any key, as we want to prevent YASD from
-     * riding direction keys. */
-    while ((ret = wgetch(win)) != 0 && !index(resp, (char) ret))
-        continue;
+
+    /* cancel mesg suppression; all messages will have had chance to be read */
+    curses_got_input();
+
+    oldcrsr = curs_set(1);
+    do {
+        ret = wgetch(win);
+        if (ret == ERR || ret == '\0')
+            ret = '\n';
+        /* msgtype=stop should require space/enter rather than any key,
+           as we want to prevent YASD from direction keys. */
+    } while (!index(resp, (char) ret));
+    if (oldcrsr >= 0)
+        (void) curs_set(oldcrsr);
+
     if (height == 1) {
         curses_clear_unhighlight_message_window();
     } else {
-        mvwprintw(win, my, mx, "      ");
+        mx -= 2, mvwprintw(win, my, mx, "  "); /* back up and blank out ">>" */
         if (!noscroll) {
             scroll_window(MESSAGE_WIN);
-            turn_lines = 1;
         }
         wrefresh(win);
     }
-
     return ret;
 }
 
@@ -196,34 +247,25 @@ curses_more()
 void
 curses_clear_unhighlight_message_window()
 {
-    int mh, mw, count;
-    boolean border = curses_window_has_border(MESSAGE_WIN);
+    int mh, mw, count,
+        brdroffset = curses_window_has_border(MESSAGE_WIN) ? 1 : 0;
     WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
 
-    turn_lines = 1;
+    turn_lines = 0;
     curses_get_window_size(MESSAGE_WIN, &mh, &mw);
 
-    mx = 0;
-    if (border) {
-        mx++;
-    }
-
     if (mh == 1) {
         curses_clear_nhwin(MESSAGE_WIN);
+        mx = my = brdroffset;
     } else {
-        mx += mw;               /* Force new line on new turn */
+        mx = mw + brdroffset; /* Force new line on new turn */
 
-        if (border) {
-            for (count = 0; count < mh; count++) {
-                mvwchgat(win, count + 1, 1, mw, COLOR_PAIR(8), A_NORMAL, NULL);
-            }
-        } else {
-            for (count = 0; count < mh; count++) {
-                mvwchgat(win, count, 0, mw, COLOR_PAIR(8), A_NORMAL, NULL);
-            }
-        }
+        for (count = 0; count < mh; count++)
+            mvwchgat(win, count + brdroffset, brdroffset,
+                     mw, COLOR_PAIR(8), A_NORMAL, NULL);
         wnoutrefresh(win);
     }
+    wmove(win, my, mx);
 }
 
 
@@ -235,19 +277,23 @@ curses_last_messages()
 {
     boolean border = curses_window_has_border(MESSAGE_WIN);
     nhprev_mesg *mesg;
-    int i;
+    int i, j, height, width;
+
+    curses_get_window_size(MESSAGE_WIN, &height, &width);
 
     if (border)
         mx = my = 1;
     else
         mx = my = 0;
 
-    for (i = (num_messages - 1); i > 0; i--) {
+    ++last_messages;
+    for (j = 0, i = num_messages - 1; i > 0 && j < height; --i, ++j) {
         mesg = get_msg_line(TRUE, i);
         if (mesg && mesg->str && *mesg->str)
             curses_message_win_puts(mesg->str, TRUE);
     }
     curses_message_win_puts(toplines, TRUE);
+    --last_messages;
 }
 
 
@@ -402,7 +448,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer)
     maxlines = buffer / width * 2;
     Strcpy(tmpbuf, prompt);
     Strcat(tmpbuf, " ");
-    nlines = curses_num_lines(tmpbuf,width);
+    nlines = curses_num_lines(tmpbuf, width);
     maxlines += nlines * 2;
     linestarts = (char **) alloc((unsigned) (maxlines * sizeof (char *)));
     p_answer = tmpbuf + strlen(tmpbuf);
@@ -463,6 +509,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer)
         wmove(win, my, mx);
         curs_set(1);
         wrefresh(win);
+        curses_got_input(); /* despite its name, before rathre than after... */
 #ifdef PDCURSES
         ch = wgetch(win);
 #else
@@ -786,6 +833,7 @@ boolean restoring_msghist;
             --stash_count;
             mesg_turn = mesg->turn;
             mesg_add_line(mesg->str);
+            /* added line became new tail */
             last_mesg->turn = mesg_turn;
             free((genericptr_t) mesg->str);
             free((genericptr_t) mesg);
index 803b0fb5bf34c498a05cea677cae3f53dcd9768e..ca0752eea6899aeec219932354cfd86db44841d7 100644 (file)
@@ -10,6 +10,7 @@
 /* Global declarations */
 
 void curses_message_win_puts(const char *message, boolean recursed);
+void curses_got_input(void);
 int curses_block(boolean require_tab);
 int curses_more(void);
 void curses_clear_unhighlight_message_window(void);
index fd712fac6e290eb144f8c28446d9b53605ac6fe5..223a8be82f468faf5db79459392e36ea2f10dddc 100644 (file)
@@ -42,6 +42,9 @@ curses_read_char()
 {
     int ch, tmpch;
 
+    /* cancel message suppression; all messages have had a chance to be read */
+    curses_got_input();
+
     ch = getch();
     tmpch = ch;
     ch = curses_convert_keys(ch);