1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed. See license for details. */
13 #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2)
14 #define MAX_MSG_LINES 32
15 #define MSG_LINES (int)min(iflags.msg_history, MAX_MSG_LINES)
16 #define MAXWINDOWTEXT 200
20 char text[MAXWINDOWTEXT];
23 typedef struct mswin_nethack_message_window {
25 struct window_line window_text[MAX_MSG_LINES];
27 int xChar; /* horizontal scrolling unit */
28 int yChar; /* vertical scrolling unit */
29 int xUpper; /* average width of uppercase letters */
30 int xPos; /* current horizontal scrolling position */
31 int yPos; /* current vertical scrolling position */
32 int xMax; /* maximum horizontal scrolling position */
33 int yMax; /* maximum vertical scrolling position */
34 int xPage; /* page size of horizontal scroll bar */
35 int lines_last_turn; /* lines added during the last turn */
36 int dont_care; /* flag the the user does not care if messages are lost */
37 } NHMessageWindow, *PNHMessageWindow;
39 static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
40 LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
41 static void register_message_window_class();
42 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
43 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
45 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
47 static void onPaint(HWND hWnd);
48 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
51 extern void play_sound_for_message(const char* str);
54 HWND mswin_init_message_window () {
55 static int run_once = 0;
60 register_message_window_class( );
65 style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
67 style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
71 szMessageWindowClass, /* registered class name */
72 NULL, /* window name */
73 style, /* window style */
74 0, /* horizontal position of window */
75 0, /* vertical position of window */
77 0, /* window height - set it later */
78 GetNHApp()->hMainWnd, /* handle to parent or owner window */
79 NULL, /* menu handle or child identifier */
80 GetNHApp()->hApp, /* handle to application instance */
81 NULL ); /* window-creation data */
83 if( !ret ) panic("Cannot create message window");
88 void register_message_window_class()
91 ZeroMemory( &wcex, sizeof(wcex));
93 wcex.style = CS_NOCLOSE;
94 wcex.lpfnWndProc = (WNDPROC)NHMessageWndProc;
97 wcex.hInstance = GetNHApp()->hApp;
99 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
100 wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG);
101 wcex.lpszMenuName = NULL;
102 wcex.lpszClassName = szMessageWindowClass;
104 RegisterClass(&wcex);
107 LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
112 onCreate( hWnd, wParam, lParam );
115 case WM_MSNH_COMMAND:
116 onMSNHCommand(hWnd, wParam, lParam);
124 SetFocus(GetNHApp()->hMainWnd);
127 #ifndef MSG_WRAP_TEXT
129 onMSNH_HScroll(hWnd, wParam, lParam);
134 onMSNH_VScroll(hWnd, wParam, lParam);
139 PNHMessageWindow data;
140 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
142 SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
150 PNHMessageWindow data;
152 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
154 xNewSize = LOWORD(lParam);
155 yNewSize = HIWORD(lParam);
157 if( xNewSize>0 || yNewSize>0 ) {
159 #ifndef MSG_WRAP_TEXT
160 data->xPage = xNewSize/data->xChar;
161 data->xMax = max(0, (int)(1 + data->max_text - data->xPage));
162 data->xPos = min(data->xPos, data->xMax);
164 ZeroMemory(&si, sizeof(si));
165 si.cbSize = sizeof(si);
166 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
168 si.nMax = data->max_text;
169 si.nPage = data->xPage;
170 si.nPos = data->xPos;
171 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
174 data->yMax = MSG_LINES-1;
175 data->yPos = min(data->yPos, data->yMax);
177 ZeroMemory(&si, sizeof(si));
178 si.cbSize = sizeof(si);
179 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
180 si.nMin = MSG_VISIBLE_LINES;
181 si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
182 si.nPage = MSG_VISIBLE_LINES;
183 si.nPos = data->yPos;
184 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
190 return DefWindowProc(hWnd, message, wParam, lParam);
195 void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
197 PNHMessageWindow data;
199 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
201 case MSNH_MSG_PUTSTR:
203 PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
207 if( msg_data->append ) {
208 strncat(data->window_text[MSG_LINES-1].text, msg_data->text,
209 MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text));
211 /* check if the string is empty */
212 for(p = data->window_text[MSG_LINES-1].text; *p && isspace(*p); p++);
215 /* last string is not empty - scroll up */
216 memmove(&data->window_text[0],
217 &data->window_text[1],
218 (MSG_LINES-1)*sizeof(data->window_text[0]));
221 /* append new text to the end of the array */
222 data->window_text[MSG_LINES-1].attr = msg_data->attr;
223 strncpy(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT);
226 /* reset V-scroll position to display new text */
227 data->yPos = data->yMax;
229 ZeroMemory(&si, sizeof(si));
230 si.cbSize = sizeof(si);
232 si.nPos = data->yPos;
233 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
235 /* deal with overflows */
236 data->lines_last_turn++;
237 if( !data->dont_care && data->lines_last_turn>=MSG_LINES-2 ) {
241 /* append "--More--" to the message window text (cannot call putstr
242 here - infinite recursion) */
243 memmove(&data->window_text[0],
244 &data->window_text[1],
245 (MSG_LINES-1)*sizeof(data->window_text[0]));
246 data->window_text[MSG_LINES-1].attr = ATR_NONE;
247 strncpy(data->window_text[MSG_LINES-1].text, "--More--", MAXWINDOWTEXT);
249 /* update window content */
250 InvalidateRect(hWnd, NULL, TRUE);
252 #if defined(WIN_CE_SMARTPHONE)
253 NHSPhoneSetKeypadFromString( "\033- <>" );
259 c = mswin_nh_poskey(&x, &y, &mod);
261 /* ESC indicates that we can safely discard any further messages during this turn */
268 SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
272 SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
275 /* continue scrolling on any key */
277 data->lines_last_turn = 0;
283 #if defined(WIN_CE_SMARTPHONE)
284 NHSPhoneSetKeypadDefault();
286 /* remove "--More--" from the message window text */
287 data->window_text[MSG_LINES-1].attr = ATR_NONE;
288 strncpy(data->window_text[MSG_LINES-1].text, " ", MAXWINDOWTEXT);
291 /* update window content */
292 InvalidateRect(hWnd, NULL, TRUE);
295 play_sound_for_message(msg_data->text);
300 case MSNH_MSG_CLEAR_WINDOW:
301 data->lines_last_turn = 0;
307 void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
309 PNHMessageWindow data;
313 /* get window data */
314 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
316 ZeroMemory(&si, sizeof(si));
317 si.cbSize = sizeof(si);
318 si.fMask = SIF_PAGE | SIF_POS;
319 GetScrollInfo(hWnd, SB_VERT, &si);
321 switch(LOWORD (wParam))
323 // User clicked the shaft above the scroll box.
326 yInc = -(int)si.nPage;
329 // User clicked the shaft below the scroll box.
335 // User clicked the top arrow.
341 // User clicked the bottom arrow.
347 // User dragged the scroll box.
350 yInc = HIWORD(wParam) - data->yPos;
357 // If applying the vertical scrolling increment does not
358 // take the scrolling position out of the scrolling range,
359 // increment the scrolling position, adjust the position
360 // of the scroll box, and update the window. UpdateWindow
361 // sends the WM_PAINT message.
363 if (yInc = max( MSG_VISIBLE_LINES - data->yPos,
364 min(yInc, data->yMax - data->yPos)))
367 /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
368 (CONST RECT *) NULL, (CONST RECT *) NULL,
369 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
371 InvalidateRect(hWnd, NULL, TRUE);
373 ZeroMemory(&si, sizeof(si));
374 si.cbSize = sizeof(si);
376 si.nPos = data->yPos;
377 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
383 #ifndef MSG_WRAP_TEXT
384 void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
386 PNHMessageWindow data;
390 /* get window data */
391 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
393 ZeroMemory(&si, sizeof(si));
394 si.cbSize = sizeof(si);
396 GetScrollInfo(hWnd, SB_HORZ, &si);
398 switch(LOWORD (wParam))
400 // User clicked shaft left of the scroll box.
403 xInc = - (int)si.nPage;
406 // User clicked shaft right of the scroll box.
412 // User clicked the left arrow.
418 // User clicked the right arrow.
424 // User dragged the scroll box.
427 xInc = HIWORD(wParam) - data->xPos;
436 // If applying the horizontal scrolling increment does not
437 // take the scrolling position out of the scrolling range,
438 // increment the scrolling position, adjust the position
439 // of the scroll box, and update the window.
441 if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos)))
444 ScrollWindowEx (hWnd, -data->xChar * xInc, 0,
445 (CONST RECT *) NULL, (CONST RECT *) NULL,
446 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
448 ZeroMemory(&si, sizeof(si));
449 si.cbSize = sizeof(si);
451 si.nPos = data->xPos;
452 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
456 #endif // MSG_WRAP_TEXT
458 void onPaint(HWND hWnd)
462 PNHMessageWindow data;
463 RECT client_rt, draw_rt;
464 int FirstLine, LastLine;
467 TCHAR wbuf[MAXWINDOWTEXT+2];
469 COLORREF OldBg, OldFg;
471 hdc = BeginPaint(hWnd, &ps);
473 OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG));
474 OldFg = SetTextColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG));
476 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
478 GetClientRect(hWnd, &client_rt);
480 if( !IsRectEmpty(&ps.rcPaint) ) {
481 FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1);
482 LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar);
483 y = min( ps.rcPaint.bottom, client_rt.bottom - 2);
484 for (i=LastLine; i>=FirstLine; i--) {
485 if( i==MSG_LINES-1 ) {
486 x = data->xChar * (2 - data->xPos);
488 x = data->xChar * (4 - data->xPos);
492 if( strlen(data->window_text[i].text)>0 ) {
493 /* convert to UNICODE */
494 NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
495 wlen = _tcslen(wbuf);
497 /* calculate text height */
499 draw_rt.right = client_rt.right;
500 draw_rt.top = y - data->yChar;
503 oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE));
506 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
507 draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
509 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
511 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX );
513 SelectObject(hdc, oldFont);
515 y -= draw_rt.bottom - draw_rt.top;
520 /* highligh the last line */
521 if( i==MSG_LINES-1 ) {
522 draw_rt.left = client_rt.left;
523 draw_rt.right = draw_rt.left + 2*data->xChar;
524 DrawText(hdc, TEXT("> "), 2, &draw_rt, DT_NOPREFIX );
527 draw_rt.left = client_rt.left;
528 draw_rt.right = client_rt.right;
530 draw_rt.bottom = client_rt.bottom;
531 DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_TOP );
532 DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_BOTTOM );
537 SetTextColor (hdc, OldFg);
538 SetBkColor (hdc, OldBg);
542 void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
546 PNHMessageWindow data;
549 /* set window data */
550 data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow));
551 if( !data ) panic("out of memory");
552 ZeroMemory(data, sizeof(NHMessageWindow));
553 data->max_text = MAXWINDOWTEXT;
554 SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
556 /* Get the handle to the client area's device context. */
558 saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
560 /* Extract font dimensions from the text metrics. */
561 GetTextMetrics (hdc, &tm);
562 data->xChar = tm.tmAveCharWidth;
563 data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2;
564 data->yChar = tm.tmHeight + tm.tmExternalLeading;
567 /* Free the device context. */
568 SelectObject(hdc, saveFont);
569 ReleaseDC (hWnd, hdc);
572 void mswin_message_window_size (HWND hWnd, LPSIZE sz)
574 PNHMessageWindow data;
577 GetWindowRect(hWnd, &rt);
579 sz->cx = rt.right - rt.left;
580 sz->cy = rt.bottom - rt.top;
582 data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
584 /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and
585 horizontal scroll bar (difference between window rect and client rect */
586 GetClientRect(hWnd, &client_rt);
587 sz->cy = sz->cy-(client_rt.bottom - client_rt.top) +
588 data->yChar * MSG_VISIBLE_LINES + 4;