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 "mhmsg.h"
6 #include "mhinput.h"
7 #include "mhmain.h"
8 #include "mhmenu.h"
9 #include "mhstatus.h"
10 #include "mhmsgwnd.h"
11 #include "mhcmd.h"
12 #include "mhmap.h"
13 #include "patchlevel.h"
14 
15 #define MAX_LOADSTRING 100
16 
17 typedef struct mswin_nethack_main_window {
18 	int				mapAcsiiModeSave;
19 } NHMainWindow, *PNHMainWindow;
20 
21 TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
22 static TCHAR szTitle[MAX_LOADSTRING];
23 
24 LRESULT CALLBACK	MainWndProc(HWND, UINT, WPARAM, LPARAM);
25 LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
26 static LRESULT  onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
27 static void		onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
28 static void		register_main_window_class();
29 static void		select_map_mode(int map_mode);
30 static int		menuid2mapmode(int menuid);
31 static int		mapmode2menuid(int map_mode);
32 static HMENU	_get_main_menu(UINT menu_id);
33 
mswin_init_main_window()34 HWND mswin_init_main_window () {
35 	static int run_once = 0;
36 	HWND ret;
37 	RECT rc;
38 
39 	/* register window class */
40 	if( !run_once ) {
41 		LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
42 		register_main_window_class( );
43 		run_once = 1;
44 	}
45 
46 	/* create the main window */
47 	SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
48 
49 	ret = CreateWindow(
50 			szMainWindowClass,		/* registered class name */
51 			szTitle,				/* window name */
52 			WS_CLIPCHILDREN,		/* window style */
53 			rc.left,			    /* horizontal position of window */
54 			rc.top,			        /* vertical position of window */
55 			rc.right - rc.left,		/* window width */
56 			rc.bottom - rc.top,		/* window height */
57 			NULL,					/* handle to parent or owner window */
58 			NULL,					/* menu handle or child identifier */
59 			GetNHApp()->hApp,		/* handle to application instance */
60 			NULL					/* window-creation data */
61 		);
62 
63 	if( !ret ) panic("Cannot create main window");
64 	return ret;
65 }
66 
register_main_window_class()67 void register_main_window_class()
68 {
69 	WNDCLASS wcex;
70 
71 	ZeroMemory(&wcex, sizeof(wcex));
72 	wcex.style			= CS_HREDRAW | CS_VREDRAW;
73 	wcex.lpfnWndProc	= (WNDPROC)MainWndProc;
74 	wcex.cbClsExtra		= 0;
75 	wcex.cbWndExtra		= 0;
76 	wcex.hInstance		= GetNHApp()->hApp;
77 	wcex.hIcon			= LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_WINHACK);
78 	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
79 	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
80 	wcex.lpszMenuName	= NULL;
81 	wcex.lpszClassName	= szMainWindowClass;
82 
83 	RegisterClass(&wcex);
84 }
85 
86 /*
87  * Keypad keys are translated to the normal values below.
88  * Shifted keypad keys are translated to the
89  *    shift values below.
90  */
91 
92 enum KEY_INDEXES {
93 KEY_NW, KEY_N, KEY_NE, KEY_MINUS,
94 KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS,
95 KEY_SW, KEY_S, KEY_SE,
96 KEY_INV, KEY_WAITLOOK,
97 KEY_LAST};
98 
99 static const unsigned char
100 /* normal, shift, control */
101 keypad[KEY_LAST][3] = {
102 	{'y', 'Y', C('y')}, /* 7 */
103 	{'k', 'K', C('k')}, /* 8 */
104 	{'u', 'U', C('u')}, /* 9 */
105 	{'m', C('p'), C('p')}, /* - */
106 	{'h', 'H', C('h')}, /* 4 */
107 	{'g', 'G', 'g'}, /* 5 */
108 	{'l', 'L', C('l')}, /* 6 */
109 	{'+', 'P', C('p')}, /* + */
110 	{'b', 'B', C('b')}, /* 1 */
111 	{'j', 'J', C('j')}, /* 2 */
112 	{'n', 'N', C('n')}, /* 3 */
113 	{'i', 'I', C('i')}, /* Ins */
114 	{'.', ':', ':'} /* Del */
115 },
116 numpad[KEY_LAST][3] = {
117 	{'7', M('7'), '7'}, /* 7 */
118 	{'8', M('8'), '8'}, /* 8 */
119 	{'9', M('9'), '9'}, /* 9 */
120 	{'m', C('p'), C('p')}, /* - */
121 	{'4', M('4'), '4'}, /* 4 */
122 	{'g', 'G', 'g'}, /* 5 */
123 	{'6', M('6'), '6'}, /* 6 */
124 	{'+', 'P', C('p')}, /* + */
125 	{'1', M('1'), '1'}, /* 1 */
126 	{'2', M('2'), '2'}, /* 2 */
127 	{'3', M('3'), '3'}, /* 3 */
128 	{'i', 'I', C('i')}, /* Ins */
129 	{'.', ':', ':'} /* Del */
130 };
131 
132 #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
133 #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
134 #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
135 #define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
136 
137 /* map mode macros */
138 #define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \
139 							  (mode)==MAP_MODE_TILES_FIT_TO_SCREEN )
140 
141 #define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN)
142 
143 
144 /*
145 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
146 //
147 //  PURPOSE:  Processes messages for the main window.
148 */
MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)149 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
150 {
151 	PNHMainWindow data;
152 
153 	switch (message)
154 	{
155 		/*-----------------------------------------------------------------------*/
156 		case WM_CREATE: {
157 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
158 			SHMENUBARINFO menubar;
159 #endif
160 			/* set window data */
161 			data = (PNHMainWindow)malloc(sizeof(NHMainWindow));
162 			if( !data ) panic("out of memory");
163 			ZeroMemory(data, sizeof(NHMainWindow));
164 			data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
165 			SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
166 
167 			GetNHApp()->hMainWnd = hWnd;
168 
169 			/* create menu bar */
170 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
171 			ZeroMemory(&menubar, sizeof(menubar));
172 			menubar.cbSize = sizeof(menubar);
173 			menubar.hwndParent = hWnd;
174 			menubar.dwFlags = 0;
175 			menubar.nToolBarId = IDC_WINHACK;
176 			menubar.hInstRes = GetNHApp()->hApp;
177 #	if defined(WIN_CE_POCKETPC)
178 			menubar.nBmpId = IDB_MENUBAR;
179 			menubar.cBmpImages = 2;
180 #	else
181 			menubar.nBmpId = 0;
182 			menubar.cBmpImages = 0;
183 #	endif
184 			if( !SHCreateMenuBar(&menubar) ) panic("cannot create menu");
185 			GetNHApp()->hMenuBar = menubar.hwndMB;
186 #else
187 			GetNHApp()->hMenuBar = CommandBar_Create(GetNHApp()->hApp, hWnd, 1);
188 			if( !GetNHApp()->hMenuBar ) panic("cannot create menu");
189 			CommandBar_InsertMenubar(
190 				GetNHApp()->hMenuBar, GetNHApp()->hApp,
191 				IDC_WINHACK, 0 );
192 #endif
193 			CheckMenuItem(
194 				_get_main_menu(ID_VIEW),
195 				IDM_VIEW_KEYPAD,
196 				MF_BYCOMMAND |
197 				(GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED)
198 			);
199 
200 			/* create command pad (keyboard emulator) */
201 			GetNHApp()->hCmdWnd = mswin_init_command_window();
202 		} break;
203 
204 		/*-----------------------------------------------------------------------*/
205 
206 		case WM_MSNH_COMMAND:
207 			onMSNHCommand(hWnd, wParam, lParam);
208 		break;
209 
210 		/*-----------------------------------------------------------------------*/
211 
212         case WM_KEYDOWN:
213 			data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
214 
215 			/* translate arrow keys into nethack commands */
216             switch (wParam)
217             {
218 			case VK_LEFT:
219 				if( STATEON(VK_CONTROL) ) {
220 					/* scroll map window one line left */
221 					SendMessage(
222 						mswin_hwnd_from_winid(WIN_MAP),
223 						WM_HSCROLL,
224 						MAKEWPARAM(SB_LINEUP, 0),
225 						(LPARAM)NULL
226 					);
227 				} else {
228 					NHEVENT_KBD(KEYTABLE(KEY_W));
229 				}
230 			return 0;
231 
232 			case VK_RIGHT:
233 				if( STATEON(VK_CONTROL) ) {
234 					/* scroll map window one line right */
235 					SendMessage(
236 						mswin_hwnd_from_winid(WIN_MAP),
237 						WM_HSCROLL,
238 						MAKEWPARAM(SB_LINEDOWN, 0),
239 						(LPARAM)NULL
240 					);
241 				} else {
242 					NHEVENT_KBD(KEYTABLE(KEY_E));
243 				}
244 			return 0;
245 
246 			case VK_UP:
247 				if( STATEON(VK_CONTROL) ) {
248 					/* scroll map window one line up */
249 					SendMessage(
250 						mswin_hwnd_from_winid(WIN_MAP),
251 						WM_VSCROLL,
252 						MAKEWPARAM(SB_LINEUP, 0),
253 						(LPARAM)NULL
254 					);
255 				} else {
256 					NHEVENT_KBD(KEYTABLE(KEY_N));
257 				}
258 			return 0;
259 
260 			case VK_DOWN:
261 				if( STATEON(VK_CONTROL) ) {
262 					/* scroll map window one line down */
263 					SendMessage(
264 						mswin_hwnd_from_winid(WIN_MAP),
265 						WM_VSCROLL,
266 						MAKEWPARAM(SB_LINEDOWN, 0),
267 						(LPARAM)NULL
268 					);
269 				} else {
270 					NHEVENT_KBD(KEYTABLE(KEY_S));
271 				}
272 			return 0;
273 
274 			case VK_HOME:
275 				if( STATEON(VK_CONTROL) ) {
276 					/* scroll map window to upper left corner */
277 					SendMessage(
278 						mswin_hwnd_from_winid(WIN_MAP),
279 						WM_VSCROLL,
280 						MAKEWPARAM(SB_THUMBTRACK, 0),
281 						(LPARAM)NULL
282 					);
283 
284 					SendMessage(
285 						mswin_hwnd_from_winid(WIN_MAP),
286 						WM_HSCROLL,
287 						MAKEWPARAM(SB_THUMBTRACK, 0),
288 						(LPARAM)NULL
289 					);
290 				} else {
291 					NHEVENT_KBD(KEYTABLE(KEY_NW));
292 				}
293 			return 0;
294 
295 			case VK_END:
296 				if( STATEON(VK_CONTROL) ) {
297 					/* scroll map window to lower right corner */
298 					SendMessage(
299 						mswin_hwnd_from_winid(WIN_MAP),
300 						WM_VSCROLL,
301 						MAKEWPARAM(SB_THUMBTRACK, ROWNO),
302 						(LPARAM)NULL
303 					);
304 
305 					SendMessage(
306 						mswin_hwnd_from_winid(WIN_MAP),
307 						WM_HSCROLL,
308 						MAKEWPARAM(SB_THUMBTRACK, COLNO),
309 						(LPARAM)NULL
310 					);
311 				} else {
312 					NHEVENT_KBD(KEYTABLE(KEY_SW));
313 				}
314 			return 0;
315 
316 			case VK_PRIOR:
317 				if( STATEON(VK_CONTROL) ) {
318 					/* scroll map window one page up */
319 					SendMessage(
320 						mswin_hwnd_from_winid(WIN_MAP),
321 						WM_VSCROLL,
322 						MAKEWPARAM(SB_PAGEUP, 0),
323 						(LPARAM)NULL
324 					);
325 				} else {
326 					NHEVENT_KBD(KEYTABLE(KEY_NE));
327 				}
328 			return 0;
329 
330 			case VK_NEXT:
331 				if( STATEON(VK_CONTROL) ) {
332 					/* scroll map window one page down */
333 					SendMessage(
334 						mswin_hwnd_from_winid(WIN_MAP),
335 						WM_VSCROLL,
336 						MAKEWPARAM(SB_PAGEDOWN, 0),
337 						(LPARAM)NULL
338 					);
339 				} else {
340 					NHEVENT_KBD(KEYTABLE(KEY_SE));
341 				}
342 			return 0;
343 
344 			case VK_DECIMAL:
345 			case VK_DELETE:
346 				NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
347 			return 0;
348 
349 			case VK_INSERT:
350 				NHEVENT_KBD(KEYTABLE(KEY_INV));
351 			return 0;
352 
353 			case VK_SUBTRACT:
354 				NHEVENT_KBD(KEYTABLE(KEY_MINUS));
355 			return 0;
356 
357 			case VK_ADD:
358 				NHEVENT_KBD(KEYTABLE(KEY_PLUS));
359 			return 0;
360 
361 			case VK_CLEAR: /* This is the '5' key */
362 				NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
363 			return 0;
364 
365 			case VK_F4:
366 				if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
367 					mswin_select_map_mode(
368 						IS_MAP_ASCII(iflags.wc_map_mode)?
369 							data->mapAcsiiModeSave :
370 							MAP_MODE_TILES
371 					);
372 				} else {
373 					mswin_select_map_mode(
374 						IS_MAP_ASCII(iflags.wc_map_mode)?
375 							MAP_MODE_ASCII_FIT_TO_SCREEN :
376 							MAP_MODE_TILES_FIT_TO_SCREEN
377 					);
378 				}
379 			return 0;
380 
381 			case VK_F5:
382 				if( IS_MAP_ASCII(iflags.wc_map_mode) ) {
383 					if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
384 						mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
385 					} else {
386 						mswin_select_map_mode(MAP_MODE_TILES);
387 					}
388 				} else {
389 					if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
390 						mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
391 					} else {
392 						mswin_select_map_mode(data->mapAcsiiModeSave);
393 					}
394 				}
395 			return 0;
396 
397 			case VK_RETURN:
398 				NHEVENT_MS( CLICK_1, u.ux, u.uy);
399 			return 0;
400 			}
401 
402 #if defined(WIN_CE_SMARTPHONE)
403 			if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) return 0;
404 #endif
405 		return 1; /* end of WM_KEYDOWN */
406 
407 		/*-----------------------------------------------------------------------*/
408 
409 #if defined(WIN_CE_SMARTPHONE)
410 		case WM_KEYUP:
411 			if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) ) return 0;
412 		return 1; /* end of WM_KEYUP */
413 #endif
414 		/*-----------------------------------------------------------------------*/
415 
416 #if !defined(WIN_CE_SMARTPHONE)
417 		case WM_CHAR:
418 			if( wParam=='\n' || wParam=='\r' || wParam==C('M') ) return 0; /* we already processed VK_RETURN */
419 
420 			/* all characters go to nethack except Ctrl-P that scrolls message window up */
421 			if( wParam==C('P') || wParam==C('p') ) {
422 				SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
423 			} else {
424 				NHEVENT_KBD( (lParam & 1<<29)? M(tolower(wParam)) : wParam );
425 			}
426 		return 0;
427 #endif
428 
429 		/*-----------------------------------------------------------------------*/
430 
431 		case WM_COMMAND:
432 			/* process commands - menu commands mostly */
433 			if( IsWindow(GetNHApp()->hPopupWnd) ) {
434 				return SendMessage(GetNHApp()->hPopupWnd, message, wParam, lParam);
435 			} else if( onWMCommand(hWnd, wParam, lParam) )
436 				return DefWindowProc(hWnd, message, wParam, lParam);
437 			else
438 				return 0;
439 
440 		/*-----------------------------------------------------------------------*/
441 
442 		case WM_ACTIVATE:
443 			if( LOWORD(wParam)!=WA_INACTIVE ) {
444 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
445 				if( GetNHApp()->bFullScreen )
446 					SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
447 				else
448 					SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
449 #endif
450 				mswin_layout_main_window(NULL);
451 			}
452 		break;
453 
454 		case WM_SETTINGCHANGE:
455 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
456 			if( GetNHApp()->bFullScreen )
457 				SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
458 			else
459 				SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
460 #endif
461 			mswin_layout_main_window(NULL);
462 		break;
463 
464 		case WM_SIZE:
465 			mswin_layout_main_window(NULL);
466 		break;
467 
468 		/*-----------------------------------------------------------------------*/
469 
470 		case WM_SETFOCUS:
471 			/* if there is a menu window out there -
472 			   transfer input focus to it */
473 			if( IsWindow( GetNHApp()->hPopupWnd ) ) {
474 				SetFocus( GetNHApp()->hPopupWnd );
475 			}
476 			break;
477 
478 		/*-----------------------------------------------------------------------*/
479 
480 		case WM_CLOSE:
481 		{
482 			/* exit gracefully */
483 			dosave0();
484 		} return 0;
485 
486 		/*-----------------------------------------------------------------------*/
487 
488 		case WM_DESTROY: {
489 			/* apparently we never get here
490 			   TODO: work on exit routines - need to send
491 			   WM_QUIT somehow */
492 
493 			/* clean up */
494 			free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) );
495 			SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
496 
497 			terminate(EXIT_SUCCESS);
498 		} break;
499 
500 		/*-----------------------------------------------------------------------*/
501 
502 		default:
503 			return DefWindowProc(hWnd, message, wParam, lParam);
504    }
505    return 0;
506 }
507 
onMSNHCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)508 void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
509 {
510 	switch(wParam) {
511 
512 	/* new window was just added */
513 	case MSNH_MSG_ADDWND: {
514 		PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam;
515 		HWND child = GetNHApp()->windowlist[msg_param->wid].win;
516 
517 		if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP )
518 			mswin_select_map_mode(iflags.wc_map_mode);
519 
520 		if( child ) mswin_layout_main_window(child);
521 	} break;
522 
523 	}
524 }
525 
526 /* adjust windows to fit main window layout
527    ---------------------------
528    |        Status           |
529    +-------------------------+
530    |                         |
531    |                         |
532    |          MAP            |
533    |                         |
534    |                         |
535    +-------------------------+
536    |      Command pad        |
537    +-------------------------+
538    |        Messages         |
539    ---------------------------
540 */
mswin_layout_main_window(HWND changed_child)541 void mswin_layout_main_window(HWND changed_child)
542 {
543 	winid i;
544 	RECT client_rt, wnd_rect;
545 	POINT status_org;
546 	SIZE status_size;
547 	POINT msg_org;
548 	SIZE msg_size;
549 	POINT map_org;
550 	SIZE map_size;
551 	POINT cmd_org;
552 	SIZE cmd_size;
553 	HWND wnd_status, wnd_msg;
554 	PNHMainWindow  data;
555 #if defined(WIN_CE_POCKETPC)
556 	SIPINFO sip;
557 	RECT menu_bar;
558 	RECT visible_rt;
559 	POINT pt;
560 #endif
561 
562 	GetClientRect(GetNHApp()->hMainWnd, &client_rt);
563 
564 #if defined(WIN_CE_POCKETPC)
565 	ZeroMemory(&sip, sizeof(sip));
566 	sip.cbSize = sizeof(sip);
567 	SHSipInfo(SPI_GETSIPINFO, 0, &sip, 0);
568 	if( GetNHApp()->bFullScreen ) sip.rcVisibleDesktop.top = 0;
569 
570 	/* adjust client rectangle size */
571 	GetWindowRect(GetNHApp()->hMenuBar, &menu_bar);
572 	client_rt.bottom -= menu_bar.bottom-menu_bar.top;
573 
574 	/* calcuate visible rect in client coordinates */
575 	pt.x = sip.rcVisibleDesktop.left;
576 	pt.y = sip.rcVisibleDesktop.top;
577 	ScreenToClient(GetNHApp()->hMainWnd, &pt);
578 	SetRect(&wnd_rect,
579 			pt.x,
580 			pt.y,
581 			pt.x+sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left,
582 			pt.y+sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top );
583 	IntersectRect(&visible_rt, &client_rt, &wnd_rect);
584 #else
585 #	if	!defined(WIN_CE_SMARTPHONE)
586 	client_rt.top += CommandBar_Height(GetNHApp()->hMenuBar);
587 #	else
588 	/* Smartphone only */
589 	if( GetNHApp()->bFullScreen ) {
590 		RECT menu_bar;
591 		GetWindowRect(GetNHApp()->hMenuBar, &menu_bar);
592 		client_rt.bottom -= menu_bar.bottom-menu_bar.top;
593 	}
594 #	endif
595 #endif
596 
597 	/* get window data */
598 	data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
599 
600 	/* get sizes of child windows */
601 	wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
602 	if( IsWindow(wnd_status) ) {
603 		mswin_status_window_size(wnd_status, &status_size);
604 	} else {
605 		status_size.cx = status_size.cy = 0;
606 	}
607 
608 	wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
609 	if( IsWindow(wnd_msg) ) {
610 		mswin_message_window_size(wnd_msg, &msg_size);
611 	} else {
612 		msg_size.cx = msg_size.cy = 0;
613 	}
614 
615 	cmd_size.cx = cmd_size.cy = 0;
616 	if( GetNHApp()->bCmdPad && IsWindow(GetNHApp()->hCmdWnd) ) {
617 		mswin_command_window_size(GetNHApp()->hCmdWnd, &cmd_size);
618 	}
619 
620 	/* set window positions */
621 
622 	/* calculate the application windows size */
623 #if defined(WIN_CE_POCKETPC)
624 	SetRect(&wnd_rect, visible_rt.left, visible_rt.top, visible_rt.right, visible_rt.bottom);
625 	if( sip.fdwFlags & SIPF_ON )
626 		cmd_size.cx = cmd_size.cy = 0;  /* hide keypad window */
627 #else
628 	SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom);
629 #endif
630 
631 #if !defined(WIN_CE_SMARTPHONE)
632 	/* other ports have it at the bottom of the screen */
633 	cmd_size.cx = (wnd_rect.right-wnd_rect.left);
634 	cmd_org.x = wnd_rect.left;
635 	cmd_org.y = wnd_rect.bottom - cmd_size.cy;
636 	wnd_rect.bottom -= cmd_size.cy;
637 #endif
638 
639 	/* status window */
640 	switch(iflags.wc_align_status) {
641 	case ALIGN_LEFT:
642 		status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
643 		status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
644 		status_org.x = wnd_rect.left;
645 		status_org.y = wnd_rect.top;
646 		wnd_rect.left += status_size.cx;
647 		break;
648 
649 	case ALIGN_RIGHT:
650 		status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
651 		status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
652 		status_org.x = wnd_rect.right - status_size.cx;
653 		status_org.y = wnd_rect.top;
654 		wnd_rect.right -= status_size.cx;
655 		break;
656 
657 	case ALIGN_TOP:
658 		status_size.cx = (wnd_rect.right-wnd_rect.left);
659 		status_org.x = wnd_rect.left;
660 		status_org.y = wnd_rect.top;
661 		wnd_rect.top += status_size.cy;
662 		break;
663 
664 	case ALIGN_BOTTOM:
665 	default:
666 		status_size.cx = (wnd_rect.right-wnd_rect.left);
667 		status_org.x = wnd_rect.left;
668 		status_org.y = wnd_rect.bottom - status_size.cy;
669 		wnd_rect.bottom -= status_size.cy;
670 		break;
671 	}
672 
673 	/* message window */
674 	switch(iflags.wc_align_message) {
675 	case ALIGN_LEFT:
676 #if defined(WIN_CE_SMARTPHONE)
677 		/* smartphone has a keypad window on the right (bottom) side of the message window */
678 		msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx);
679 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy;
680 		msg_org.x = cmd_org.x = wnd_rect.left;
681 		msg_org.y = wnd_rect.top;
682 		cmd_org.y = msg_org.y + msg_size.cy;
683 #else
684 		msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
685 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top);
686 		msg_org.x = wnd_rect.left;
687 		msg_org.y = wnd_rect.top;
688 #endif
689 		wnd_rect.left += msg_size.cx;
690 
691 		break;
692 
693 	case ALIGN_RIGHT:
694 #if defined(WIN_CE_SMARTPHONE)
695 		/* smartphone has a keypad window on the right (bottom) side of the message window */
696 		msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx);
697 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy;
698 		msg_org.x = cmd_org.x = wnd_rect.right - msg_size.cx;
699 		msg_org.y = wnd_rect.top;
700 		cmd_org.y = msg_org.y + msg_size.cy;
701 #else
702 		msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
703 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top);
704 		msg_org.x = wnd_rect.right - msg_size.cx;
705 		msg_org.y = wnd_rect.top;
706 #endif
707 
708 		wnd_rect.right -= msg_size.cx;
709 		break;
710 
711 	case ALIGN_TOP:
712 #if defined(WIN_CE_SMARTPHONE)
713 		/* smartphone has a keypad window on the right side of the message window */
714 		msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy);
715 		msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx;
716 		msg_org.x = wnd_rect.left;
717 		cmd_org.x = msg_org.x + msg_size.cx;
718 		msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy;
719 #else
720 		msg_size.cx = (wnd_rect.right-wnd_rect.left);
721 		msg_org.x = wnd_rect.left;
722 		msg_org.y = wnd_rect.top;
723 #endif
724 		wnd_rect.top += msg_size.cy;
725 		break;
726 
727 	case ALIGN_BOTTOM:
728 	default:
729 #if defined(WIN_CE_SMARTPHONE)
730 		/* smartphone has a keypad window on the right side of the message window */
731 		msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy);
732 		msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx;
733 		msg_org.x = wnd_rect.left;
734 		cmd_org.x = msg_org.x + msg_size.cx;
735 		msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy;
736 #else
737 		msg_size.cx = (wnd_rect.right-wnd_rect.left);
738 		msg_org.x = wnd_rect.left;
739 		msg_org.y = wnd_rect.bottom - msg_size.cy;
740 #endif
741 		wnd_rect.bottom -= msg_size.cy;
742 		break;
743 	}
744 
745 	map_org.x = wnd_rect.left;
746 	map_org.y = wnd_rect.top;
747 	map_size.cx = wnd_rect.right - wnd_rect.left;
748 	map_size.cy = wnd_rect.bottom - wnd_rect.top;
749 
750 	/* go through the windows list and adjust sizes */
751 	for( i=0; i<MAXWINDOWS; i++ ) {
752 		if(GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) {
753 			switch( GetNHApp()->windowlist[i].type ) {
754 			case NHW_MESSAGE:
755 				MoveWindow(GetNHApp()->windowlist[i].win,
756 					       msg_org.x,
757 						   msg_org.y,
758 						   msg_size.cx,
759 						   msg_size.cy,
760 						   TRUE );
761 				break;
762 			case NHW_MAP:
763 				MoveWindow(GetNHApp()->windowlist[i].win,
764 					       map_org.x,
765 						   map_org.y,
766 						   map_size.cx,
767 						   map_size.cy,
768 						   TRUE );
769 				break;
770 			case NHW_STATUS:
771 				MoveWindow(GetNHApp()->windowlist[i].win,
772 					       status_org.x,
773 						   status_org.y,
774 						   status_size.cx,
775 						   status_size.cy,
776 						   TRUE );
777 				break;
778 
779 			case NHW_TEXT:
780 			case NHW_MENU:
781 			case NHW_RIP:
782 			{
783 				POINT menu_org;
784 				SIZE menu_size;
785 
786 				menu_org.x = client_rt.left;
787 				menu_org.y = client_rt.top;
788 #if defined(WIN_CE_POCKETPC)
789 				menu_size.cx = min(sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left,
790 					               client_rt.right - client_rt.left);
791 				menu_size.cy = min(sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top,
792 								   client_rt.bottom - client_rt.top);
793 #else
794 				menu_size.cx = client_rt.right - client_rt.left;
795 				menu_size.cy = client_rt.bottom - client_rt.top;
796 #endif
797 
798 #if defined(WIN_CE_SMARTPHONE)
799 				/* leave room for the command window */
800 				if( GetNHApp()->windowlist[i].type == NHW_MENU ) {
801 					menu_size.cy -= cmd_size.cy;
802 				}
803 
804 				/* dialogs are popup windows unde SmartPhone so we need
805 				   to convert to screen coordinates */
806 				ClientToScreen(GetNHApp()->hMainWnd, &menu_org);
807 #endif
808 				MoveWindow(GetNHApp()->windowlist[i].win,
809 					       menu_org.x,
810 						   menu_org.y,
811 						   menu_size.cx,
812 						   menu_size.cy,
813 						   TRUE );
814 			} break;
815 			}
816 			ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW);
817 			InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE);
818 		}
819 	}
820 
821 	if( IsWindow(GetNHApp()->hCmdWnd) ) {
822 		/* show command window only if it exists and
823 		   the game is ready (plname is set) */
824 		if( GetNHApp()->bCmdPad && cmd_size.cx>0 && cmd_size.cy>0 && *plname) {
825 			MoveWindow(GetNHApp()->hCmdWnd,
826 				   cmd_org.x,
827 				   cmd_org.y,
828 				   cmd_size.cx,
829 				   cmd_size.cy,
830 				   TRUE );
831 			ShowWindow(GetNHApp()->hCmdWnd, SW_SHOW);
832 		} else {
833 			ShowWindow(GetNHApp()->hCmdWnd, SW_HIDE);
834 		}
835 	}
836 }
837 
onWMCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)838 LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
839 {
840 	int wmId, wmEvent;
841 	PNHMainWindow  data;
842 
843 	data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
844 	wmId    = LOWORD(wParam);
845 	wmEvent = HIWORD(wParam);
846 
847 	// process the menu selections:
848 	switch (wmId)
849 	{
850 		case IDM_ABOUT:
851 		   DialogBox(GetNHApp()->hApp, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
852 		   break;
853 
854 		case IDM_EXIT:
855 		   done2();
856 		   break;
857 
858 		case IDM_SAVE:
859 		   dosave();
860 		   break;
861 
862 		case IDM_MAP_TILES:
863 		case IDM_MAP_ASCII4X6:
864 		case IDM_MAP_ASCII6X8:
865 		case IDM_MAP_ASCII8X8:
866 		case IDM_MAP_ASCII16X8:
867 		case IDM_MAP_ASCII7X12:
868 		case IDM_MAP_ASCII8X12:
869 		case IDM_MAP_ASCII12X16:
870 		case IDM_MAP_ASCII16X12:
871 		case IDM_MAP_ASCII10X18:
872 			mswin_select_map_mode(menuid2mapmode(wmId));
873 			break;
874 
875 		case IDM_MAP_FIT_TO_SCREEN:
876 			if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
877 				mswin_select_map_mode(
878 					IS_MAP_ASCII(iflags.wc_map_mode)?
879 						data->mapAcsiiModeSave :
880 						MAP_MODE_TILES
881 				);
882 			} else {
883 				mswin_select_map_mode(
884 					IS_MAP_ASCII(iflags.wc_map_mode)?
885 						MAP_MODE_ASCII_FIT_TO_SCREEN :
886 						MAP_MODE_TILES_FIT_TO_SCREEN
887 				);
888 			}
889 			break;
890 
891 		case IDM_VIEW_KEYPAD:
892 			GetNHApp()->bCmdPad = !GetNHApp()->bCmdPad;
893 			CheckMenuItem(
894 				_get_main_menu(ID_VIEW),
895 				IDM_VIEW_KEYPAD,
896 				MF_BYCOMMAND |
897 				(GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED)
898 			);
899 			mswin_layout_main_window(GetNHApp()->hCmdWnd);
900 			break;
901 
902 		case IDM_VIEW_OPTIONS:
903 			doset();
904 			break;
905 
906 		case IDM_HELP_LONG:
907 			display_file(HELP, TRUE);
908 			break;
909 
910 		case IDM_HELP_COMMANDS:
911 			display_file(SHELP, TRUE);
912 			break;
913 
914 		case IDM_HELP_HISTORY:
915 			(void) dohistory();
916 			break;
917 
918 		case IDM_HELP_INFO_CHAR:
919 			(void) dowhatis();
920 			break;
921 
922 		case IDM_HELP_INFO_KEY:
923 			(void) dowhatdoes();
924 			break;
925 
926 		case IDM_HELP_OPTIONS:
927 			option_help();
928 			break;
929 
930 		case IDM_HELP_OPTIONS_LONG:
931 			display_file(OPTIONFILE, TRUE);
932 			break;
933 
934 		case IDM_HELP_EXTCMD:
935 			(void) doextlist();
936 			break;
937 
938 		case IDM_HELP_LICENSE:
939 			display_file(LICENSE, TRUE);
940 			break;
941 
942 		case IDM_HELP_MENU:
943 			dohelp();
944 			break;
945 
946 		default:
947 		   return 1;
948 	}
949 	return 0;
950 }
951 
952 // Mesage handler for about box.
About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)953 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
954 {
955 	char buf[BUFSZ];
956 	TCHAR wbuf[NHSTR_BUFSIZE];
957 	RECT   main_rt, dlg_rt;
958 	SIZE   dlg_sz;
959 
960 	switch (message)
961 	{
962 		case WM_INITDIALOG:
963 				getversionstring(buf);
964 				SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, NHSTR_BUFSIZE));
965 
966 				SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
967 							NH_A2W(
968 								COPYRIGHT_BANNER_A "\n"
969 								COPYRIGHT_BANNER_B "\n"
970 								COPYRIGHT_BANNER_C,
971 								wbuf,
972 								NHSTR_BUFSIZE
973 							) );
974 
975 
976 				/* center dialog in the main window */
977 				GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
978 				GetWindowRect(hDlg, &dlg_rt);
979 				dlg_sz.cx = dlg_rt.right - dlg_rt.left;
980 				dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
981 
982 				dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
983 				dlg_rt.right = dlg_rt.left + dlg_sz.cx;
984 				dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
985 				dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
986 				MoveWindow( hDlg,
987 							(main_rt.left+main_rt.right-dlg_sz.cx)/2,
988 							(main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
989 							dlg_sz.cx,
990 							dlg_sz.cy,
991 							TRUE );
992 
993 				return TRUE;
994 
995 		case WM_COMMAND:
996 			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
997 			{
998 				EndDialog(hDlg, LOWORD(wParam));
999 				return TRUE;
1000 			}
1001 			break;
1002 	}
1003     return FALSE;
1004 }
1005 
1006 
1007 /* Set map display mode */
mswin_select_map_mode(int mode)1008 void mswin_select_map_mode(int mode)
1009 {
1010 	HMENU hmenuMap;
1011 	PNHMainWindow  data;
1012 	winid map_id;
1013 
1014 	map_id = WIN_MAP;
1015 	data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
1016 #if defined(WIN_CE_SMARTPHONE)
1017 	/* Smartphone manu has only 2 items */
1018 	hmenuMap = _get_main_menu(ID_VIEW);
1019 #else
1020 	hmenuMap = _get_main_menu(ID_MAP);
1021 #endif
1022 
1023 	/* override for Rogue level */
1024 #ifdef REINCARNATION
1025     if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return;
1026 #endif
1027 
1028 	/* set map mode menu mark */
1029 	if( IS_MAP_ASCII(mode) ) {
1030 		CheckMenuRadioItem(
1031 			hmenuMap,
1032 			IDM_MAP_TILES,
1033 			IDM_MAP_FIT_TO_SCREEN,
1034 			mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ),
1035 			MF_BYCOMMAND);
1036 	} else {
1037 		CheckMenuRadioItem(
1038 			hmenuMap,
1039 			IDM_MAP_TILES,
1040 			IDM_MAP_FIT_TO_SCREEN,
1041 			mapmode2menuid( MAP_MODE_TILES ),
1042 			MF_BYCOMMAND);
1043 	}
1044 
1045 #if defined(WIN_CE_SMARTPHONE)
1046 	/* update "Fit To Screen" item text */
1047 	{
1048 		TCHAR wbuf[BUFSZ];
1049 		TBBUTTONINFO tbbi;
1050 
1051 		ZeroMemory( wbuf, sizeof(wbuf) );
1052 		if( !LoadString(
1053 			GetNHApp()->hApp,
1054 			(IS_MAP_FIT_TO_SCREEN(mode)? IDS_CAP_NORMALMAP : IDS_CAP_ENTIREMAP),
1055 			wbuf,
1056 			BUFSZ) ) {
1057 			panic("cannot load main menu strings");
1058 		}
1059 
1060 		ZeroMemory( &tbbi, sizeof(tbbi) );
1061 		tbbi.cbSize = sizeof(tbbi);
1062 		tbbi.dwMask = TBIF_TEXT;
1063 		tbbi.pszText = wbuf;
1064 		if( !SendMessage(
1065 				GetNHApp()->hMenuBar,
1066 				TB_SETBUTTONINFO,
1067 				IDM_MAP_FIT_TO_SCREEN,
1068 				(LPARAM)&tbbi) ) {
1069 			error( "Cannot update IDM_MAP_FIT_TO_SCREEN menu item." );
1070 		}
1071 	}
1072 #else
1073 	/* set fit-to-screen mode mark */
1074 	CheckMenuItem(
1075 		hmenuMap,
1076 		IDM_MAP_FIT_TO_SCREEN,
1077 		MF_BYCOMMAND |
1078 		(IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED)
1079 	);
1080 #endif
1081 
1082 	if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
1083 		data->mapAcsiiModeSave = iflags.wc_map_mode;
1084 	}
1085 
1086 	iflags.wc_map_mode = mode;
1087 
1088 	/*
1089 	** first, check if WIN_MAP has been inialized.
1090 	** If not - attempt to retrieve it by type, then check it again
1091 	*/
1092 	if( map_id==WIN_ERR )
1093 		map_id = mswin_winid_from_type(NHW_MAP);
1094 	if( map_id!=WIN_ERR )
1095 		mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
1096 }
1097 
1098 static struct t_menu2mapmode {
1099 	int menuID;
1100 	int mapMode;
1101 } _menu2mapmode[] =
1102 {
1103 	{ IDM_MAP_TILES, MAP_MODE_TILES },
1104 	{ IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
1105 	{ IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
1106 	{ IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
1107 	{ IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
1108 	{ IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
1109 	{ IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
1110 	{ IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
1111 	{ IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
1112 	{ IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
1113 	{ IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
1114 	{ -1, -1 }
1115 };
1116 
menuid2mapmode(int menuid)1117 int	menuid2mapmode(int menuid)
1118 {
1119 	struct t_menu2mapmode* p;
1120 	for( p = _menu2mapmode; p->mapMode!=-1; p++ )
1121 		if(p->menuID==menuid ) return p->mapMode;
1122 	return -1;
1123 }
1124 
mapmode2menuid(int map_mode)1125 int	mapmode2menuid(int map_mode)
1126 {
1127 	struct t_menu2mapmode* p;
1128 	for( p = _menu2mapmode; p->mapMode!=-1; p++ )
1129 		if(p->mapMode==map_mode ) return p->menuID;
1130 	return -1;
1131 }
1132 
_get_main_menu(UINT menu_id)1133 HMENU _get_main_menu(UINT menu_id)
1134 {
1135 	HMENU hmenuMap;
1136 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
1137 	TBBUTTONINFO tbbi;
1138 #endif
1139 
1140 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
1141 	tbbi.cbSize = sizeof(tbbi);
1142 	tbbi.dwMask = TBIF_LPARAM;
1143 	SendMessage( GetNHApp()->hMenuBar, TB_GETBUTTONINFO, menu_id, (LPARAM)&tbbi);
1144     hmenuMap = (HMENU)tbbi.lParam;
1145 #else
1146 	hmenuMap = CommandBar_GetMenu(GetNHApp()->hMenuBar, 0);
1147 #endif
1148 	return hmenuMap;
1149 }
1150 
1151