OSDN Git Service

no bone
[nethackexpress/trunk.git] / sys / wince / mhmain.c
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
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
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 */
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
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 */
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
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.
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 */
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
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
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
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