]> granicus.if.org Git - nethack/commitdiff
win32 "more" handling (from <Someone>)
authornethack.allison <nethack.allison>
Thu, 20 Feb 2003 03:42:46 +0000 (03:42 +0000)
committernethack.allison <nethack.allison>
Thu, 20 Feb 2003 03:42:46 +0000 (03:42 +0000)
> There is a slight problem with "--more--" prompt being handled in
> WM_PAINT. WM_PAINT can be sent while you're inside
> mswin_nhgetch(). This causes some weirdness if window is resized
> while waiting for --more-- prompt.

win/win32/mhmsgwnd.c

index ad9c0250ecab6144e7519ce4fb0ec7ee9f673f5c..9bd00481054e467bd8577fecf4086c6ffa7e100e 100644 (file)
 
 struct window_line {
        int  attr;
-       char text[MAXWINDOWTEXT];
+       char text[MAXWINDOWTEXT+1];
 };
 
 typedef struct mswin_nethack_message_window {
        size_t max_text;
        struct window_line window_text[MAX_MSG_LINES];
-#ifdef MSG_WRAP_TEXT
-    int  window_text_lines[MAX_MSG_LINES]; /* How much space this text line takes */
-#endif
     int  lines_last_turn; /* lines added during the last turn */
-    int  cleared;     /* clear was called */
-    int  last_line;   /* last line in the message history */
-    struct window_line new_line;
     int  lines_not_seen;  /* lines not yet seen by user after last turn or --More-- */
-    int  in_more;   /* We are in a --More-- prompt */
     int  nevermore;   /* We want no more --More-- prompts */
 
        int  xChar;       /* horizontal scrolling unit */
@@ -58,6 +51,11 @@ static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
 static COLORREF setMsgTextColor(HDC hdc, int gray);
 static void onPaint(HWND hWnd);
 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+static BOOL can_append_text(HWND hWnd, int attr, const char* text ); 
+                       /* check if text can be appended to the last line without wrapping */
+
+static BOOL more_prompt_check(HWND hWnd);
+                       /* check if "--more--" promt needs to be displayed */
 
 #ifdef USER_SOUNDS
 extern void play_sound_for_message(const char* str);
@@ -215,22 +213,41 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
        {
                PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
                SCROLLINFO si;
+               char* p;
+               BOOL check_more = FALSE;
 
                if( msg_data->append == 1) {
                    /* Forcibly append to line, even if we pass the edge */
-                   strncat(data->window_text[data->last_line].text, msg_data->text, 
-                           MAXWINDOWTEXT - strlen(data->window_text[data->last_line].text));
+                   strncat(data->window_text[MSG_LINES-1].text, msg_data->text, 
+                           MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text));
                } else if( msg_data->append < 0) {
             /* remove that many chars */
-                   int len = strlen(data->window_text[data->last_line].text);
+                   int len = strlen(data->window_text[MSG_LINES-1].text);
             int newend = max(len + msg_data->append, 0);
-                   data->window_text[data->last_line].text[newend] = '\0';
+                   data->window_text[MSG_LINES-1].text[newend] = '\0';
         } else {
-                   /* Try to append but move the whole message to the next line if 
-                      it doesn't fit */
-                   /* just schedule for displaying */
-                   data->new_line.attr = msg_data->attr;
-                   strncpy(data->new_line.text, msg_data->text, MAXWINDOWTEXT);
+                       if( can_append_text(hWnd, msg_data->attr, msg_data->text ) ) {
+                               strncat(data->window_text[MSG_LINES-1].text, "  ", MAXWINDOWTEXT-strlen(data->window_text[MSG_LINES-1].text));
+                               strncat(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT-strlen(data->window_text[MSG_LINES-1].text));
+                       } else {
+                               /* check if the string is empty */
+                               for(p = data->window_text[MSG_LINES-1].text; *p && isspace(*p); p++);
+
+                               if( *p ) {
+                                       /* last string is not empty - scroll up */
+                                       memmove(&data->window_text[0],
+                                                       &data->window_text[1],
+                                                       (MSG_LINES-1)*sizeof(data->window_text[0]));
+                               }
+
+                               /* append new text to the end of the array */
+                               data->window_text[MSG_LINES-1].attr = msg_data->attr;
+                               strncpy(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT);
+
+                               data->lines_not_seen++;
+                               data->lines_last_turn++;
+                               check_more = TRUE;
+                       }
                }
                
                /* reset V-scroll position to display new text */
@@ -242,6 +259,43 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
         si.nPos   = data->yPos; 
         SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
 
+               /* check for "--more--" */
+               if( check_more && !data->nevermore && more_prompt_check(hWnd) ) {
+                       int okkey = 0;
+                       int chop;
+                       // @@@ Ok respnses
+
+                       /* append more prompt and inticate the update */
+                       strncat(data->window_text[MSG_LINES-1].text, MORE, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text));
+                       InvalidateRect(hWnd, NULL, TRUE);
+
+                       /* get the input */
+                       while (!okkey) {
+                       char c = mswin_nhgetch();
+
+                       switch (c)
+                       {
+                               /* space or enter */
+                               case ' ':
+                               case '\015':
+                               okkey = 1;
+                               break;
+                               /* ESC */
+                               case '\033':
+                               data->nevermore = 1;
+                               okkey = 1;
+                               break;
+                               default:
+                               break;
+                               }
+                       }
+
+                       /* erase the "--more--" prompt */
+                       chop = strlen(data->window_text[MSG_LINES-1].text) - strlen(MORE);
+                       data->window_text[MSG_LINES-1].text[chop] = '\0';
+                       data->lines_not_seen = 0;
+               }
+
                /* update window content */
                InvalidateRect(hWnd, NULL, TRUE);
 
