NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / win32 / mhmsgwnd.c
blobf85c7e211fc3c073cfa8bd8f5689755ceed63e69
1 /* aNetHack 0.0.1 mhmsgwnd.c $ANH-Date: 1432512812 2015/05/25 00:13:32 $ $ANH-Branch: master $:$ANH-Revision: 1.32 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "winMS.h"
6 #include "mhmsgwnd.h"
7 #include "mhmsg.h"
8 #include "mhfont.h"
10 #define MSG_WRAP_TEXT
12 #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 1)
13 #define MAX_MSG_LINES 128
14 #define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES)
15 #define MAXWINDOWTEXT TBUFSZ
17 #define DEFAULT_COLOR_BG_MSG COLOR_WINDOW
18 #define DEFAULT_COLOR_FG_MSG COLOR_WINDOWTEXT
20 #define MORE "--More--"
22 struct window_line {
23 int attr;
24 char text[MAXWINDOWTEXT + 1];
27 typedef struct mswin_anethack_message_window {
28 size_t max_text;
29 struct window_line window_text[MAX_MSG_LINES];
30 int lines_last_turn; /* lines added during the last turn */
31 int lines_not_seen; /* lines not yet seen by user after last turn or
32 --More-- */
33 int nevermore; /* We want no more --More-- prompts */
35 int xChar; /* horizontal scrolling unit */
36 int yChar; /* vertical scrolling unit */
37 int xUpper; /* average width of uppercase letters */
38 int xPos; /* current horizontal scrolling position */
39 int yPos; /* current vertical scrolling position */
40 int xMax; /* maximum horizontal scrolling position */
41 int yMax; /* maximum vertical scrolling position */
42 int xPage; /* page size of horizontal scroll bar */
43 } NHMessageWindow, *PNHMessageWindow;
45 static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
46 LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
47 static void register_message_window_class(void);
48 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
49 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
50 #ifndef MSG_WRAP_TEXT
51 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
52 #endif
53 static COLORREF setMsgTextColor(HDC hdc, int gray);
54 static void onPaint(HWND hWnd);
55 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
56 static BOOL can_append_text(HWND hWnd, int attr, const char *text);
57 /* check if text can be appended to the last line without wrapping */
59 static BOOL more_prompt_check(HWND hWnd);
60 /* check if "--more--" prompt needs to be displayed */
62 #ifdef USER_SOUNDS
63 extern void play_sound_for_message(const char *str);
64 #endif
66 HWND
67 mswin_init_message_window()
69 static int run_once = 0;
70 HWND ret;
71 DWORD style;
72 RECT rt;
74 if (!run_once) {
75 register_message_window_class();
76 run_once = 1;
79 /* get window position */
80 if (GetNHApp()->bAutoLayout) {
81 SetRect(&rt, 0, 0, 0, 0);
82 } else {
83 mswin_get_window_placement(NHW_MESSAGE, &rt);
86 #ifdef MSG_WRAP_TEXT
87 style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_SIZEBOX;
88 #else
89 style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL | WS_SIZEBOX;
90 #endif
92 ret = CreateWindowEx(
93 WS_EX_CLIENTEDGE, szMessageWindowClass, /* registered class name */
94 NULL, /* window name */
95 style, /* window style */
96 rt.left, /* horizontal position of window */
97 rt.top, /* vertical position of window */
98 rt.right - rt.left, /* window width */
99 rt.bottom - rt.top, /* window height */
100 GetNHApp()->hMainWnd, /* handle to parent or owner window */
101 NULL, /* menu handle or child identifier */
102 GetNHApp()->hApp, /* handle to application instance */
103 NULL); /* window-creation data */
105 if (!ret)
106 panic("Cannot create message window");
108 /* Set window caption */
109 SetWindowText(ret, "Messages");
111 mswin_apply_window_style(ret);
113 return ret;
116 void
117 register_message_window_class()
119 WNDCLASS wcex;
120 ZeroMemory(&wcex, sizeof(wcex));
122 wcex.style = CS_NOCLOSE;
123 wcex.lpfnWndProc = (WNDPROC) NHMessageWndProc;
124 wcex.cbClsExtra = 0;
125 wcex.cbWndExtra = 0;
126 wcex.hInstance = GetNHApp()->hApp;
127 wcex.hIcon = NULL;
128 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
129 wcex.hbrBackground = message_bg_brush
130 ? message_bg_brush
131 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MSG);
132 wcex.lpszMenuName = NULL;
133 wcex.lpszClassName = szMessageWindowClass;
135 RegisterClass(&wcex);
138 LRESULT CALLBACK
139 NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
141 switch (message) {
142 case WM_CREATE:
143 onCreate(hWnd, wParam, lParam);
144 break;
146 case WM_MSNH_COMMAND:
147 onMSNHCommand(hWnd, wParam, lParam);
148 break;
150 case WM_PAINT:
151 onPaint(hWnd);
152 break;
154 case WM_SETFOCUS:
155 SetFocus(GetNHApp()->hMainWnd);
156 break;
158 #ifndef MSG_WRAP_TEXT
159 case WM_HSCROLL:
160 onMSNH_HScroll(hWnd, wParam, lParam);
161 break;
162 #endif
164 case WM_VSCROLL:
165 onMSNH_VScroll(hWnd, wParam, lParam);
166 break;
168 case WM_DESTROY: {
169 PNHMessageWindow data;
170 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
171 free(data);
172 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
173 } break;
175 case WM_SIZE: {
176 SCROLLINFO si;
177 int xNewSize;
178 int yNewSize;
179 PNHMessageWindow data;
180 RECT rt;
182 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
184 xNewSize = LOWORD(lParam);
185 yNewSize = HIWORD(lParam);
187 if (xNewSize > 0 || yNewSize > 0) {
188 #ifndef MSG_WRAP_TEXT
189 data->xPage = xNewSize / data->xChar;
190 data->xMax = max(0, (int) (1 + data->max_text - data->xPage));
191 data->xPos = min(data->xPos, data->xMax);
193 ZeroMemory(&si, sizeof(si));
194 si.cbSize = sizeof(si);
195 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
196 si.nMin = 0;
197 si.nMax = data->max_text;
198 si.nPage = data->xPage;
199 si.nPos = data->xPos;
200 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
201 #endif
203 data->yMax = MSG_LINES - 1;
204 data->yPos = min(data->yPos, data->yMax);
206 ZeroMemory(&si, sizeof(si));
207 si.cbSize = sizeof(si);
208 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
209 si.nMin = MSG_VISIBLE_LINES;
210 si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
211 si.nPage = MSG_VISIBLE_LINES;
212 si.nPos = data->yPos;
213 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
216 /* update aNetHack internal window position */
217 GetWindowRect(hWnd, &rt);
218 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
219 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
220 mswin_update_window_placement(NHW_MESSAGE, &rt);
222 /* redraw window - it does not handle incremental resizing too well */
223 InvalidateRect(hWnd, NULL, TRUE);
224 } break;
226 case WM_MOVE: {
227 RECT rt;
228 GetWindowRect(hWnd, &rt);
229 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
230 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
231 mswin_update_window_placement(NHW_MESSAGE, &rt);
232 } break;
234 default:
235 return DefWindowProc(hWnd, message, wParam, lParam);
237 return 0;
240 void
241 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
243 PNHMessageWindow data;
245 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
246 switch (wParam) {
247 case MSNH_MSG_PUTSTR: {
248 PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam;
249 SCROLLINFO si;
250 char *p;
252 if (msg_data->append == 1) {
253 /* Forcibly append to line, even if we pass the edge */
254 strncat(data->window_text[MSG_LINES - 1].text, msg_data->text,
255 MAXWINDOWTEXT
256 - strlen(data->window_text[MSG_LINES - 1].text));
257 } else if (msg_data->append < 0) {
258 /* remove that many chars */
259 int len = strlen(data->window_text[MSG_LINES - 1].text);
260 int newend = max(len + msg_data->append, 0);
261 data->window_text[MSG_LINES - 1].text[newend] = '\0';
262 } else {
263 if (can_append_text(hWnd, msg_data->attr, msg_data->text)) {
264 strncat(data->window_text[MSG_LINES - 1].text, " ",
265 MAXWINDOWTEXT
266 - strlen(data->window_text[MSG_LINES - 1].text));
267 strncat(data->window_text[MSG_LINES - 1].text, msg_data->text,
268 MAXWINDOWTEXT
269 - strlen(data->window_text[MSG_LINES - 1].text));
270 } else {
271 /* check for "--more--" */
272 if (!data->nevermore && more_prompt_check(hWnd)) {
273 int okkey = 0;
274 int chop;
275 // @@@ Ok respnses
277 /* append more prompt and inticate the update */
278 strncat(
279 data->window_text[MSG_LINES - 1].text, MORE,
280 MAXWINDOWTEXT
281 - strlen(data->window_text[MSG_LINES - 1].text));
282 InvalidateRect(hWnd, NULL, TRUE);
284 /* get the input */
285 while (!okkey) {
286 int c = mswin_nhgetch();
288 switch (c) {
289 /* space or enter */
290 case ' ':
291 case '\015':
292 okkey = 1;
293 break;
294 /* ESC */
295 case '\033':
296 data->nevermore = 1;
297 okkey = 1;
298 break;
299 default:
300 break;
304 /* erase the "--more--" prompt */
305 chop = strlen(data->window_text[MSG_LINES - 1].text)
306 - strlen(MORE);
307 data->window_text[MSG_LINES - 1].text[chop] = '\0';
308 data->lines_not_seen = 0;
311 /* check if the string is empty */
312 for (p = data->window_text[MSG_LINES - 1].text;
313 *p && isspace((uchar) *p); p++)
316 if (*p) {
317 /* last string is not empty - scroll up */
318 memmove(&data->window_text[0], &data->window_text[1],
319 (MSG_LINES - 1) * sizeof(data->window_text[0]));
322 /* append new text to the end of the array */
323 data->window_text[MSG_LINES - 1].attr = msg_data->attr;
324 strncpy(data->window_text[MSG_LINES - 1].text, msg_data->text,
325 MAXWINDOWTEXT);
327 data->lines_not_seen++;
328 data->lines_last_turn++;
332 /* reset V-scroll position to display new text */
333 data->yPos = data->yMax;
335 ZeroMemory(&si, sizeof(si));
336 si.cbSize = sizeof(si);
337 si.fMask = SIF_POS;
338 si.nPos = data->yPos;
339 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
341 /* update window content */
342 InvalidateRect(hWnd, NULL, TRUE);
344 #ifdef USER_SOUNDS
345 if (!GetNHApp()->bNoSounds)
346 play_sound_for_message(msg_data->text);
347 #endif
348 } break;
350 case MSNH_MSG_CLEAR_WINDOW: {
351 data->lines_last_turn = 0;
352 data->lines_not_seen = 0;
353 data->nevermore = 0;
354 break;
356 case MSNH_MSG_CARET:
357 /* Create or destroy a caret */
358 if (*(int *) lParam)
359 CreateCaret(hWnd, NULL, 0, data->yChar);
360 else {
361 DestroyCaret();
362 /* this means we just did something interactive in this window, so
364 don't need a --More-- for the lines above.
366 data->lines_not_seen = 0;
368 break;
370 case MSNH_MSG_GETTEXT: {
371 PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam;
372 int i;
373 size_t buflen;
375 buflen = 0;
376 for (i = 0; i < MSG_LINES; i++)
377 if (*data->window_text[i].text) {
378 strncpy(&msg_data->buffer[buflen], data->window_text[i].text,
379 msg_data->max_size - buflen);
380 buflen += strlen(data->window_text[i].text);
381 if (buflen >= msg_data->max_size)
382 break;
384 strncpy(&msg_data->buffer[buflen], "\r\n",
385 msg_data->max_size - buflen);
386 buflen += 2;
387 if (buflen > msg_data->max_size)
388 break;
390 } break;
392 } /* switch( wParam ) */
395 void
396 onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
398 PNHMessageWindow data;
399 SCROLLINFO si;
400 int yInc;
402 UNREFERENCED_PARAMETER(lParam);
404 /* get window data */
405 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
407 ZeroMemory(&si, sizeof(si));
408 si.cbSize = sizeof(si);
409 si.fMask = SIF_PAGE | SIF_POS;
410 GetScrollInfo(hWnd, SB_VERT, &si);
412 switch (LOWORD(wParam)) {
413 // User clicked the shaft above the scroll box.
415 case SB_PAGEUP:
416 yInc = -(int) si.nPage;
417 break;
419 // User clicked the shaft below the scroll box.
421 case SB_PAGEDOWN:
422 yInc = si.nPage;
423 break;
425 // User clicked the top arrow.
427 case SB_LINEUP:
428 yInc = -1;
429 break;
431 // User clicked the bottom arrow.
433 case SB_LINEDOWN:
434 yInc = 1;
435 break;
437 // User dragged the scroll box.
439 case SB_THUMBTRACK:
440 yInc = HIWORD(wParam) - data->yPos;
441 break;
443 default:
444 yInc = 0;
447 // If applying the vertical scrolling increment does not
448 // take the scrolling position out of the scrolling range,
449 // increment the scrolling position, adjust the position
450 // of the scroll box, and update the window. UpdateWindow
451 // sends the WM_PAINT message.
453 if (yInc = max(MSG_VISIBLE_LINES - data->yPos,
454 min(yInc, data->yMax - data->yPos))) {
455 data->yPos += yInc;
456 /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
457 (CONST RECT *) NULL, (CONST RECT *) NULL,
458 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
460 InvalidateRect(hWnd, NULL, TRUE);
462 ZeroMemory(&si, sizeof(si));
463 si.cbSize = sizeof(si);
464 si.fMask = SIF_POS;
465 si.nPos = data->yPos;
466 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
468 UpdateWindow(hWnd);
472 #ifndef MSG_WRAP_TEXT
473 void
474 onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
476 PNHMessageWindow data;
477 SCROLLINFO si;
478 int xInc;
480 /* get window data */
481 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
483 ZeroMemory(&si, sizeof(si));
484 si.cbSize = sizeof(si);
485 si.fMask = SIF_PAGE;
486 GetScrollInfo(hWnd, SB_HORZ, &si);
488 switch (LOWORD(wParam)) {
489 // User clicked shaft left of the scroll box.
491 case SB_PAGEUP:
492 xInc = -(int) si.nPage;
493 break;
495 // User clicked shaft right of the scroll box.
497 case SB_PAGEDOWN:
498 xInc = si.nPage;
499 break;
501 // User clicked the left arrow.
503 case SB_LINEUP:
504 xInc = -1;
505 break;
507 // User clicked the right arrow.
509 case SB_LINEDOWN:
510 xInc = 1;
511 break;
513 // User dragged the scroll box.
515 case SB_THUMBTRACK:
516 xInc = HIWORD(wParam) - data->xPos;
517 break;
519 default:
520 xInc = 0;
523 // If applying the horizontal scrolling increment does not
524 // take the scrolling position out of the scrolling range,
525 // increment the scrolling position, adjust the position
526 // of the scroll box, and update the window.
528 if (xInc = max(-data->xPos, min(xInc, data->xMax - data->xPos))) {
529 data->xPos += xInc;
530 ScrollWindowEx(hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL,
531 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
532 SW_INVALIDATE | SW_ERASE);
534 ZeroMemory(&si, sizeof(si));
535 si.cbSize = sizeof(si);
536 si.fMask = SIF_POS;
537 si.nPos = data->xPos;
538 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
539 UpdateWindow(hWnd);
542 #endif // MSG_WRAP_TEXT
544 COLORREF
545 setMsgTextColor(HDC hdc, int gray)
547 COLORREF fg, color1, color2;
548 if (gray) {
549 if (message_bg_brush) {
550 color1 = message_bg_color;
551 color2 = message_fg_color;
552 } else {
553 color1 = (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MSG);
554 color2 = (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MSG);
556 /* Make a "gray" color by taking the average of the individual R,G,B
557 components of two colors. Thanks to Jonathan del Strother */
558 fg = RGB((GetRValue(color1) + GetRValue(color2)) / 2,
559 (GetGValue(color1) + GetGValue(color2)) / 2,
560 (GetBValue(color1) + GetBValue(color2)) / 2);
561 } else {
562 fg = message_fg_brush ? message_fg_color
563 : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MSG);
566 return SetTextColor(hdc, fg);
569 void
570 onPaint(HWND hWnd)
572 PAINTSTRUCT ps;
573 HDC hdc;
574 PNHMessageWindow data;
575 RECT client_rt, draw_rt;
576 int FirstLine, LastLine;
577 int i, x, y;
578 HGDIOBJ oldFont;
579 TCHAR wbuf[MAXWINDOWTEXT + 2];
580 size_t wlen;
581 COLORREF OldBg, OldFg;
583 hdc = BeginPaint(hWnd, &ps);
585 OldBg = SetBkColor(
586 hdc, message_bg_brush ? message_bg_color
587 : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MSG));
588 OldFg = setMsgTextColor(hdc, 0);
590 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
592 GetClientRect(hWnd, &client_rt);
594 if (!IsRectEmpty(&ps.rcPaint)) {
595 FirstLine = max(
596 0, data->yPos - (client_rt.bottom - ps.rcPaint.top) / data->yChar
597 + 1);
598 LastLine =
599 min(MSG_LINES - 1,
600 data->yPos
601 - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar);
602 y = min(ps.rcPaint.bottom, client_rt.bottom);
603 for (i = LastLine; i >= FirstLine; i--) {
604 x = data->xChar * (2 - data->xPos);
606 draw_rt.left = x;
607 draw_rt.right = client_rt.right;
608 draw_rt.top = y - data->yChar;
609 draw_rt.bottom = y;
611 oldFont = SelectObject(
612 hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr,
613 hdc, FALSE));
615 /* convert to UNICODE */
616 NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
617 wlen = _tcslen(wbuf);
618 setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
619 #ifdef MSG_WRAP_TEXT
620 /* Find out how large the bounding rectangle of the text is */
621 DrawText(hdc, wbuf, wlen, &draw_rt,
622 DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
623 /* move that rectangle up, so that the bottom remains at the same
624 * height */
625 draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
626 draw_rt.bottom = y;
628 /* Now really draw it */
629 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
631 /* Find out the cursor (caret) position */
632 if (i == MSG_LINES - 1) {
633 int nnum, numfit;
634 SIZE size;
635 TCHAR *nbuf;
636 int nlen;
638 nbuf = wbuf;
639 nlen = wlen;
640 while (nlen) {
641 /* Get the number of characters that fit on the line */
642 GetTextExtentExPoint(hdc, nbuf, nlen,
643 draw_rt.right - draw_rt.left,
644 &numfit, NULL, &size);
645 /* Search back to a space */
646 nnum = numfit;
647 if (numfit < nlen) {
648 while (nnum > 0 && nbuf[nnum] != ' ')
649 nnum--;
650 /* If no space found, break wherever */
651 if (nnum == 0)
652 nnum = numfit;
654 nbuf += nnum;
655 nlen -= nnum;
656 if (*nbuf == ' ') {
657 nbuf++;
658 nlen--;
661 /* The last size is the size of the last line. Set the caret
662 there.
663 This will fail automatically if we don't own the caret
664 (i.e.,
665 when not in a question.)
667 SetCaretPos(draw_rt.left + size.cx,
668 draw_rt.bottom - data->yChar);
670 #else
671 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX);
672 SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar);
673 #endif
674 SelectObject(hdc, oldFont);
675 y -= draw_rt.bottom - draw_rt.top;
678 SetTextColor(hdc, OldFg);
679 SetBkColor(hdc, OldBg);
680 EndPaint(hWnd, &ps);
683 void
684 onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
686 PNHMessageWindow data;
687 SIZE dummy;
689 UNREFERENCED_PARAMETER(wParam);
690 UNREFERENCED_PARAMETER(lParam);
692 /* set window data */
693 data = (PNHMessageWindow) malloc(sizeof(NHMessageWindow));
694 if (!data)
695 panic("out of memory");
696 ZeroMemory(data, sizeof(NHMessageWindow));
697 data->max_text = MAXWINDOWTEXT;
698 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
700 /* re-calculate window size (+ font size) */
701 mswin_message_window_size(hWnd, &dummy);
704 void
705 mswin_message_window_size(HWND hWnd, LPSIZE sz)
707 HDC hdc;
708 HGDIOBJ saveFont;
709 TEXTMETRIC tm;
710 PNHMessageWindow data;
711 RECT rt, client_rt;
713 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
714 if (!data)
715 return;
717 /* -- Calculate the font size -- */
718 /* Get the handle to the client area's device context. */
719 hdc = GetDC(hWnd);
720 saveFont =
721 SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
723 /* Extract font dimensions from the text metrics. */
724 GetTextMetrics(hdc, &tm);
725 data->xChar = tm.tmAveCharWidth;
726 data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar / 2;
727 data->yChar = tm.tmHeight + tm.tmExternalLeading;
728 data->xPage = 1;
730 /* Free the device context. */
731 SelectObject(hdc, saveFont);
732 ReleaseDC(hWnd, hdc);
734 /* -- calculate window size -- */
735 GetWindowRect(hWnd, &rt);
736 sz->cx = rt.right - rt.left;
737 sz->cy = rt.bottom - rt.top;
739 /* set size to accomodate MSG_VISIBLE_LINES and
740 horizontal scroll bar (difference between window rect and client rect
742 GetClientRect(hWnd, &client_rt);
743 sz->cy = sz->cy - (client_rt.bottom - client_rt.top)
744 + data->yChar * MSG_VISIBLE_LINES;
747 /* check if text can be appended to the last line without wrapping */
748 BOOL
749 can_append_text(HWND hWnd, int attr, const char *text)
751 PNHMessageWindow data;
752 char tmptext[MAXWINDOWTEXT + 1];
753 HDC hdc;
754 HGDIOBJ saveFont;
755 RECT draw_rt;
756 BOOL retval = FALSE;
758 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
760 /* cannot append if lines_not_seen is 0 (beginning of the new turn */
761 if (data->lines_not_seen == 0)
762 return FALSE;
764 /* cannot append text with different attrbutes */
765 if (data->window_text[MSG_LINES - 1].attr != attr)
766 return FALSE;
768 /* check if the maximum string langth will be exceeded */
769 if (strlen(data->window_text[MSG_LINES - 1].text) + 2
770 + /* space characters */
771 strlen(text) + strlen(MORE)
772 >= MAXWINDOWTEXT)
773 return FALSE;
775 /* check if the text is goinf to fin into a single line */
776 strcpy(tmptext, data->window_text[MSG_LINES - 1].text);
777 strcat(tmptext, " ");
778 strcat(tmptext, text);
779 strcat(tmptext, MORE);
781 hdc = GetDC(hWnd);
782 saveFont = SelectObject(
783 hdc,
784 mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES - 1].attr,
785 hdc, FALSE));
786 GetClientRect(hWnd, &draw_rt);
787 draw_rt.bottom = draw_rt.top; /* we only need width for the DrawText */
788 DrawText(hdc, tmptext, strlen(tmptext), &draw_rt,
789 DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
791 /* we will check against 1.5 of the font size in order to determine
792 if the text is single-line or not - just to be on the safe size */
793 retval = (draw_rt.bottom - draw_rt.top) < (data->yChar + data->yChar / 2);
795 /* free device context */
796 SelectObject(hdc, saveFont);
797 ReleaseDC(hWnd, hdc);
798 return retval;
801 /* check if "--more--" prompt needs to be displayed
802 basically, check if the lines not seen are going to find in the message
803 window
805 BOOL
806 more_prompt_check(HWND hWnd)
808 PNHMessageWindow data;
809 HDC hdc;
810 HGDIOBJ saveFont;
811 RECT client_rt, draw_rt;
812 int i;
813 int remaining_height;
814 char tmptext[MAXWINDOWTEXT + 1];
816 data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
818 if (data->lines_not_seen == 0)
819 return FALSE; /* don't bother checking - nothig to "more" */
820 if (data->lines_not_seen >= MSG_LINES)
821 return TRUE; /* history size exceeded - always more */
823 GetClientRect(hWnd, &client_rt);
824 remaining_height = client_rt.bottom - client_rt.top;
826 hdc = GetDC(hWnd);
827 saveFont =
828 SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
829 for (i = 0; i < data->lines_not_seen; i++) {
830 /* we only need width for the DrawText */
831 SetRect(&draw_rt, client_rt.left, client_rt.top, client_rt.right,
832 client_rt.top);
833 SelectObject(hdc,
834 mswin_get_font(NHW_MESSAGE,
835 data->window_text[MSG_LINES - i - 1].attr,
836 hdc, FALSE));
838 strcpy(tmptext, data->window_text[MSG_LINES - i - 1].text);
839 if (i == 0)
840 strcat(tmptext, MORE);
842 remaining_height -=
843 DrawText(hdc, tmptext, strlen(tmptext), &draw_rt,
844 DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
845 if (remaining_height <= 0)
846 break;
849 /* free device context */
850 SelectObject(hdc, saveFont);
851 ReleaseDC(hWnd, hdc);
852 return (remaining_height
853 <= 0); /* TRUE if lines_not_seen take more that window height */