1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed. See license for details. */
3
4 #include "winMS.h"
5 #include "mhmsgwnd.h"
6 #include "mhmsg.h"
7 #include "mhfont.h"
8
9 #define MSG_WRAP_TEXT
10
11 #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2)
12 #define MAX_MSG_LINES 32
13 #define MSG_LINES (int)min(iflags.msg_history, MAX_MSG_LINES)
14 #define MAXWINDOWTEXT TBUFSZ
15
16 #define DEFAULT_COLOR_BG_MSG COLOR_WINDOW
17 #define DEFAULT_COLOR_FG_MSG COLOR_WINDOWTEXT
18
19 #define MORE "--More--"
20
21 struct window_line {
22 int attr;
23 char text[MAXWINDOWTEXT];
24 };
25
26 typedef struct mswin_nethack_message_window {
27 size_t max_text;
28 struct window_line window_text[MAX_MSG_LINES];
29 #ifdef MSG_WRAP_TEXT
30 int window_text_lines[MAX_MSG_LINES]; /* How much space this text line takes */
31 #endif
32 int lines_last_turn; /* lines added during the last turn */
33 int cleared; /* clear was called */
34 int last_line; /* last line in the message history */
35 struct window_line new_line;
36 int lines_not_seen; /* lines not yet seen by user after last turn or --More-- */
37 int in_more; /* We are in a --More-- prompt */
38 int nevermore; /* We want no more --More-- prompts */
39
40 int xChar; /* horizontal scrolling unit */
41 int yChar; /* vertical scrolling unit */
42 int xUpper; /* average width of uppercase letters */
43 int xPos; /* current horizontal scrolling position */
44 int yPos; /* current vertical scrolling position */
45 int xMax; /* maximum horizontal scrolling position */
46 int yMax; /* maximum vertical scrolling position */
47 int xPage; /* page size of horizontal scroll bar */
48 } NHMessageWindow, *PNHMessageWindow;
49
50 static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
51 LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
52 static void register_message_window_class(void);
53 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
54 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
55 #ifndef MSG_WRAP_TEXT
56 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
57 #endif
58 static COLORREF setMsgTextColor(HDC hdc, int gray);
59 static void onPaint(HWND hWnd);
60 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
61
62 #ifdef USER_SOUNDS
63 extern void play_sound_for_message(const char* str);
64 #endif
65
mswin_init_message_window()66 HWND mswin_init_message_window () {
67 static int run_once = 0;
68 HWND ret;
69 DWORD style;
70
71 if( !run_once ) {
72 register_message_window_class( );
73 run_once = 1;
74 }
75
76 #ifdef MSG_WRAP_TEXT
77 style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
78 #else
79 style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
80 #endif
81
82 ret = CreateWindowEx(
83 WS_EX_CLIENTEDGE,
84 szMessageWindowClass, /* registered class name */
85 NULL, /* window name */
86 style, /* window style */
87 0, /* horizontal position of window */
88 0, /* vertical position of window */
89 0, /* window width */
90 0, /* window height - set it later */
91 GetNHApp()->hMainWnd, /* handle to parent or owner window */
92 NULL, /* menu handle or child identifier */
93 GetNHApp()->hApp, /* handle to application instance */
94 NULL ); /* window-creation data */
95
96 if( !ret ) panic("Cannot create message window");
97
98 return ret;
99 }
100
register_message_window_class()101 void register_message_window_class()
102 {
103 WNDCLASS wcex;
104 ZeroMemory( &wcex, sizeof(wcex));
105
106 wcex.style = CS_NOCLOSE;
107 wcex.lpfnWndProc = (WNDPROC)NHMessageWndProc;
108 wcex.cbClsExtra = 0;
109 wcex.cbWndExtra = 0;
110 wcex.hInstance = GetNHApp()->hApp;
111 wcex.hIcon = NULL;
112 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
113 wcex.hbrBackground = message_bg_brush ? message_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MSG);
114 wcex.lpszMenuName = NULL;
115 wcex.lpszClassName = szMessageWindowClass;
116
117 RegisterClass(&wcex);
118 }
119
NHMessageWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)120 LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
121 {
122 switch (message)
123 {
124 case WM_CREATE:
125 onCreate( hWnd, wParam, lParam );
126 break;
127
128 case WM_MSNH_COMMAND:
129 onMSNHCommand(hWnd, wParam, lParam);
130 break;
131
132 case WM_PAINT:
133 onPaint(hWnd);
134 break;
135
136 case WM_SETFOCUS:
137 SetFocus(GetNHApp()->hMainWnd);
138 break;
139
140 #ifndef MSG_WRAP_TEXT
141 case WM_HSCROLL:
142 onMSNH_HScroll(hWnd, wParam, lParam);
143 break;
144 #endif
145
146 case WM_VSCROLL:
147 onMSNH_VScroll(hWnd, wParam, lParam);
148 break;
149
150 case WM_DESTROY:
151 {
152 PNHMessageWindow data;
153 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
154 free(data);
155 SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
156 } break;
157
158 case WM_SIZE:
159 {
160 SCROLLINFO si;
161 int xNewSize;
162 int yNewSize;
163 PNHMessageWindow data;
164
165 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
166
167 xNewSize = LOWORD(lParam);
168 yNewSize = HIWORD(lParam);
169
170 if( xNewSize>0 || yNewSize>0 ) {
171
172 #ifndef MSG_WRAP_TEXT
173 data->xPage = xNewSize/data->xChar;
174 data->xMax = max(0, (int)(1 + data->max_text - data->xPage));
175 data->xPos = min(data->xPos, data->xMax);
176
177 ZeroMemory(&si, sizeof(si));
178 si.cbSize = sizeof(si);
179 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
180 si.nMin = 0;
181 si.nMax = data->max_text;
182 si.nPage = data->xPage;
183 si.nPos = data->xPos;
184 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
185 #endif
186
187 data->yMax = MSG_LINES-1;
188 data->yPos = min(data->yPos, data->yMax);
189
190 ZeroMemory(&si, sizeof(si));
191 si.cbSize = sizeof(si);
192 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
193 si.nMin = MSG_VISIBLE_LINES;
194 si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
195 si.nPage = MSG_VISIBLE_LINES;
196 si.nPos = data->yPos;
197 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
198 }
199 }
200 break;
201
202 default:
203 return DefWindowProc(hWnd, message, wParam, lParam);
204 }
205 return 0;
206 }
207
onMSNHCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)208 void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
209 {
210 PNHMessageWindow data;
211
212 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
213 switch( wParam ) {
214 case MSNH_MSG_PUTSTR:
215 {
216 PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
217 SCROLLINFO si;
218
219 if( msg_data->append == 1) {
220 /* Forcibly append to line, even if we pass the edge */
221 strncat(data->window_text[data->last_line].text, msg_data->text,
222 MAXWINDOWTEXT - strlen(data->window_text[data->last_line].text));
223 } else if( msg_data->append < 0) {
224 /* remove that many chars */
225 int len = strlen(data->window_text[data->last_line].text);
226 int newend = max(len + msg_data->append, 0);
227 data->window_text[data->last_line].text[newend] = '\0';
228 } else {
229 /* Try to append but move the whole message to the next line if
230 it doesn't fit */
231 /* just schedule for displaying */
232 data->new_line.attr = msg_data->attr;
233 strncpy(data->new_line.text, msg_data->text, MAXWINDOWTEXT);
234 }
235
236 /* reset V-scroll position to display new text */
237 data->yPos = data->yMax;
238
239 ZeroMemory(&si, sizeof(si));
240 si.cbSize = sizeof(si);
241 si.fMask = SIF_POS;
242 si.nPos = data->yPos;
243 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
244
245 /* update window content */
246 InvalidateRect(hWnd, NULL, TRUE);
247
248 #ifdef USER_SOUNDS
249 play_sound_for_message(msg_data->text);
250 #endif
251 }
252 break;
253
254 case MSNH_MSG_CLEAR_WINDOW:
255 {
256 data->cleared = 1;
257 data->lines_not_seen = 0;
258 /* do --More-- again if needed */
259 data->nevermore = 0;
260 break;
261 }
262 case MSNH_MSG_CARET:
263 /* Create or destroy a caret */
264 if (*(int *)lParam)
265 CreateCaret(hWnd, NULL, 0, data->yChar);
266 else {
267 DestroyCaret();
268 /* this means we just did something interactive in this window, so we
269 don't need a --More-- for the lines above.
270 */
271 data->lines_not_seen = 0;
272 }
273 break;
274
275
276 }
277 }
278
onMSNH_VScroll(HWND hWnd,WPARAM wParam,LPARAM lParam)279 void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
280 {
281 PNHMessageWindow data;
282 SCROLLINFO si;
283 int yInc;
284
285 /* get window data */
286 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
287
288 ZeroMemory(&si, sizeof(si));
289 si.cbSize = sizeof(si);
290 si.fMask = SIF_PAGE | SIF_POS;
291 GetScrollInfo(hWnd, SB_VERT, &si);
292
293 switch(LOWORD (wParam))
294 {
295 // User clicked the shaft above the scroll box.
296
297 case SB_PAGEUP:
298 yInc = -(int)si.nPage;
299 break;
300
301 // User clicked the shaft below the scroll box.
302
303 case SB_PAGEDOWN:
304 yInc = si.nPage;
305 break;
306
307 // User clicked the top arrow.
308
309 case SB_LINEUP:
310 yInc = -1;
311 break;
312
313 // User clicked the bottom arrow.
314
315 case SB_LINEDOWN:
316 yInc = 1;
317 break;
318
319 // User dragged the scroll box.
320
321 case SB_THUMBTRACK:
322 yInc = HIWORD(wParam) - data->yPos;
323 break;
324
325 default:
326 yInc = 0;
327 }
328
329 // If applying the vertical scrolling increment does not
330 // take the scrolling position out of the scrolling range,
331 // increment the scrolling position, adjust the position
332 // of the scroll box, and update the window. UpdateWindow
333 // sends the WM_PAINT message.
334
335 if (yInc = max( MSG_VISIBLE_LINES - data->yPos,
336 min(yInc, data->yMax - data->yPos)))
337 {
338 data->yPos += yInc;
339 /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
340 (CONST RECT *) NULL, (CONST RECT *) NULL,
341 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
342 */
343 InvalidateRect(hWnd, NULL, TRUE);
344
345 ZeroMemory(&si, sizeof(si));
346 si.cbSize = sizeof(si);
347 si.fMask = SIF_POS;
348 si.nPos = data->yPos;
349 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
350
351 UpdateWindow (hWnd);
352 }
353 }
354
355 #ifndef MSG_WRAP_TEXT
onMSNH_HScroll(HWND hWnd,WPARAM wParam,LPARAM lParam)356 void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
357 {
358 PNHMessageWindow data;
359 SCROLLINFO si;
360 int xInc;
361
362 /* get window data */
363 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
364
365 ZeroMemory(&si, sizeof(si));
366 si.cbSize = sizeof(si);
367 si.fMask = SIF_PAGE;
368 GetScrollInfo(hWnd, SB_HORZ, &si);
369
370 switch(LOWORD (wParam))
371 {
372 // User clicked shaft left of the scroll box.
373
374 case SB_PAGEUP:
375 xInc = - (int)si.nPage;
376 break;
377
378 // User clicked shaft right of the scroll box.
379
380 case SB_PAGEDOWN:
381 xInc = si.nPage;
382 break;
383
384 // User clicked the left arrow.
385
386 case SB_LINEUP:
387 xInc = -1;
388 break;
389
390 // User clicked the right arrow.
391
392 case SB_LINEDOWN:
393 xInc = 1;
394 break;
395
396 // User dragged the scroll box.
397
398 case SB_THUMBTRACK:
399 xInc = HIWORD(wParam) - data->xPos;
400 break;
401
402 default:
403 xInc = 0;
404
405 }
406
407
408 // If applying the horizontal scrolling increment does not
409 // take the scrolling position out of the scrolling range,
410 // increment the scrolling position, adjust the position
411 // of the scroll box, and update the window.
412
413 if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos)))
414 {
415 data->xPos += xInc;
416 ScrollWindowEx (hWnd, -data->xChar * xInc, 0,
417 (CONST RECT *) NULL, (CONST RECT *) NULL,
418 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
419
420 ZeroMemory(&si, sizeof(si));
421 si.cbSize = sizeof(si);
422 si.fMask = SIF_POS;
423 si.nPos = data->xPos;
424 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
425 UpdateWindow (hWnd);
426 }
427 }
428 #endif // MSG_WRAP_TEXT
429
setMsgTextColor(HDC hdc,int gray)430 COLORREF setMsgTextColor(HDC hdc, int gray)
431 {
432 COLORREF fg, color1, color2;
433 if (gray) {
434 if (message_bg_brush) {
435 color1 = message_bg_color;
436 color2 = message_fg_color;
437 } else {
438 color1 = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG);
439 color2 = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG);
440 }
441 /* Make a "gray" color by taking the average of the individual R,G,B
442 components of two colors. Thanks to Jonathan del Strother */
443 fg = RGB((GetRValue(color1)+GetRValue(color2))/2,
444 (GetGValue(color1)+GetGValue(color2))/2,
445 (GetBValue(color1)+GetBValue(color2))/2);
446 } else {
447 fg = message_fg_brush ? message_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG);
448 }
449
450
451 return SetTextColor(hdc, fg);
452 }
453
454
onPaint(HWND hWnd)455 void onPaint(HWND hWnd)
456 {
457 PAINTSTRUCT ps;
458 HDC hdc;
459 PNHMessageWindow data;
460 RECT client_rt, draw_rt;
461 int FirstLine, LastLine;
462 int i, x, y;
463 HGDIOBJ oldFont;
464 TCHAR wbuf[MAXWINDOWTEXT+2];
465 size_t wlen;
466 COLORREF OldBg, OldFg;
467 int do_more = 0;
468
469 hdc = BeginPaint(hWnd, &ps);
470
471 OldBg = SetBkColor(hdc, message_bg_brush ? message_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG));
472 OldFg = setMsgTextColor(hdc, 0);
473
474 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
475
476 GetClientRect(hWnd, &client_rt);
477
478 if( !IsRectEmpty(&ps.rcPaint) ) {
479 FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1);
480 LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar);
481 y = min( ps.rcPaint.bottom, client_rt.bottom );
482 for (i=LastLine; i>=FirstLine; i--) {
483 int lineidx = (data->last_line + 1 + i) % MSG_LINES;
484 x = data->xChar * (2 - data->xPos);
485
486 draw_rt.left = x;
487 draw_rt.right = client_rt.right;
488 draw_rt.top = y - data->yChar;
489 draw_rt.bottom = y;
490
491 oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
492
493 /* find out if we can concatenate the scheduled message without wrapping,
494 but only if no clear_nhwindow was done just before putstr'ing this one,
495 and only if not in a more prompt already (to prevent concatenating to
496 a line containing --More-- when resizing while --More-- is displayed.)
497 */
498 if (i == MSG_LINES-1
499 && strlen(data->new_line.text) > 0
500 && !data->in_more) {
501 /* concatenate to the previous line if that is not empty, and
502 if it has the same attribute, and no clear was done.
503 */
504 if (strlen(data->window_text[lineidx].text) > 0
505 && (data->window_text[lineidx].attr
506 == data->new_line.attr)
507 && !data->cleared) {
508 RECT tmpdraw_rt = draw_rt;
509 /* assume this will never work when textsize is near MAXWINDOWTEXT */
510 char tmptext[MAXWINDOWTEXT];
511 TCHAR tmpwbuf[MAXWINDOWTEXT+2];
512
513 strcpy(tmptext, data->window_text[lineidx].text);
514 strncat(tmptext, " ",
515 MAXWINDOWTEXT - strlen(tmptext));
516 strncat(tmptext, data->new_line.text,
517 MAXWINDOWTEXT - strlen(tmptext));
518 /* Always keep room for a --More-- */
519 strncat(tmptext, MORE,
520 MAXWINDOWTEXT - strlen(tmptext));
521 NH_A2W(tmptext, tmpwbuf, sizeof(tmpwbuf));
522 /* Find out how large the bounding rectangle of the text is */
523 DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
524 if ((tmpdraw_rt.bottom - tmpdraw_rt.top) == (draw_rt.bottom - draw_rt.top) /* fits pixelwise */
525 && (strlen(data->window_text[lineidx].text)
526 + strlen(data->new_line.text) < MAXWINDOWTEXT)) /* fits charwise */
527 {
528 /* strip off --More-- of this combined line and make it so */
529 tmptext[strlen(tmptext) - strlen(MORE)] = '\0';
530 strcpy(data->window_text[lineidx].text, tmptext);
531 data->new_line.text[0] = '\0';
532 i++; /* Start from the last line again */
533 continue;
534 }
535 }
536 if (strlen(data->new_line.text) > 0) {
537 /* if we get here, the new line was not concatenated. Add it on a new line,
538 but first check whether we should --More--. */
539 RECT tmpdraw_rt = draw_rt;
540 TCHAR tmpwbuf[MAXWINDOWTEXT+2];
541 HGDIOBJ oldFont;
542 int new_screen_lines;
543 int screen_lines_not_seen = 0;
544 /* Count how many screen lines we haven't seen yet. */
545 #ifdef MSG_WRAP_TEXT
546 {
547 int n;
548 for (n = data->lines_not_seen - 1; n >= 0; n--) {
549 screen_lines_not_seen +=
550 data->window_text_lines[(data->last_line - n + MSG_LINES) % MSG_LINES];
551 }
552 }
553 #else
554 screen_lines_not_seen = data->lines_not_seen;
555 #endif
556 /* Now find out how many screen lines we would like to add */
557 NH_A2W(data->new_line.text, tmpwbuf, sizeof(tmpwbuf));
558 /* Find out how large the bounding rectangle of the text is */
559 oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE));
560 DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
561 SelectObject(hdc, oldFont);
562 new_screen_lines = (tmpdraw_rt.bottom - tmpdraw_rt.top) / data->yChar;
563 /* If this together is more than fits on the window, we must
564 --More--, unless:
565 - We are in --More-- already (the user is scrolling the window)
566 - The user pressed ESC
567 */
568 if (screen_lines_not_seen + new_screen_lines > MSG_VISIBLE_LINES
569 && !data->in_more && !data->nevermore) {
570 data->in_more = 1;
571 /* Show --More-- on last line */
572 strcat(data->window_text[data->last_line].text, MORE);
573 /* Go on drawing, but remember we must do a more afterwards */
574 do_more = 1;
575 } else if (!data->in_more) {
576 data->last_line++;
577 data->last_line %= MSG_LINES;
578 data->window_text[data->last_line].attr = data->new_line.attr;
579 strncpy(data->window_text[data->last_line].text, data->new_line.text, MAXWINDOWTEXT);
580 data->new_line.text[0] = '\0';
581 if (data->cleared) {
582 /* now we are drawing a new line, the old lines can be redrawn in grey.*/
583 data->lines_last_turn = 0;
584 data->cleared = 0;
585 }
586 data->lines_last_turn++;
587 data->lines_not_seen++;
588 /* and start over */
589 i++; /* Start from the last line again */
590 continue;
591 }
592 }
593 }
594 /* convert to UNICODE */
595 NH_A2W(data->window_text[lineidx].text, wbuf, sizeof(wbuf));
596 wlen = _tcslen(wbuf);
597 setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
598 #ifdef MSG_WRAP_TEXT
599 /* Find out how large the bounding rectangle of the text is */
600 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
601 /* move that rectangle up, so that the bottom remains at the same height */
602 draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
603 draw_rt.bottom = y;
604 /* Remember the height of this line for subsequent --More--'s */
605 data->window_text_lines[lineidx] = (draw_rt.bottom - draw_rt.top) / data->yChar;
606 /* Now really draw it */
607 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
608
609 /* Find out the cursor (caret) position */
610 if (i == MSG_LINES-1) {
611 int nnum, numfit;
612 SIZE size;
613 TCHAR *nbuf;
614 int nlen;
615
616 nbuf = wbuf;
617 nlen = wlen;
618 while (nlen) {
619 /* Get the number of characters that fit on the line */
620 GetTextExtentExPoint(hdc, nbuf, nlen, draw_rt.right - draw_rt.left, &numfit, NULL, &size);
621 /* Search back to a space */
622 nnum = numfit;
623 if (numfit < nlen) {
624 while (nnum > 0 && nbuf[nnum] != ' ')
625 nnum--;
626 /* If no space found, break wherever */
627 if (nnum == 0)
628 nnum = numfit;
629 }
630 nbuf += nnum;
631 nlen -= nnum;
632 if (*nbuf == ' ') {
633 nbuf++;
634 nlen--;
635 }
636 }
637 /* The last size is the size of the last line. Set the caret there.
638 This will fail automatically if we don't own the caret (i.e.,
639 when not in a question.)
640 */
641 SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar);
642 }
643 #else
644 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX );
645 SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar);
646 #endif
647 SelectObject(hdc, oldFont);
648 y -= draw_rt.bottom - draw_rt.top;
649 }
650 if (do_more) {
651 int okkey = 0;
652 int chop;
653 // @@@ Ok respnses
654
655 while (!okkey) {
656 char c = mswin_nhgetch();
657
658 switch (c)
659 {
660 /* space or enter */
661 case ' ':
662 case '\015':
663 okkey = 1;
664 break;
665 /* ESC */
666 case '\033':
667 data->nevermore = 1;
668 okkey = 1;
669 break;
670 default:
671 break;
672 }
673 }
674 chop = strlen(data->window_text[data->last_line].text)
675 - strlen(MORE);
676 data->window_text[data->last_line].text[chop] = '\0';
677 data->in_more = 0;
678 data->lines_not_seen = 0;
679 /* We did the --More--, reset the lines_not_seen; now draw that
680 new line. This is the easiest method */
681 InvalidateRect(hWnd, NULL, TRUE);
682 }
683 }
684 SetTextColor (hdc, OldFg);
685 SetBkColor (hdc, OldBg);
686 EndPaint(hWnd, &ps);
687 }
688
onCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)689 void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
690 {
691 PNHMessageWindow data;
692 SIZE dummy;
693
694 /* set window data */
695 data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow));
696 if( !data ) panic("out of memory");
697 ZeroMemory(data, sizeof(NHMessageWindow));
698 data->max_text = MAXWINDOWTEXT;
699 SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
700
701 /* re-calculate window size (+ font size) */
702 mswin_message_window_size(hWnd, &dummy);
703 }
704
mswin_message_window_size(HWND hWnd,LPSIZE sz)705 void mswin_message_window_size (HWND hWnd, LPSIZE sz)
706 {
707 HDC hdc;
708 HGDIOBJ saveFont;
709 TEXTMETRIC tm;
710 PNHMessageWindow data;
711 RECT rt, client_rt;
712
713 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
714 if( !data ) return;
715
716 /* -- Calculate the font size -- */
717 /* Get the handle to the client area's device context. */
718 hdc = GetDC(hWnd);
719 saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
720
721 /* Extract font dimensions from the text metrics. */
722 GetTextMetrics (hdc, &tm);
723 data->xChar = tm.tmAveCharWidth;
724 data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2;
725 data->yChar = tm.tmHeight + tm.tmExternalLeading;
726 data->xPage = 1;
727
728 /* Free the device context. */
729 SelectObject(hdc, saveFont);
730 ReleaseDC (hWnd, hdc);
731
732 /* -- calculate window size -- */
733 GetWindowRect(hWnd, &rt);
734 sz->cx = rt.right - rt.left;
735 sz->cy = rt.bottom - rt.top;
736
737 /* set size to accomodate MSG_VISIBLE_LINES and
738 horizontal scroll bar (difference between window rect and client rect */
739 GetClientRect(hWnd, &client_rt);
740 sz->cy = sz->cy - (client_rt.bottom - client_rt.top) +
741 data->yChar * MSG_VISIBLE_LINES;
742 }
743