@@ -253,9 +307,8 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
 
        case MSNH_MSG_CLEAR_WINDOW:
        {
-               data->cleared = 1;
+               data->lines_last_turn = 0;
                data->lines_not_seen = 0;
-               /* do --More-- again if needed */
                data->nevermore = 0;
                break;
        }
@@ -480,7 +533,6 @@ void onPaint(HWND hWnd)
                LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar); 
                y = min( ps.rcPaint.bottom, client_rt.bottom ); 
                for (i=LastLine; i>=FirstLine; i--) { 
-                               int lineidx = (data->last_line + 1 + i) % MSG_LINES;
                                x = data->xChar * (2 - data->xPos); 
 
                                draw_rt.left = x;
@@ -488,120 +540,21 @@ void onPaint(HWND hWnd)
                                draw_rt.top = y - data->yChar;
                                draw_rt.bottom = y;
 
-           oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
+           oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE));
 
-           /* find out if we can concatenate the scheduled message without wrapping,
-              but only if no clear_nhwindow was done just before putstr'ing this one. 
-              */
-           if (i == MSG_LINES-1 
-                   && strlen(data->new_line.text) > 0) {
-               /* concatenate to the previous line if that is not empty, and
-                  if it has the same attribute, and no clear was done.
-                  */
-               if (strlen(data->window_text[lineidx].text) > 0
-                       && (data->window_text[lineidx].attr 
-                           == data->new_line.attr)
-                       && !data->cleared) {
-                   RECT tmpdraw_rt = draw_rt;
-                   /* assume this will never work when textsize is near MAXWINDOWTEXT */
-                   char tmptext[MAXWINDOWTEXT];
-                   TCHAR tmpwbuf[MAXWINDOWTEXT+2];
-
-                   strcpy(tmptext, data->window_text[lineidx].text);
-                   strncat(tmptext, "  ", 
-                           MAXWINDOWTEXT - strlen(tmptext));
-                   strncat(tmptext, data->new_line.text, 
-                           MAXWINDOWTEXT - strlen(tmptext));
-                   /* Always keep room for a --More-- */
-                   strncat(tmptext, MORE, 
-                           MAXWINDOWTEXT - strlen(tmptext));
-                   NH_A2W(tmptext, tmpwbuf, sizeof(tmpwbuf));
-                   /* Find out how large the bounding rectangle of the text is */                
-                   DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
-                   if ((tmpdraw_rt.bottom - tmpdraw_rt.top) == (draw_rt.bottom - draw_rt.top)  /* fits pixelwise */
-                           && (strlen(data->window_text[lineidx].text) 
-                               + strlen(data->new_line.text) < MAXWINDOWTEXT)) /* fits charwise */
-                   {
-                       /* strip off --More-- of this combined line and make it so */
-                       tmptext[strlen(tmptext) - strlen(MORE)] = '\0';
-                       strcpy(data->window_text[lineidx].text, tmptext);
-                       data->new_line.text[0] = '\0';
-                       i++; /* Start from the last line again */
-                       continue;
-                   }
-               }
-               if (strlen(data->new_line.text) > 0) {
-                   /* if we get here, the new line was not concatenated. Add it on a new line,
-                      but first check whether we should --More--. */
-                   RECT tmpdraw_rt = draw_rt;
-                   TCHAR tmpwbuf[MAXWINDOWTEXT+2];
-                   HGDIOBJ oldFont;
-                   int new_screen_lines;
-                   int screen_lines_not_seen = 0;
-                   /* Count how many screen lines we haven't seen yet. */
-#ifdef MSG_WRAP_TEXT                           
-                   {
-                       int n;
-                       for (n = data->lines_not_seen - 1; n >= 0; n--) {
-                           screen_lines_not_seen += 
-                               data->window_text_lines[(data->last_line - n + MSG_LINES) % MSG_LINES];
-                       }
-                   }
-#else
-                   screen_lines_not_seen = data->lines_not_seen;
-#endif
-                   /* Now find out how many screen lines we would like to add */
-                   NH_A2W(data->new_line.text, tmpwbuf, sizeof(tmpwbuf));
-                   /* Find out how large the bounding rectangle of the text is */                
-                   oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
-                   DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
-                   SelectObject(hdc, oldFont);
-                   new_screen_lines = (tmpdraw_rt.bottom - tmpdraw_rt.top) / data->yChar;
-                   /* If this together is more than fits on the window, we must 
-                      --More--, unless:
-                      - We are in --More-- already (the user is scrolling the window)
-                      - The user pressed ESC
-                      */
-                   if (screen_lines_not_seen + new_screen_lines > MSG_VISIBLE_LINES
-                           && !data->in_more && !data->nevermore) {
-                       data->in_more = 1;
-                       /* Show --More-- on last line */
-                       strcat(data->window_text[data->last_line].text, MORE);
-                       /* Go on drawing, but remember we must do a more afterwards */
-                       do_more = 1;
-                   } else if (!data->in_more) {
-                       data->last_line++;
-                       data->last_line %= MSG_LINES; 
-                       data->window_text[data->last_line].attr = data->new_line.attr;
-                       strncpy(data->window_text[data->last_line].text, data->new_line.text, MAXWINDOWTEXT);
-                       data->new_line.text[0] = '\0';
-                       if (data->cleared) {
-                           /* now we are drawing a new line, the old lines can be redrawn in grey.*/
-                           data->lines_last_turn = 0;
-                           data->cleared = 0;
-                       }
-                       data->lines_last_turn++;
-                       data->lines_not_seen++;
-                       /* and start over */
-                       i++; /* Start from the last line again */
-                       continue;
-                   }
-               }
-           }
            /* convert to UNICODE */
