PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/sys/wince/mhmsgwnd.c

https://github.com/tung/nethackds
C | 591 lines | 429 code | 114 blank | 48 comment | 24 complexity | e50c4632b3970d46dfe8b02f2b4d874f MD5 | raw file
  1. /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
  2. /* NetHack may be freely redistributed. See license for details. */
  3. #include "winMS.h"
  4. #include "mhmsgwnd.h"
  5. #include "mhmsg.h"
  6. #include "mhcmd.h"
  7. #include "mhfont.h"
  8. #include "mhcolor.h"
  9. #define MSG_WRAP_TEXT
  10. #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2)
  11. #define MAX_MSG_LINES 32
  12. #define MSG_LINES (int)min(iflags.msg_history, MAX_MSG_LINES)
  13. #define MAXWINDOWTEXT 200
  14. struct window_line {
  15. int attr;
  16. char text[MAXWINDOWTEXT];
  17. };
  18. typedef struct mswin_nethack_message_window {
  19. size_t max_text;
  20. struct window_line window_text[MAX_MSG_LINES];
  21. int xChar; /* horizontal scrolling unit */
  22. int yChar; /* vertical scrolling unit */
  23. int xUpper; /* average width of uppercase letters */
  24. int xPos; /* current horizontal scrolling position */
  25. int yPos; /* current vertical scrolling position */
  26. int xMax; /* maximum horizontal scrolling position */
  27. int yMax; /* maximum vertical scrolling position */
  28. int xPage; /* page size of horizontal scroll bar */
  29. int lines_last_turn; /* lines added during the last turn */
  30. int dont_care; /* flag the the user does not care if messages are lost */
  31. } NHMessageWindow, *PNHMessageWindow;
  32. static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
  33. LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
  34. static void register_message_window_class();
  35. static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
  36. static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
  37. #ifndef MSG_WRAP_TEXT
  38. static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
  39. #endif
  40. static void onPaint(HWND hWnd);
  41. static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
  42. #ifdef USER_SOUNDS
  43. extern void play_sound_for_message(const char* str);
  44. #endif
  45. HWND mswin_init_message_window () {
  46. static int run_once = 0;
  47. HWND ret;
  48. DWORD style;
  49. if( !run_once ) {
  50. register_message_window_class( );
  51. run_once = 1;
  52. }
  53. #ifdef MSG_WRAP_TEXT
  54. style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
  55. #else
  56. style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
  57. #endif
  58. ret = CreateWindow(
  59. szMessageWindowClass, /* registered class name */
  60. NULL, /* window name */
  61. style, /* window style */
  62. 0, /* horizontal position of window */
  63. 0, /* vertical position of window */
  64. 0, /* window width */
  65. 0, /* window height - set it later */
  66. GetNHApp()->hMainWnd, /* handle to parent or owner window */
  67. NULL, /* menu handle or child identifier */
  68. GetNHApp()->hApp, /* handle to application instance */
  69. NULL ); /* window-creation data */
  70. if( !ret ) panic("Cannot create message window");
  71. return ret;
  72. }
  73. void register_message_window_class()
  74. {
  75. WNDCLASS wcex;
  76. ZeroMemory( &wcex, sizeof(wcex));
  77. wcex.style = CS_NOCLOSE;
  78. wcex.lpfnWndProc = (WNDPROC)NHMessageWndProc;
  79. wcex.cbClsExtra = 0;
  80. wcex.cbWndExtra = 0;
  81. wcex.hInstance = GetNHApp()->hApp;
  82. wcex.hIcon = NULL;
  83. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  84. wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG);
  85. wcex.lpszMenuName = NULL;
  86. wcex.lpszClassName = szMessageWindowClass;
  87. RegisterClass(&wcex);
  88. }
  89. LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  90. {
  91. switch (message)
  92. {
  93. case WM_CREATE:
  94. onCreate( hWnd, wParam, lParam );
  95. break;
  96. case WM_MSNH_COMMAND:
  97. onMSNHCommand(hWnd, wParam, lParam);
  98. break;
  99. case WM_PAINT:
  100. onPaint(hWnd);
  101. break;
  102. case WM_SETFOCUS:
  103. SetFocus(GetNHApp()->hMainWnd);
  104. break;
  105. #ifndef MSG_WRAP_TEXT
  106. case WM_HSCROLL:
  107. onMSNH_HScroll(hWnd, wParam, lParam);
  108. break;
  109. #endif
  110. case WM_VSCROLL:
  111. onMSNH_VScroll(hWnd, wParam, lParam);
  112. break;
  113. case WM_DESTROY:
  114. {
  115. PNHMessageWindow data;
  116. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  117. free(data);
  118. SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
  119. } break;
  120. case WM_SIZE:
  121. {
  122. SCROLLINFO si;
  123. int xNewSize;
  124. int yNewSize;
  125. PNHMessageWindow data;
  126. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  127. xNewSize = LOWORD(lParam);
  128. yNewSize = HIWORD(lParam);
  129. if( xNewSize>0 || yNewSize>0 ) {
  130. #ifndef MSG_WRAP_TEXT
  131. data->xPage = xNewSize/data->xChar;
  132. data->xMax = max(0, (int)(1 + data->max_text - data->xPage));
  133. data->xPos = min(data->xPos, data->xMax);
  134. ZeroMemory(&si, sizeof(si));
  135. si.cbSize = sizeof(si);
  136. si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
  137. si.nMin = 0;
  138. si.nMax = data->max_text;
  139. si.nPage = data->xPage;
  140. si.nPos = data->xPos;
  141. SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
  142. #endif
  143. data->yMax = MSG_LINES-1;
  144. data->yPos = min(data->yPos, data->yMax);
  145. ZeroMemory(&si, sizeof(si));
  146. si.cbSize = sizeof(si);
  147. si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
  148. si.nMin = MSG_VISIBLE_LINES;
  149. si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
  150. si.nPage = MSG_VISIBLE_LINES;
  151. si.nPos = data->yPos;
  152. SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
  153. }
  154. }
  155. break;
  156. default:
  157. return DefWindowProc(hWnd, message, wParam, lParam);
  158. }
  159. return 0;
  160. }
  161. void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  162. {
  163. PNHMessageWindow data;
  164. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  165. switch( wParam ) {
  166. case MSNH_MSG_PUTSTR:
  167. {
  168. PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
  169. SCROLLINFO si;
  170. char* p;
  171. if( msg_data->append ) {
  172. strncat(data->window_text[MSG_LINES-1].text, msg_data->text,
  173. MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text));
  174. } else {
  175. /* check if the string is empty */
  176. for(p = data->window_text[MSG_LINES-1].text; *p && isspace(*p); p++);
  177. if( *p ) {
  178. /* last string is not empty - scroll up */
  179. memmove(&data->window_text[0],
  180. &data->window_text[1],
  181. (MSG_LINES-1)*sizeof(data->window_text[0]));
  182. }
  183. /* append new text to the end of the array */
  184. data->window_text[MSG_LINES-1].attr = msg_data->attr;
  185. strncpy(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT);
  186. }
  187. /* reset V-scroll position to display new text */
  188. data->yPos = data->yMax;
  189. ZeroMemory(&si, sizeof(si));
  190. si.cbSize = sizeof(si);
  191. si.fMask = SIF_POS;
  192. si.nPos = data->yPos;
  193. SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
  194. /* deal with overflows */
  195. data->lines_last_turn++;
  196. if( !data->dont_care && data->lines_last_turn>=MSG_LINES-2 ) {
  197. char c;
  198. BOOL done;
  199. /* append "--More--" to the message window text (cannot call putstr
  200. here - infinite recursion) */
  201. memmove(&data->window_text[0],
  202. &data->window_text[1],
  203. (MSG_LINES-1)*sizeof(data->window_text[0]));
  204. data->window_text[MSG_LINES-1].attr = ATR_NONE;
  205. strncpy(data->window_text[MSG_LINES-1].text, "--More--", MAXWINDOWTEXT);
  206. /* update window content */
  207. InvalidateRect(hWnd, NULL, TRUE);
  208. #if defined(WIN_CE_SMARTPHONE)
  209. NHSPhoneSetKeypadFromString( "\033- <>" );
  210. #endif
  211. done = FALSE;
  212. while( !done ) {
  213. int x, y, mod;
  214. c = mswin_nh_poskey(&x, &y, &mod);
  215. switch (c) {
  216. /* ESC indicates that we can safely discard any further messages during this turn */
  217. case '\033':
  218. data->dont_care = 1;
  219. done = TRUE;
  220. break;
  221. case '<':
  222. SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
  223. break;
  224. case '>':
  225. SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
  226. break;
  227. /* continue scrolling on any key */
  228. default:
  229. data->lines_last_turn = 0;
  230. done = TRUE;
  231. break;
  232. }
  233. }
  234. #if defined(WIN_CE_SMARTPHONE)
  235. NHSPhoneSetKeypadDefault();
  236. #endif
  237. /* remove "--More--" from the message window text */
  238. data->window_text[MSG_LINES-1].attr = ATR_NONE;
  239. strncpy(data->window_text[MSG_LINES-1].text, " ", MAXWINDOWTEXT);
  240. }
  241. /* update window content */
  242. InvalidateRect(hWnd, NULL, TRUE);
  243. #ifdef USER_SOUNDS
  244. play_sound_for_message(msg_data->text);
  245. #endif
  246. }
  247. break;
  248. case MSNH_MSG_CLEAR_WINDOW:
  249. data->lines_last_turn = 0;
  250. data->dont_care = 0;
  251. break;
  252. }
  253. }
  254. void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
  255. {
  256. PNHMessageWindow data;
  257. SCROLLINFO si;
  258. int yInc;
  259. /* get window data */
  260. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  261. ZeroMemory(&si, sizeof(si));
  262. si.cbSize = sizeof(si);
  263. si.fMask = SIF_PAGE | SIF_POS;
  264. GetScrollInfo(hWnd, SB_VERT, &si);
  265. switch(LOWORD (wParam))
  266. {
  267. // User clicked the shaft above the scroll box.
  268. case SB_PAGEUP:
  269. yInc = -(int)si.nPage;
  270. break;
  271. // User clicked the shaft below the scroll box.
  272. case SB_PAGEDOWN:
  273. yInc = si.nPage;
  274. break;
  275. // User clicked the top arrow.
  276. case SB_LINEUP:
  277. yInc = -1;
  278. break;
  279. // User clicked the bottom arrow.
  280. case SB_LINEDOWN:
  281. yInc = 1;
  282. break;
  283. // User dragged the scroll box.
  284. case SB_THUMBTRACK:
  285. yInc = HIWORD(wParam) - data->yPos;
  286. break;
  287. default:
  288. yInc = 0;
  289. }
  290. // If applying the vertical scrolling increment does not
  291. // take the scrolling position out of the scrolling range,
  292. // increment the scrolling position, adjust the position
  293. // of the scroll box, and update the window. UpdateWindow
  294. // sends the WM_PAINT message.
  295. if (yInc = max( MSG_VISIBLE_LINES - data->yPos,
  296. min(yInc, data->yMax - data->yPos)))
  297. {
  298. data->yPos += yInc;
  299. /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
  300. (CONST RECT *) NULL, (CONST RECT *) NULL,
  301. (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
  302. */
  303. InvalidateRect(hWnd, NULL, TRUE);
  304. ZeroMemory(&si, sizeof(si));
  305. si.cbSize = sizeof(si);
  306. si.fMask = SIF_POS;
  307. si.nPos = data->yPos;
  308. SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
  309. UpdateWindow (hWnd);
  310. }
  311. }
  312. #ifndef MSG_WRAP_TEXT
  313. void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
  314. {
  315. PNHMessageWindow data;
  316. SCROLLINFO si;
  317. int xInc;
  318. /* get window data */
  319. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  320. ZeroMemory(&si, sizeof(si));
  321. si.cbSize = sizeof(si);
  322. si.fMask = SIF_PAGE;
  323. GetScrollInfo(hWnd, SB_HORZ, &si);
  324. switch(LOWORD (wParam))
  325. {
  326. // User clicked shaft left of the scroll box.
  327. case SB_PAGEUP:
  328. xInc = - (int)si.nPage;
  329. break;
  330. // User clicked shaft right of the scroll box.
  331. case SB_PAGEDOWN:
  332. xInc = si.nPage;
  333. break;
  334. // User clicked the left arrow.
  335. case SB_LINEUP:
  336. xInc = -1;
  337. break;
  338. // User clicked the right arrow.
  339. case SB_LINEDOWN:
  340. xInc = 1;
  341. break;
  342. // User dragged the scroll box.
  343. case SB_THUMBTRACK:
  344. xInc = HIWORD(wParam) - data->xPos;
  345. break;
  346. default:
  347. xInc = 0;
  348. }
  349. // If applying the horizontal scrolling increment does not
  350. // take the scrolling position out of the scrolling range,
  351. // increment the scrolling position, adjust the position
  352. // of the scroll box, and update the window.
  353. if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos)))
  354. {
  355. data->xPos += xInc;
  356. ScrollWindowEx (hWnd, -data->xChar * xInc, 0,
  357. (CONST RECT *) NULL, (CONST RECT *) NULL,
  358. (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
  359. ZeroMemory(&si, sizeof(si));
  360. si.cbSize = sizeof(si);
  361. si.fMask = SIF_POS;
  362. si.nPos = data->xPos;
  363. SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
  364. UpdateWindow (hWnd);
  365. }
  366. }
  367. #endif // MSG_WRAP_TEXT
  368. void onPaint(HWND hWnd)
  369. {
  370. PAINTSTRUCT ps;
  371. HDC hdc;
  372. PNHMessageWindow data;
  373. RECT client_rt, draw_rt;
  374. int FirstLine, LastLine;
  375. int i, x, y;
  376. HGDIOBJ oldFont;
  377. TCHAR wbuf[MAXWINDOWTEXT+2];
  378. size_t wlen;
  379. COLORREF OldBg, OldFg;
  380. hdc = BeginPaint(hWnd, &ps);
  381. OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG));
  382. OldFg = SetTextColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG));
  383. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  384. GetClientRect(hWnd, &client_rt);
  385. if( !IsRectEmpty(&ps.rcPaint) ) {
  386. FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1);
  387. LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar);
  388. y = min( ps.rcPaint.bottom, client_rt.bottom - 2);
  389. for (i=LastLine; i>=FirstLine; i--) {
  390. if( i==MSG_LINES-1 ) {
  391. x = data->xChar * (2 - data->xPos);
  392. } else {
  393. x = data->xChar * (4 - data->xPos);
  394. }
  395. if( strlen(data->window_text[i].text)>0 ) {
  396. /* convert to UNICODE */
  397. NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
  398. wlen = _tcslen(wbuf);
  399. /* calculate text height */
  400. draw_rt.left = x;
  401. draw_rt.right = client_rt.right;
  402. draw_rt.top = y - data->yChar;
  403. draw_rt.bottom = y;
  404. oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE));
  405. #ifdef MSG_WRAP_TEXT
  406. DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
  407. draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
  408. draw_rt.bottom = y;
  409. DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK);
  410. #else
  411. DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX );
  412. #endif
  413. SelectObject(hdc, oldFont);
  414. y -= draw_rt.bottom - draw_rt.top;
  415. } else {
  416. y -= data->yChar;
  417. }
  418. /* highligh the last line */
  419. if( i==MSG_LINES-1 ) {
  420. draw_rt.left = client_rt.left;
  421. draw_rt.right = draw_rt.left + 2*data->xChar;
  422. DrawText(hdc, TEXT("> "), 2, &draw_rt, DT_NOPREFIX );
  423. y -= 2;
  424. draw_rt.left = client_rt.left;
  425. draw_rt.right = client_rt.right;
  426. draw_rt.top -= 2;
  427. draw_rt.bottom = client_rt.bottom;
  428. DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_TOP );
  429. DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_BOTTOM );
  430. }
  431. }
  432. }
  433. SetTextColor (hdc, OldFg);
  434. SetBkColor (hdc, OldBg);
  435. EndPaint(hWnd, &ps);
  436. }
  437. void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
  438. {
  439. HDC hdc;
  440. TEXTMETRIC tm;
  441. PNHMessageWindow data;
  442. HGDIOBJ saveFont;
  443. /* set window data */
  444. data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow));
  445. if( !data ) panic("out of memory");
  446. ZeroMemory(data, sizeof(NHMessageWindow));
  447. data->max_text = MAXWINDOWTEXT;
  448. SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
  449. /* Get the handle to the client area's device context. */
  450. hdc = GetDC(hWnd);
  451. saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
  452. /* Extract font dimensions from the text metrics. */
  453. GetTextMetrics (hdc, &tm);
  454. data->xChar = tm.tmAveCharWidth;
  455. data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2;
  456. data->yChar = tm.tmHeight + tm.tmExternalLeading;
  457. data->xPage = 1;
  458. /* Free the device context. */
  459. SelectObject(hdc, saveFont);
  460. ReleaseDC (hWnd, hdc);
  461. }
  462. void mswin_message_window_size (HWND hWnd, LPSIZE sz)
  463. {
  464. PNHMessageWindow data;
  465. RECT rt, client_rt;
  466. GetWindowRect(hWnd, &rt);
  467. sz->cx = rt.right - rt.left;
  468. sz->cy = rt.bottom - rt.top;
  469. data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA);
  470. if(data) {
  471. /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and
  472. horizontal scroll bar (difference between window rect and client rect */
  473. GetClientRect(hWnd, &client_rt);
  474. sz->cy = sz->cy-(client_rt.bottom - client_rt.top) +
  475. data->yChar * MSG_VISIBLE_LINES + 4;
  476. }
  477. }