OSDN Git Service

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