-           NH_A2W(data->window_text[lineidx].text, wbuf, sizeof(wbuf));
+           NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
            wlen = _tcslen(wbuf);
            setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
 #ifdef MSG_WRAP_TEXT                           
            /* Find out how large the bounding rectangle of the text is */                
                                DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
-           /* move that rectangle up, so that the bottom remains at the same height */
+               /* move that rectangle up, so that the bottom remains at the same height */
                                draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
                                draw_rt.bottom = y;
-           /* Remember the height of this line for subsequent --More--'s */
-           data->window_text_lines[lineidx] = (draw_rt.bottom - draw_rt.top) / data->yChar;
-           /* Now really draw it */
-                               DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
+
+                       /* Now really draw it */
+                       DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
                 
                 /* Find out the cursor (caret) position */
            if (i == MSG_LINES-1) {
@@ -644,39 +597,6 @@ void onPaint(HWND hWnd)
                                SelectObject(hdc, oldFont);
                                y -= draw_rt.bottom - draw_rt.top;
                        }
-       if (do_more) {
-           int okkey = 0;
-           int chop;
-           // @@@ Ok respnses
-
-           while (!okkey) {
-               char c = mswin_nhgetch();
-
-               switch (c)
-               {
-                   /* space or enter */
-                   case ' ':
-                   case '\015':
-                       okkey = 1;
-                       break;
-                       /* ESC */
-                   case '\033':
-                       data->nevermore = 1;
-                       okkey = 1;
-                       break;
-                   default:
-                       break;
-                       }
-               }
-           chop = strlen(data->window_text[data->last_line].text) 
-               - strlen(MORE);
-           data->window_text[data->last_line].text[chop] = '\0';
-           data->in_more = 0;
-           data->lines_not_seen = 0;
-           /* We did the --More--, reset the lines_not_seen; now draw that
-              new line. This is the easiest method */
-           InvalidateRect(hWnd, NULL, TRUE);
-       }
        }
        SetTextColor (hdc, OldFg);
        SetBkColor (hdc, OldBg);
