1 /* NetHack 3.6 mhmsgwnd.c $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
14 #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2)
15 #define MAX_MSG_LINES 32
16 #define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES)
17 #define MAXWINDOWTEXT 200
21 char text[MAXWINDOWTEXT];
24 typedef struct mswin_nethack_message_window {
26 struct window_line window_text[MAX_MSG_LINES];
28 int xChar; /* horizontal scrolling unit */
29 int yChar; /* vertical scrolling unit */
30 int xUpper; /* average width of uppercase letters */
31 int xPos; /* current horizontal scrolling position */
32 int yPos; /* current vertical scrolling position */
33 int xMax; /* maximum horizontal scrolling position */
34 int yMax; /* maximum vertical scrolling position */
35 int xPage; /* page size of horizontal scroll bar */
36 int lines_last_turn; /* lines added during the last turn */
37 int dont_care; /* flag the user does not care if messages are lost */
38 } NHMessageWindow, *PNHMessageWindow;
40 static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
41 LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
42 static void register_message_window_class();
43 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
44 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
46 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
48 static COLORREF setMsgTextColor(HDC hdc, int gray);
49 static void onPaint(HWND hWnd);
50 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
53 extern void play_sound_for_message(const char *str);
57 mswin_init_message_window()
59 static int run_once = 0;
64 register_message_window_class();
69 style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
71 style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
75 szMessageWindowClass, /* registered class name */
76 NULL, /* window name */
77 style, /* window style */
78 0, /* horizontal position of window */
79 0, /* vertical position of window */
81 0, /* window height - set it later */
82 GetNHApp()->hMainWnd, /* handle to parent or owner window */
83 NULL, /* menu handle or child identifier */
84 GetNHApp()->hApp, /* handle to application instance */
85 NULL); /* window-creation data */
88 panic("Cannot create message window");
94 register_message_window_class()
97 ZeroMemory(&wcex, sizeof(wcex));
99 wcex.style = CS_NOCLOSE;
100 wcex.lpfnWndProc = (WNDPROC) NHMessageWndProc;
103 wcex.hInstance = GetNHApp()->hApp;
105 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
106 wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG);
107 wcex.lpszMenuName = NULL;
108 wcex.lpszClassName = szMessageWindowClass;
110 RegisterClass(&wcex);
114 NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
118 onCreate(hWnd, wParam, lParam);
121 case WM_MSNH_COMMAND:
122 onMSNHCommand(hWnd, wParam, lParam);
130 SetFocus(GetNHApp()->hMainWnd);
133 #ifndef MSG_WRAP_TEXT
135 onMSNH_HScroll(hWnd, wParam, lParam);
140 onMSNH_VScroll(hWnd, wParam, lParam);
144 PNHMessageWindow data;
145 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
147 SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0);
154 PNHMessageWindow data;
156 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
158 xNewSize = LOWORD(lParam);
159 yNewSize = HIWORD(lParam);
161 if (xNewSize > 0 || yNewSize > 0) {
162 #ifndef MSG_WRAP_TEXT
163 data->xPage = xNewSize / data->xChar;
164 data->xMax = max(0, (int) (1 + data->max_text - data->xPage));
165 data->xPos = min(data->xPos, data->xMax);
167 ZeroMemory(&si, sizeof(si));
168 si.cbSize = sizeof(si);
169 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
171 si.nMax = data->max_text;
172 si.nPage = data->xPage;
173 si.nPos = data->xPos;
174 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
177 data->yMax = MSG_LINES - 1;
178 data->yPos = min(data->yPos, data->yMax);
180 ZeroMemory(&si, sizeof(si));
181 si.cbSize = sizeof(si);
182 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
183 si.nMin = MSG_VISIBLE_LINES;
184 si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
185 si.nPage = MSG_VISIBLE_LINES;
186 si.nPos = data->yPos;
187 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
192 return DefWindowProc(hWnd, message, wParam, lParam);
198 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
200 PNHMessageWindow data;
202 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
204 case MSNH_MSG_PUTSTR: {
205 PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam;
209 if (msg_data->append) {
210 strncat(data->window_text[MSG_LINES - 1].text, msg_data->text,
212 - strlen(data->window_text[MSG_LINES - 1].text));
214 /* check if the string is empty */
215 for (p = data->window_text[MSG_LINES - 1].text; *p && isspace(*p);
220 /* last string is not empty - scroll up */
221 memmove(&data->window_text[0], &data->window_text[1],
222 (MSG_LINES - 1) * sizeof(data->window_text[0]));
225 /* append new text to the end of the array */
226 data->window_text[MSG_LINES - 1].attr = msg_data->attr;
227 strncpy(data->window_text[MSG_LINES - 1].text, msg_data->text,
231 /* reset V-scroll position to display new text */
232 data->yPos = data->yMax;
234 ZeroMemory(&si, sizeof(si));
235 si.cbSize = sizeof(si);
237 si.nPos = data->yPos;
238 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
240 /* deal with overflows */
241 data->lines_last_turn++;
242 if (!data->dont_care && data->lines_last_turn >= MSG_LINES - 2) {
246 /* append "--More--" to the message window text (cannot call
248 here - infinite recursion) */
249 memmove(&data->window_text[0], &data->window_text[1],
250 (MSG_LINES - 1) * sizeof(data->window_text[0]));
251 data->window_text[MSG_LINES - 1].attr = ATR_NONE;
252 strncpy(data->window_text[MSG_LINES - 1].text, "--More--",
255 /* update window content */
256 InvalidateRect(hWnd, NULL, TRUE);
258 #if defined(WIN_CE_SMARTPHONE)
259 NHSPhoneSetKeypadFromString("\033- <>");
265 c = mswin_nh_poskey(&x, &y, &mod);
267 /* ESC indicates that we can safely discard any further
268 * messages during this turn */
275 SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0),
280 SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0),
284 /* continue scrolling on any key */
286 data->lines_last_turn = 0;
292 #if defined(WIN_CE_SMARTPHONE)
293 NHSPhoneSetKeypadDefault();
295 /* remove "--More--" from the message window text */
296 data->window_text[MSG_LINES - 1].attr = ATR_NONE;
297 strncpy(data->window_text[MSG_LINES - 1].text, " ",
301 /* update window content */
302 InvalidateRect(hWnd, NULL, TRUE);
305 play_sound_for_message(msg_data->text);
309 case MSNH_MSG_CLEAR_WINDOW:
310 data->lines_last_turn = 0;
317 onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
319 PNHMessageWindow data;
323 /* get window data */
324 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
326 ZeroMemory(&si, sizeof(si));
327 si.cbSize = sizeof(si);
328 si.fMask = SIF_PAGE | SIF_POS;
329 GetScrollInfo(hWnd, SB_VERT, &si);
331 switch (LOWORD(wParam)) {
332 // User clicked the shaft above the scroll box.
335 yInc = -(int) si.nPage;
338 // User clicked the shaft below the scroll box.
344 // User clicked the top arrow.
350 // User clicked the bottom arrow.
356 // User dragged the scroll box.
359 yInc = HIWORD(wParam) - data->yPos;
366 // If applying the vertical scrolling increment does not
367 // take the scrolling position out of the scrolling range,
368 // increment the scrolling position, adjust the position
369 // of the scroll box, and update the window. UpdateWindow
370 // sends the WM_PAINT message.
372 if (yInc = max(MSG_VISIBLE_LINES - data->yPos,
373 min(yInc, data->yMax - data->yPos))) {
375 /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
376 (CONST RECT *) NULL, (CONST RECT *) NULL,
377 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
379 InvalidateRect(hWnd, NULL, TRUE);
381 ZeroMemory(&si, sizeof(si));
382 si.cbSize = sizeof(si);
384 si.nPos = data->yPos;
385 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
391 #ifndef MSG_WRAP_TEXT
393 onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
395 PNHMessageWindow data;
399 /* get window data */
400 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
402 ZeroMemory(&si, sizeof(si));
403 si.cbSize = sizeof(si);
405 GetScrollInfo(hWnd, SB_HORZ, &si);
407 switch (LOWORD(wParam)) {
408 // User clicked shaft left of the scroll box.
411 xInc = -(int) si.nPage;
414 // User clicked shaft right of the scroll box.
420 // User clicked the left arrow.
426 // User clicked the right arrow.
432 // User dragged the scroll box.
435 xInc = HIWORD(wParam) - data->xPos;
442 // If applying the horizontal scrolling increment does not
443 // take the scrolling position out of the scrolling range,
444 // increment the scrolling position, adjust the position
445 // of the scroll box, and update the window.
447 if (xInc = max(-data->xPos, min(xInc, data->xMax - data->xPos))) {
449 ScrollWindowEx(hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL,
450 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
451 SW_INVALIDATE | SW_ERASE);
453 ZeroMemory(&si, sizeof(si));
454 si.cbSize = sizeof(si);
456 si.nPos = data->xPos;
457 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
461 #endif // MSG_WRAP_TEXT
464 setMsgTextColor(HDC hdc, int gray)
466 COLORREF fg, color1, color2;
468 color1 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG);
469 color2 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG);
470 /* Make a "gray" color by taking the average of the individual R,G,B
471 components of two colors. Thanks to Jonathan del Strother */
472 fg = RGB((GetRValue(color1) + GetRValue(color2)) / 2,
473 (GetGValue(color1) + GetGValue(color2)) / 2,
474 (GetBValue(color1) + GetBValue(color2)) / 2);
476 fg = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG);
479 return SetTextColor(hdc, fg);
487 PNHMessageWindow data;
488 RECT client_rt, draw_rt;
489 int FirstLine, LastLine;
492 TCHAR wbuf[MAXWINDOWTEXT + 2];
494 COLORREF OldBg, OldFg;
496 hdc = BeginPaint(hWnd, &ps);
498 OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG));
499 OldFg = setMsgTextColor(hdc, 0);
501 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
503 GetClientRect(hWnd, &client_rt);
505 if (!IsRectEmpty(&ps.rcPaint)) {
507 0, data->yPos - (client_rt.bottom - ps.rcPaint.top) / data->yChar
512 - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar);
513 y = min(ps.rcPaint.bottom, client_rt.bottom - 2);
514 for (i = LastLine; i >= FirstLine; i--) {
515 if (i == MSG_LINES - 1) {
516 x = data->xChar * (2 - data->xPos);
518 x = data->xChar * (4 - data->xPos);
521 if (strlen(data->window_text[i].text) > 0) {
522 /* convert to UNICODE */
523 NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
524 wlen = _tcslen(wbuf);
526 /* calculate text height */
528 draw_rt.right = client_rt.right;
529 draw_rt.top = y - data->yChar;
532 oldFont = SelectObject(
534 mswin_get_font(NHW_MESSAGE, data->window_text[i].attr,
537 setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
539 DrawText(hdc, wbuf, wlen, &draw_rt,
540 DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
541 draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
543 DrawText(hdc, wbuf, wlen, &draw_rt,
544 DT_NOPREFIX | DT_WORDBREAK);
546 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX);
548 SelectObject(hdc, oldFont);
550 y -= draw_rt.bottom - draw_rt.top;
557 SetTextColor(hdc, OldFg);
558 SetBkColor(hdc, OldBg);
563 onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
567 PNHMessageWindow data;
570 /* set window data */
571 data = (PNHMessageWindow) malloc(sizeof(NHMessageWindow));
573 panic("out of memory");
574 ZeroMemory(data, sizeof(NHMessageWindow));
575 data->max_text = MAXWINDOWTEXT;
576 SetWindowLong(hWnd, GWL_USERDATA, (LONG) data);
578 /* Get the handle to the client area's device context. */
581 SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
583 /* Extract font dimensions from the text metrics. */
584 GetTextMetrics(hdc, &tm);
585 data->xChar = tm.tmAveCharWidth;
586 data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar / 2;
587 data->yChar = tm.tmHeight + tm.tmExternalLeading;
590 /* Free the device context. */
591 SelectObject(hdc, saveFont);
592 ReleaseDC(hWnd, hdc);
594 /* create command pad (keyboard emulator) */
595 if (!GetNHApp()->hCmdWnd)
596 GetNHApp()->hCmdWnd = mswin_init_command_window();
600 mswin_message_window_size(HWND hWnd, LPSIZE sz)
602 PNHMessageWindow data;
605 GetWindowRect(hWnd, &rt);
607 sz->cx = rt.right - rt.left;
608 sz->cy = rt.bottom - rt.top;
610 data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
612 /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and
613 horizontal scroll bar (difference between window rect and client
615 GetClientRect(hWnd, &client_rt);
616 sz->cy = sz->cy - (client_rt.bottom - client_rt.top)
617 + data->yChar * MSG_VISIBLE_LINES + 4;