@@ -736,4 +656,95 @@ void mswin_message_window_size (HWND hWnd, LPSIZE sz)
        GetClientRect(hWnd, &client_rt);
        sz->cy = sz->cy - (client_rt.bottom - client_rt.top) +
                         data->yChar * MSG_VISIBLE_LINES;
-}
\ No newline at end of file
+}
+
+/* check if text can be appended to the last line without wrapping */
+BOOL can_append_text(HWND hWnd, int attr, const char* text )
+{
+       PNHMessageWindow data;
+       char tmptext[MAXWINDOWTEXT+1];
+       HDC hdc;
+       HGDIOBJ saveFont;
+       RECT draw_rt;
+       BOOL retval = FALSE;
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       /* cannot append if lines_not_seen is 0 (beginning of the new turn */
+       if( data->lines_not_seen==0 ) return FALSE;
+
+       /* cannot append text with different attrbutes */
+       if( data->window_text[MSG_LINES-1].attr != attr ) return FALSE;
+
+       /* check if the maximum string langth will be exceeded */
+       if( strlen(data->window_text[MSG_LINES-1].text)+
+               2 + /* space characters */
+               strlen(text) +
+               strlen(MORE) >= MAXWINDOWTEXT ) return FALSE;
+
+       /* check if the text is goinf to fin into a single line */
+       strcpy(tmptext, data->window_text[MSG_LINES-1].text );
+       strcat(tmptext, "  " );
+       strcat(tmptext, text );
+       strcat(tmptext, MORE );
+
+    hdc = GetDC(hWnd); 
+    saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES-1].attr, hdc, FALSE));
+       GetClientRect(hWnd, &draw_rt);
+       draw_rt.bottom = draw_rt.top; /* we only need width for the DrawText */
+       DrawText(hdc, tmptext, strlen(tmptext), &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
+
+       /* we will check against 1.5 of the font size in order to determine
+          if the text is single-line or not - just to be on the safe size */
+       retval = (draw_rt.bottom-draw_rt.top)<(data->yChar+data->yChar/2);
+                       
+       /* free device context */
+       SelectObject(hdc, saveFont);
+       ReleaseDC (hWnd, hdc); 
+       return retval;
+}
+
+/* check if "--more--" promt needs to be displayed 
+   basically, check if the lines not seen are going to find in the message window 
+*/
+BOOL more_prompt_check(HWND hWnd)
+{
+       PNHMessageWindow data;
+       HDC hdc;
+       HGDIOBJ saveFont;
+       RECT client_rt, draw_rt;
+       BOOL retval = FALSE;
+       int visible_lines = 0;
+       int i;
+       int remaining_height;
+
+       data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
+
+       if( data->lines_not_seen==0 ) return FALSE;  /* don't bother checking - nothig to "more" */
+       if( data->lines_not_seen>=MSG_LINES ) return TRUE; /* history size exceeded - always more */
+
+       GetClientRect(hWnd, &client_rt);
+       remaining_height = client_rt.bottom - client_rt.top;
+
+    hdc = GetDC(hWnd); 
+    saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
+       for( i=0; i<data->lines_not_seen; i++ ) {
+               /* we only need width for the DrawText */
+               SetRect(&draw_rt, client_rt.left, client_rt.top, client_rt.right, client_rt.top);
+               SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES-i-1].attr, hdc, FALSE));
+               remaining_height -= 
+                                       DrawText( hdc, 
+                                                         data->window_text[MSG_LINES-i-1].text, 
+                                                         strlen(data->window_text[MSG_LINES-i-1].text), 
+                                                         &draw_rt, 
+                                                         DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT
+                                                       );
+               if( remaining_height<0 ) break;
+       }
+       
+       /* free device context */
+       SelectObject(hdc, saveFont);
+       ReleaseDC (hWnd, hdc); 
+       return (remaining_height<0); /* TRUE if lines_not_seen take more that window height */ 
+}
+