1 /* aNetHack 0.0.1 mhmenu.c $ANH-Date: 1432512811 2015/05/25 00:13:31 $ $ANH-Branch: master $:$ANH-Revision: 1.48 $ */
2 /* Copyright (c) Alex Kompel, 2002 */
3 /* aNetHack may be freely redistributed. See license for details. */
15 #define NHMENU_STR_SIZE BUFSZ
16 #define MIN_TABSTOP_SIZE 0
18 #define TAB_SEPARATION 10 /* pixels between each tab stop */
20 #define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW
21 #define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT
22 #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW
23 #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT
25 typedef struct mswin_menu_item
{
31 char str
[NHMENU_STR_SIZE
];
35 } NHMenuItem
, *PNHMenuItem
;
37 typedef struct mswin_anethack_menu_window
{
38 int type
; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */
39 int how
; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */
43 int size
; /* number of items in items[] */
44 int allocated
; /* number of allocated slots in items[] */
45 PNHMenuItem items
; /* menu items */
46 char gacc
[QBUFSZ
]; /* group accelerators */
47 BOOL counting
; /* counting flag */
48 char prompt
[QBUFSZ
]; /* menu prompt */
49 int tab_stop_size
[NUMTABS
]; /* tabstops to align option values */
50 int menu_cx
; /* menu width */
62 HBITMAP bmpCheckedCount
;
63 HBITMAP bmpNotChecked
;
66 } NHMenuWindow
, *PNHMenuWindow
;
68 extern short glyph2tile
[];
70 static WNDPROC wndProcListViewOrig
= NULL
;
71 static WNDPROC editControlWndProc
= NULL
;
73 #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj != NULL)
74 #define NHMENU_IS_SELECTED(item) ((item).count != 0)
75 #define NHMENU_HAS_GLYPH(item) ((item).glyph != NO_GLYPH)
77 INT_PTR CALLBACK
MenuWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
78 LRESULT CALLBACK
NHMenuListWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
79 LRESULT CALLBACK
NHMenuTextWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
80 static void onMSNHCommand(HWND hWnd
, WPARAM wParam
, LPARAM lParam
);
81 static BOOL
onMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
);
82 static BOOL
onDrawItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
);
83 static void LayoutMenu(HWND hwnd
);
84 static void SetMenuType(HWND hwnd
, int type
);
85 static void SetMenuListType(HWND hwnd
, int now
);
86 static HWND
GetMenuControl(HWND hwnd
);
87 static void SelectMenuItem(HWND hwndList
, PNHMenuWindow data
, int item
,
89 static void reset_menu_count(HWND hwndList
, PNHMenuWindow data
);
90 static BOOL
onListChar(HWND hWnd
, HWND hwndList
, WORD ch
);
92 /*-----------------------------------------------------------------------------*/
94 mswin_init_menu_window(int type
)
99 /* get window position */
100 if (GetNHApp()->bAutoLayout
) {
101 SetRect(&rt
, 0, 0, 0, 0);
103 mswin_get_window_placement(NHW_MENU
, &rt
);
106 /* create menu window object */
107 ret
= CreateDialog(GetNHApp()->hApp
, MAKEINTRESOURCE(IDD_MENU
),
108 GetNHApp()->hMainWnd
, MenuWndProc
);
110 panic("Cannot create menu window");
113 /* move it in the predefined position */
114 if (!GetNHApp()->bAutoLayout
) {
115 MoveWindow(ret
, rt
.left
, rt
.top
, rt
.right
- rt
.left
,
116 rt
.bottom
- rt
.top
, TRUE
);
119 /* Set window caption */
120 SetWindowText(ret
, "Menu/Text");
122 mswin_apply_window_style(ret
);
124 SetMenuType(ret
, type
);
127 /*-----------------------------------------------------------------------------*/
129 mswin_menu_window_select_menu(HWND hWnd
, int how
, MENU_ITEM_P
**_selected
,
134 MENU_ITEM_P
*selected
= NULL
;
138 assert(_selected
!= NULL
);
142 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
144 /* force activate for certain menu types */
145 if (data
->type
== MENU_TYPE_MENU
146 && (how
== PICK_ONE
|| how
== PICK_ANY
)) {
150 data
->is_active
= activate
&& !GetNHApp()->regaNetHackMode
;
153 SetMenuListType(hWnd
, how
);
155 /* Ok, now give items a unique accelerators */
156 if (data
->type
== MENU_TYPE_MENU
) {
157 char next_char
= 'a';
159 data
->menu
.gacc
[0] = '\0';
160 ap
= data
->menu
.gacc
;
161 for (i
= 0; i
< data
->menu
.size
; i
++) {
162 if (data
->menu
.items
[i
].accelerator
!= 0) {
163 next_char
= (char) (data
->menu
.items
[i
].accelerator
+ 1);
164 } else if (NHMENU_IS_SELECTABLE(data
->menu
.items
[i
])) {
165 if ((next_char
>= 'a' && next_char
<= 'z')
166 || (next_char
>= 'A' && next_char
<= 'Z')) {
167 data
->menu
.items
[i
].accelerator
= next_char
;
171 else if (next_char
> 'Z')
174 data
->menu
.items
[i
].accelerator
= next_char
;
181 /* collect group accelerators */
182 for (i
= 0; i
< data
->menu
.size
; i
++) {
183 if (data
->how
!= PICK_NONE
) {
184 if (data
->menu
.items
[i
].group_accel
185 && !strchr(data
->menu
.gacc
,
186 data
->menu
.items
[i
].group_accel
)) {
187 *ap
++ = data
->menu
.items
[i
].group_accel
;
193 reset_menu_count(NULL
, data
);
196 LayoutMenu(hWnd
); // show dialog buttons
199 mswin_popup_display(hWnd
, &data
->done
);
201 SetFocus(GetNHApp()->hMainWnd
);
202 mswin_layout_main_window(hWnd
);
206 if (data
->result
!= -1) {
207 if (how
== PICK_NONE
) {
208 if (data
->result
>= 0)
212 } else if (how
== PICK_ONE
|| how
== PICK_ANY
) {
213 /* count selected items */
215 for (i
= 0; i
< data
->menu
.size
; i
++) {
216 if (NHMENU_IS_SELECTABLE(data
->menu
.items
[i
])
217 && NHMENU_IS_SELECTED(data
->menu
.items
[i
])) {
225 (MENU_ITEM_P
*) malloc(ret_val
* sizeof(MENU_ITEM_P
));
227 panic("out of memory");
230 for (i
= 0; i
< data
->menu
.size
; i
++) {
231 if (NHMENU_IS_SELECTABLE(data
->menu
.items
[i
])
232 && NHMENU_IS_SELECTED(data
->menu
.items
[i
])) {
233 selected
[sel_ind
].item
=
234 data
->menu
.items
[i
].identifier
;
235 selected
[sel_ind
].count
= data
->menu
.items
[i
].count
;
240 *_selected
= selected
;
246 data
->is_active
= FALSE
;
247 LayoutMenu(hWnd
); // hide dialog buttons
248 mswin_popup_destroy(hWnd
);
252 /*-----------------------------------------------------------------------------*/
254 MenuWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
259 TCHAR title
[MAX_LOADSTRING
];
261 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
264 data
= (PNHMenuWindow
) malloc(sizeof(NHMenuWindow
));
265 ZeroMemory(data
, sizeof(NHMenuWindow
));
266 data
->type
= MENU_TYPE_TEXT
;
267 data
->how
= PICK_NONE
;
271 LoadBitmap(GetNHApp()->hApp
, MAKEINTRESOURCE(IDB_MENU_SEL
));
272 data
->bmpCheckedCount
=
273 LoadBitmap(GetNHApp()->hApp
, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT
));
274 data
->bmpNotChecked
=
275 LoadBitmap(GetNHApp()->hApp
, MAKEINTRESOURCE(IDB_MENU_UNSEL
));
276 data
->is_active
= FALSE
;
277 SetWindowLongPtr(hWnd
, GWLP_USERDATA
, (LONG_PTR
) data
);
279 /* set font for the text cotrol */
280 control
= GetDlgItem(hWnd
, IDC_MENU_TEXT
);
281 hdc
= GetDC(control
);
282 SendMessage(control
, WM_SETFONT
,
283 (WPARAM
) mswin_get_font(NHW_MENU
, ATR_NONE
, hdc
, FALSE
),
285 ReleaseDC(control
, hdc
);
287 /* subclass edit control */
289 (WNDPROC
) GetWindowLongPtr(control
, GWLP_WNDPROC
);
290 SetWindowLongPtr(control
, GWLP_WNDPROC
, (LONG_PTR
) NHMenuTextWndProc
);
292 /* Even though the dialog has no caption, you can still set the title
293 which shows on Alt-Tab */
294 LoadString(GetNHApp()->hApp
, IDS_APP_TITLE
, title
, MAX_LOADSTRING
);
295 SetWindowText(hWnd
, title
);
297 /* set focus to text control for now */
301 case WM_MSNH_COMMAND
:
302 onMSNHCommand(hWnd
, wParam
, lParam
);
308 GetWindowRect(hWnd
, &rt
);
309 ScreenToClient(GetNHApp()->hMainWnd
, (LPPOINT
) &rt
);
310 ScreenToClient(GetNHApp()->hMainWnd
, ((LPPOINT
) &rt
) + 1);
311 if (flags
.perm_invent
&& mswin_winid_from_handle(hWnd
) == WIN_INVEN
)
312 mswin_update_window_placement(NHW_INVEN
, &rt
);
314 mswin_update_window_placement(NHW_MENU
, &rt
);
320 GetWindowRect(hWnd
, &rt
);
321 ScreenToClient(GetNHApp()->hMainWnd
, (LPPOINT
) &rt
);
322 ScreenToClient(GetNHApp()->hMainWnd
, ((LPPOINT
) &rt
) + 1);
323 if (flags
.perm_invent
&& mswin_winid_from_handle(hWnd
) == WIN_INVEN
)
324 mswin_update_window_placement(NHW_INVEN
, &rt
);
326 mswin_update_window_placement(NHW_MENU
, &rt
);
331 if (program_state
.gameover
) {
334 program_state
.stopprint
++;
340 switch (LOWORD(wParam
)) {
342 if (data
->type
== MENU_TYPE_MENU
343 && (data
->how
== PICK_ONE
|| data
->how
== PICK_ANY
)
344 && data
->menu
.counting
) {
348 /* reset counter if counting is in progress */
349 list
= GetMenuControl(hWnd
);
350 i
= ListView_GetNextItem(list
, -1, LVNI_FOCUSED
);
352 SelectMenuItem(list
, data
, i
, 0);
369 LPNMHDR lpnmhdr
= (LPNMHDR
) lParam
;
370 switch (LOWORD(wParam
)) {
371 case IDC_MENU_LIST
: {
372 if (!data
|| data
->type
!= MENU_TYPE_MENU
)
375 switch (lpnmhdr
->code
) {
376 case LVN_ITEMACTIVATE
: {
377 LPNMLISTVIEW lpnmlv
= (LPNMLISTVIEW
) lParam
;
378 if (data
->how
== PICK_ONE
) {
379 if (lpnmlv
->iItem
>= 0 && lpnmlv
->iItem
< data
->menu
.size
380 && NHMENU_IS_SELECTABLE(
381 data
->menu
.items
[lpnmlv
->iItem
])) {
382 SelectMenuItem(lpnmlv
->hdr
.hwndFrom
, data
,
392 LPNMLISTVIEW lpnmitem
= (LPNMLISTVIEW
) lParam
;
393 if (lpnmitem
->iItem
== -1)
395 if (data
->how
== PICK_ANY
) {
397 lpnmitem
->hdr
.hwndFrom
, data
, lpnmitem
->iItem
,
398 NHMENU_IS_SELECTED(data
->menu
.items
[lpnmitem
->iItem
])
404 case LVN_ITEMCHANGED
: {
405 LPNMLISTVIEW lpnmlv
= (LPNMLISTVIEW
) lParam
;
406 if (lpnmlv
->iItem
== -1)
408 if (!(lpnmlv
->uChanged
& LVIF_STATE
))
411 if (data
->how
== PICK_ONE
|| data
->how
== PICK_ANY
) {
412 data
->menu
.items
[lpnmlv
->iItem
].has_focus
=
413 !!(lpnmlv
->uNewState
& LVIS_FOCUSED
);
414 ListView_RedrawItems(lpnmlv
->hdr
.hwndFrom
, lpnmlv
->iItem
,
418 /* update count for single-selection menu (follow the listview
420 if (data
->how
== PICK_ONE
) {
421 if (lpnmlv
->uNewState
& LVIS_SELECTED
) {
422 SelectMenuItem(lpnmlv
->hdr
.hwndFrom
, data
,
427 /* check item focus */
428 if (data
->how
== PICK_ONE
|| data
->how
== PICK_ANY
) {
429 data
->menu
.items
[lpnmlv
->iItem
].has_focus
=
430 !!(lpnmlv
->uNewState
& LVIS_FOCUSED
);
431 ListView_RedrawItems(lpnmlv
->hdr
.hwndFrom
, lpnmlv
->iItem
,
437 reset_menu_count(lpnmhdr
->hwndFrom
, data
);
445 if (hWnd
!= GetNHApp()->hPopupWnd
) {
446 SetFocus(GetNHApp()->hMainWnd
);
448 if (IsWindow(GetMenuControl(hWnd
)))
449 SetFocus(GetMenuControl(hWnd
));
454 if (wParam
== IDC_MENU_LIST
)
455 return onMeasureItem(hWnd
, wParam
, lParam
);
460 if (wParam
== IDC_MENU_LIST
)
461 return onDrawItem(hWnd
, wParam
, lParam
);
465 case WM_CTLCOLORSTATIC
: { /* sent by edit control before it is drawn */
466 HDC hdcEdit
= (HDC
) wParam
;
467 HWND hwndEdit
= (HWND
) lParam
;
468 if (hwndEdit
== GetDlgItem(hWnd
, IDC_MENU_TEXT
)) {
469 SetBkColor(hdcEdit
, text_bg_brush
? text_bg_color
470 : (COLORREF
) GetSysColor(
471 DEFAULT_COLOR_BG_TEXT
));
472 SetTextColor(hdcEdit
, text_fg_brush
? text_fg_color
473 : (COLORREF
) GetSysColor(
474 DEFAULT_COLOR_FG_TEXT
));
475 return (INT_PTR
)(text_bg_brush
477 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT
));
483 return (INT_PTR
)(text_bg_brush
485 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT
));
489 DeleteObject(data
->bmpChecked
);
490 DeleteObject(data
->bmpCheckedCount
);
491 DeleteObject(data
->bmpNotChecked
);
492 if (data
->type
== MENU_TYPE_TEXT
) {
494 free(data
->text
.text
);
497 SetWindowLongPtr(hWnd
, GWLP_USERDATA
, (LONG_PTR
) 0);
503 /*-----------------------------------------------------------------------------*/
505 onMSNHCommand(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
509 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
511 case MSNH_MSG_PUTSTR
: {
512 PMSNHMsgPutstr msg_data
= (PMSNHMsgPutstr
) lParam
;
520 if (data
->type
!= MENU_TYPE_TEXT
)
521 SetMenuType(hWnd
, MENU_TYPE_TEXT
);
523 if (!data
->text
.text
) {
524 text_size
= strlen(msg_data
->text
) + 4;
526 (TCHAR
*) malloc(text_size
* sizeof(data
->text
.text
[0]));
527 ZeroMemory(data
->text
.text
,
528 text_size
* sizeof(data
->text
.text
[0]));
530 text_size
= _tcslen(data
->text
.text
) + strlen(msg_data
->text
) + 4;
531 data
->text
.text
= (TCHAR
*) realloc(
532 data
->text
.text
, text_size
* sizeof(data
->text
.text
[0]));
534 if (!data
->text
.text
)
537 _tcscat(data
->text
.text
, NH_A2W(msg_data
->text
, wbuf
, BUFSZ
));
538 _tcscat(data
->text
.text
, TEXT("\r\n"));
540 text_view
= GetDlgItem(hWnd
, IDC_MENU_TEXT
);
542 panic("cannot get text view window");
543 SetWindowText(text_view
, data
->text
.text
);
545 /* calculate dimensions of the added line of text */
546 hdc
= GetDC(text_view
);
548 SelectObject(hdc
, mswin_get_font(NHW_MENU
, ATR_NONE
, hdc
, FALSE
));
549 SetRect(&text_rt
, 0, 0, 0, 0);
550 DrawText(hdc
, msg_data
->text
, strlen(msg_data
->text
), &text_rt
,
551 DT_CALCRECT
| DT_TOP
| DT_LEFT
| DT_NOPREFIX
553 data
->text
.text_box_size
.cx
=
554 max(text_rt
.right
- text_rt
.left
, data
->text
.text_box_size
.cx
);
555 data
->text
.text_box_size
.cy
+= text_rt
.bottom
- text_rt
.top
;
556 SelectObject(hdc
, saveFont
);
557 ReleaseDC(text_view
, hdc
);
560 case MSNH_MSG_STARTMENU
: {
562 if (data
->type
!= MENU_TYPE_MENU
)
563 SetMenuType(hWnd
, MENU_TYPE_MENU
);
565 if (data
->menu
.items
)
566 free(data
->menu
.items
);
567 data
->how
= PICK_NONE
;
568 data
->menu
.items
= NULL
;
570 data
->menu
.allocated
= 0;
573 for (i
= 0; i
< NUMTABS
; ++i
)
574 data
->menu
.tab_stop_size
[i
] = MIN_TABSTOP_SIZE
;
577 case MSNH_MSG_ADDMENU
: {
578 PMSNHMsgAddMenu msg_data
= (PMSNHMsgAddMenu
) lParam
;
584 LONG menuitemwidth
= 0;
587 if (data
->type
!= MENU_TYPE_MENU
)
589 if (strlen(msg_data
->str
) == 0)
592 if (data
->menu
.size
== data
->menu
.allocated
) {
593 data
->menu
.allocated
+= 10;
594 data
->menu
.items
= (PNHMenuItem
) realloc(
595 data
->menu
.items
, data
->menu
.allocated
* sizeof(NHMenuItem
));
598 new_item
= data
->menu
.size
;
599 ZeroMemory(&data
->menu
.items
[new_item
],
600 sizeof(data
->menu
.items
[new_item
]));
601 data
->menu
.items
[new_item
].glyph
= msg_data
->glyph
;
602 data
->menu
.items
[new_item
].identifier
= *msg_data
->identifier
;
603 data
->menu
.items
[new_item
].accelerator
= msg_data
->accelerator
;
604 data
->menu
.items
[new_item
].group_accel
= msg_data
->group_accel
;
605 data
->menu
.items
[new_item
].attr
= msg_data
->attr
;
606 strncpy(data
->menu
.items
[new_item
].str
, msg_data
->str
,
608 data
->menu
.items
[new_item
].presel
= msg_data
->presel
;
610 /* calculate tabstop size */
612 saveFont
= SelectObject(
613 hDC
, mswin_get_font(NHW_MENU
, msg_data
->attr
, hDC
, FALSE
));
614 GetTextMetrics(hDC
, &tm
);
615 p1
= data
->menu
.items
[new_item
].str
;
616 p
= strchr(data
->menu
.items
[new_item
].str
, '\t');
621 SetRect(&drawRect
, 0, 0, 1, 1);
623 *p
= '\0'; /* for time being, view tab field as zstring */
624 DrawText(hDC
, NH_A2W(p1
, wbuf
, BUFSZ
), strlen(p1
), &drawRect
,
625 DT_CALCRECT
| DT_LEFT
| DT_VCENTER
| DT_EXPANDTABS
627 data
->menu
.tab_stop_size
[column
] =
628 max(data
->menu
.tab_stop_size
[column
],
629 drawRect
.right
- drawRect
.left
);
631 menuitemwidth
+= data
->menu
.tab_stop_size
[column
];
635 else /* last string so, */
638 /* add the separation only when not the last item */
639 /* in the last item, we break out of the loop, in the statement
641 menuitemwidth
+= TAB_SEPARATION
;
645 p
= strchr(p1
, '\t');
647 SelectObject(hDC
, saveFont
);
648 ReleaseDC(hWnd
, hDC
);
650 /* calculate new menu width */
652 max(data
->menu
.menu_cx
,
653 2 * TILE_X
+ menuitemwidth
654 + (tm
.tmAveCharWidth
+ tm
.tmOverhang
) * 12);
660 case MSNH_MSG_ENDMENU
: {
661 PMSNHMsgEndMenu msg_data
= (PMSNHMsgEndMenu
) lParam
;
662 if (msg_data
->text
) {
663 strncpy(data
->menu
.prompt
, msg_data
->text
,
664 sizeof(data
->menu
.prompt
) - 1);
666 ZeroMemory(data
->menu
.prompt
, sizeof(data
->menu
.prompt
));
671 /*-----------------------------------------------------------------------------*/
673 LayoutMenu(HWND hWnd
)
679 POINT pt_elem
, pt_ok
, pt_cancel
;
680 SIZE sz_elem
, sz_ok
, sz_cancel
;
682 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
683 menu_ok
= GetDlgItem(hWnd
, IDOK
);
684 menu_cancel
= GetDlgItem(hWnd
, IDCANCEL
);
686 /* get window coordinates */
687 GetClientRect(hWnd
, &clrt
);
690 if (data
->is_active
) {
691 GetWindowRect(menu_ok
, &rt
);
692 if (data
->type
== MENU_TYPE_TEXT
693 || (data
->type
== MENU_TYPE_MENU
&& data
->how
== PICK_NONE
)) {
694 sz_ok
.cx
= (clrt
.right
- clrt
.left
) - 2 * MENU_MARGIN
;
696 sz_ok
.cx
= (clrt
.right
- clrt
.left
) / 2 - 2 * MENU_MARGIN
;
698 sz_ok
.cy
= rt
.bottom
- rt
.top
;
699 pt_ok
.x
= clrt
.left
+ MENU_MARGIN
;
700 pt_ok
.y
= clrt
.bottom
- MENU_MARGIN
- sz_ok
.cy
;
701 ShowWindow(menu_ok
, SW_SHOW
);
702 MoveWindow(menu_ok
, pt_ok
.x
, pt_ok
.y
, sz_ok
.cx
, sz_ok
.cy
, TRUE
);
704 sz_ok
.cx
= sz_ok
.cy
= 0;
705 pt_ok
.x
= pt_ok
.y
= 0;
706 ShowWindow(menu_ok
, SW_HIDE
);
711 && !(data
->type
== MENU_TYPE_TEXT
712 || (data
->type
== MENU_TYPE_MENU
&& data
->how
== PICK_NONE
))) {
713 GetWindowRect(menu_ok
, &rt
);
714 sz_cancel
.cx
= (clrt
.right
- clrt
.left
) / 2 - 2 * MENU_MARGIN
;
715 pt_cancel
.x
= (clrt
.left
+ clrt
.right
) / 2 + MENU_MARGIN
;
716 sz_cancel
.cy
= rt
.bottom
- rt
.top
;
717 pt_cancel
.y
= clrt
.bottom
- MENU_MARGIN
- sz_cancel
.cy
;
718 ShowWindow(menu_cancel
, SW_SHOW
);
719 MoveWindow(menu_cancel
, pt_cancel
.x
, pt_cancel
.y
, sz_cancel
.cx
,
722 sz_cancel
.cx
= sz_cancel
.cy
= 0;
723 pt_cancel
.x
= pt_cancel
.y
= 0;
724 ShowWindow(menu_cancel
, SW_HIDE
);
728 pt_elem
.x
= clrt
.left
+ MENU_MARGIN
;
729 pt_elem
.y
= clrt
.top
+ MENU_MARGIN
;
730 sz_elem
.cx
= (clrt
.right
- clrt
.left
) - 2 * MENU_MARGIN
;
731 if (data
->is_active
) {
732 sz_elem
.cy
= (clrt
.bottom
- clrt
.top
) - max(sz_ok
.cy
, sz_cancel
.cy
)
735 sz_elem
.cy
= (clrt
.bottom
- clrt
.top
) - 2 * MENU_MARGIN
;
738 if (data
->type
== MENU_TYPE_MENU
) {
739 ListView_SetColumnWidth(
740 GetMenuControl(hWnd
), 0,
741 max(clrt
.right
- clrt
.left
- GetSystemMetrics(SM_CXVSCROLL
),
742 data
->menu
.menu_cx
));
745 MoveWindow(GetMenuControl(hWnd
), pt_elem
.x
, pt_elem
.y
, sz_elem
.cx
,
748 /*-----------------------------------------------------------------------------*/
750 SetMenuType(HWND hWnd
, int type
)
755 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
759 text
= GetDlgItem(hWnd
, IDC_MENU_TEXT
);
760 list
= GetDlgItem(hWnd
, IDC_MENU_LIST
);
761 if (data
->type
== MENU_TYPE_TEXT
) {
762 ShowWindow(list
, SW_HIDE
);
763 EnableWindow(list
, FALSE
);
764 EnableWindow(text
, TRUE
);
765 ShowWindow(text
, SW_SHOW
);
769 ShowWindow(text
, SW_HIDE
);
770 EnableWindow(text
, FALSE
);
771 EnableWindow(list
, TRUE
);
772 ShowWindow(list
, SW_SHOW
);
778 /*-----------------------------------------------------------------------------*/
780 SetMenuListType(HWND hWnd
, int how
)
793 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
794 if (data
->type
!= MENU_TYPE_MENU
)
801 dwStyles
= WS_VISIBLE
| WS_TABSTOP
| WS_CHILD
| WS_VSCROLL
802 | WS_HSCROLL
| LVS_REPORT
| LVS_OWNERDRAWFIXED
806 dwStyles
= WS_VISIBLE
| WS_TABSTOP
| WS_CHILD
| WS_VSCROLL
807 | WS_HSCROLL
| LVS_REPORT
| LVS_OWNERDRAWFIXED
811 dwStyles
= WS_VISIBLE
| WS_TABSTOP
| WS_CHILD
| WS_VSCROLL
812 | WS_HSCROLL
| LVS_REPORT
| LVS_OWNERDRAWFIXED
816 panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY");
819 if (strlen(data
->menu
.prompt
) == 0) {
820 dwStyles
|= LVS_NOCOLUMNHEADER
;
823 GetWindowRect(GetDlgItem(hWnd
, IDC_MENU_LIST
), &rt
);
824 DestroyWindow(GetDlgItem(hWnd
, IDC_MENU_LIST
));
825 control
= CreateWindow(WC_LISTVIEW
, NULL
, dwStyles
, rt
.left
, rt
.top
,
826 rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, hWnd
,
827 (HMENU
) IDC_MENU_LIST
, GetNHApp()->hApp
, NULL
);
829 panic("cannot create menu control");
831 /* install the hook for the control window procedure */
832 wndProcListViewOrig
= (WNDPROC
) GetWindowLongPtr(control
, GWLP_WNDPROC
);
833 SetWindowLongPtr(control
, GWLP_WNDPROC
, (LONG_PTR
) NHMenuListWndProc
);
835 /* set control colors */
836 ListView_SetBkColor(control
, menu_bg_brush
? menu_bg_color
837 : (COLORREF
) GetSysColor(
838 DEFAULT_COLOR_BG_MENU
));
839 ListView_SetTextBkColor(
840 control
, menu_bg_brush
? menu_bg_color
: (COLORREF
) GetSysColor(
841 DEFAULT_COLOR_BG_MENU
));
842 ListView_SetTextColor(
843 control
, menu_fg_brush
? menu_fg_color
: (COLORREF
) GetSysColor(
844 DEFAULT_COLOR_FG_MENU
));
846 /* set control font */
847 fnt
= SendMessage(hWnd
, WM_GETFONT
, (WPARAM
) 0, (LPARAM
) 0);
848 SendMessage(control
, WM_SETFONT
, (WPARAM
) fnt
, (LPARAM
) 0);
850 /* add column to the list view */
851 ZeroMemory(&lvcol
, sizeof(lvcol
));
852 lvcol
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
853 lvcol
.cx
= GetSystemMetrics(SM_CXFULLSCREEN
);
854 lvcol
.pszText
= NH_A2W(data
->menu
.prompt
, wbuf
, BUFSZ
);
855 ListView_InsertColumn(control
, 0, &lvcol
);
857 /* add items to the list view */
858 for (i
= 0; i
< data
->menu
.size
; i
++) {
860 ZeroMemory(&lvitem
, sizeof(lvitem
));
861 sprintf(buf
, "%c - %s", max(data
->menu
.items
[i
].accelerator
, ' '),
862 data
->menu
.items
[i
].str
);
864 lvitem
.mask
= LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
;
867 lvitem
.state
= data
->menu
.items
[i
].presel
? LVIS_SELECTED
: 0;
868 lvitem
.pszText
= NH_A2W(buf
, wbuf
, BUFSZ
);
869 lvitem
.lParam
= (LPARAM
) &data
->menu
.items
[i
];
870 nItem
= (int) SendMessage(control
, LB_ADDSTRING
, (WPARAM
) 0,
872 if (ListView_InsertItem(control
, &lvitem
) == -1) {
873 panic("cannot insert menu item");
879 /*-----------------------------------------------------------------------------*/
881 GetMenuControl(HWND hWnd
)
885 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
887 if (data
->type
== MENU_TYPE_TEXT
) {
888 return GetDlgItem(hWnd
, IDC_MENU_TEXT
);
890 return GetDlgItem(hWnd
, IDC_MENU_LIST
);
893 /*-----------------------------------------------------------------------------*/
895 onMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
897 LPMEASUREITEMSTRUCT lpmis
;
905 UNREFERENCED_PARAMETER(wParam
);
907 lpmis
= (LPMEASUREITEMSTRUCT
) lParam
;
908 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
909 GetClientRect(GetMenuControl(hWnd
), &list_rect
);
911 hdc
= GetDC(GetMenuControl(hWnd
));
913 SelectObject(hdc
, mswin_get_font(NHW_MENU
, ATR_INVERSE
, hdc
, FALSE
));
914 GetTextMetrics(hdc
, &tm
);
916 /* Set the height of the list box items to max height of the individual
918 for (i
= 0; i
< data
->menu
.size
; i
++) {
919 if (NHMENU_HAS_GLYPH(data
->menu
.items
[i
])
920 && !IS_MAP_ASCII(iflags
.wc_map_mode
)) {
922 max(lpmis
->itemHeight
,
923 (UINT
) max(tm
.tmHeight
, GetNHApp()->mapTile_Y
) + 2);
926 max(lpmis
->itemHeight
, (UINT
) max(tm
.tmHeight
, TILE_Y
) + 2);
930 /* set width to the window width */
931 lpmis
->itemWidth
= list_rect
.right
- list_rect
.left
;
933 SelectObject(hdc
, saveFont
);
934 ReleaseDC(GetMenuControl(hWnd
), hdc
);
937 /*-----------------------------------------------------------------------------*/
939 onDrawItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
941 LPDRAWITEMSTRUCT lpdis
;
952 COLORREF OldBg
, OldFg
, NewBg
;
957 int color
= NO_COLOR
, attr
;
958 boolean menucolr
= FALSE
;
960 UNREFERENCED_PARAMETER(wParam
);
962 lpdis
= (LPDRAWITEMSTRUCT
) lParam
;
964 /* If there are no list box items, skip this message. */
965 if (lpdis
->itemID
== -1)
968 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
970 item
= &data
->menu
.items
[lpdis
->itemID
];
972 tileDC
= CreateCompatibleDC(lpdis
->hDC
);
973 saveFont
= SelectObject(
974 lpdis
->hDC
, mswin_get_font(NHW_MENU
, item
->attr
, lpdis
->hDC
, FALSE
));
975 NewBg
= menu_bg_brush
? menu_bg_color
976 : (COLORREF
) GetSysColor(DEFAULT_COLOR_BG_MENU
);
977 OldBg
= SetBkColor(lpdis
->hDC
, NewBg
);
978 OldFg
= SetTextColor(lpdis
->hDC
,
981 : (COLORREF
) GetSysColor(DEFAULT_COLOR_FG_MENU
));
983 GetTextMetrics(lpdis
->hDC
, &tm
);
984 spacing
= tm
.tmAveCharWidth
;
986 /* set initial offset */
987 x
= lpdis
->rcItem
.left
+ 1;
989 /* print check mark and letter */
990 if (NHMENU_IS_SELECTABLE(*item
)) {
992 if (data
->how
!= PICK_NONE
) {
996 switch (item
->count
) {
998 hbrCheckMark
= CreatePatternBrush(data
->bmpChecked
);
1001 hbrCheckMark
= CreatePatternBrush(data
->bmpNotChecked
);
1004 hbrCheckMark
= CreatePatternBrush(data
->bmpCheckedCount
);
1008 y
= (lpdis
->rcItem
.bottom
+ lpdis
->rcItem
.top
- TILE_Y
) / 2;
1009 SetBrushOrgEx(lpdis
->hDC
, x
, y
, NULL
);
1010 saveBrush
= SelectObject(lpdis
->hDC
, hbrCheckMark
);
1011 PatBlt(lpdis
->hDC
, x
, y
, TILE_X
, TILE_Y
, PATCOPY
);
1012 SelectObject(lpdis
->hDC
, saveBrush
);
1013 DeleteObject(hbrCheckMark
);
1016 x
+= TILE_X
+ spacing
;
1018 if (item
->accelerator
!= 0) {
1019 buf
[0] = item
->accelerator
;
1022 if (iflags
.use_menu_color
1023 && (menucolr
= get_menu_coloring(item
->str
, &color
, &attr
))) {
1024 SelectObject(lpdis
->hDC
,
1025 mswin_get_font(NHW_MENU
, attr
, lpdis
->hDC
, FALSE
));
1026 if (color
!= NO_COLOR
)
1027 SetTextColor(lpdis
->hDC
, nhcolor_to_RGB(color
));
1030 SetRect(&drawRect
, x
, lpdis
->rcItem
.top
, lpdis
->rcItem
.right
,
1031 lpdis
->rcItem
.bottom
);
1032 DrawText(lpdis
->hDC
, NH_A2W(buf
, wbuf
, 2), 1, &drawRect
,
1033 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
);
1035 x
+= tm
.tmAveCharWidth
+ tm
.tmOverhang
+ spacing
;
1037 x
+= TILE_X
+ tm
.tmAveCharWidth
+ tm
.tmOverhang
+ 2 * spacing
;
1040 /* print glyph if present */
1041 if (NHMENU_HAS_GLYPH(*item
)) {
1042 if (!IS_MAP_ASCII(iflags
.wc_map_mode
)) {
1045 saveBmp
= SelectObject(tileDC
, GetNHApp()->bmpMapTiles
);
1046 ntile
= glyph2tile
[item
->glyph
];
1048 (ntile
% GetNHApp()->mapTilesPerLine
) * GetNHApp()->mapTile_X
;
1050 (ntile
/ GetNHApp()->mapTilesPerLine
) * GetNHApp()->mapTile_Y
;
1052 y
= (lpdis
->rcItem
.bottom
+ lpdis
->rcItem
.top
1053 - GetNHApp()->mapTile_Y
) / 2;
1055 if (GetNHApp()->bmpMapTiles
== GetNHApp()->bmpTiles
) {
1056 /* using original anethack tiles - apply image transparently */
1057 (*GetNHApp()->lpfnTransparentBlt
)(lpdis
->hDC
, x
, y
, TILE_X
, TILE_Y
,
1058 tileDC
, t_x
, t_y
, TILE_X
, TILE_Y
,
1061 /* using custom tiles - simple blt */
1062 BitBlt(lpdis
->hDC
, x
, y
, GetNHApp()->mapTile_X
,
1063 GetNHApp()->mapTile_Y
, tileDC
, t_x
, t_y
, SRCCOPY
);
1065 SelectObject(tileDC
, saveBmp
);
1066 x
+= GetNHApp()->mapTile_X
;
1068 const char *sel_ind
;
1069 switch (item
->count
) {
1081 SetRect(&drawRect
, x
, lpdis
->rcItem
.top
,
1082 min(x
+ tm
.tmAveCharWidth
, lpdis
->rcItem
.right
),
1083 lpdis
->rcItem
.bottom
);
1084 DrawText(lpdis
->hDC
, NH_A2W(sel_ind
, wbuf
, BUFSZ
), 1, &drawRect
,
1085 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
1086 x
+= tm
.tmAveCharWidth
;
1089 /* no glyph - need to adjust so help window won't look to cramped */
1095 /* draw item text */
1097 p
= strchr(item
->str
, '\t');
1099 SetRect(&drawRect
, x
, lpdis
->rcItem
.top
,
1100 min(x
+ data
->menu
.tab_stop_size
[0], lpdis
->rcItem
.right
),
1101 lpdis
->rcItem
.bottom
);
1105 *p
= '\0'; /* for time being, view tab field as zstring */
1106 DrawText(lpdis
->hDC
, NH_A2W(p1
, wbuf
, BUFSZ
), strlen(p1
), &drawRect
,
1107 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1110 else /* last string so, */
1114 p
= strchr(p1
, '\t');
1115 drawRect
.left
= drawRect
.right
+ TAB_SEPARATION
;
1117 drawRect
.right
= min(drawRect
.left
+ data
->menu
.tab_stop_size
[column
],
1118 lpdis
->rcItem
.right
);
1121 /* draw focused item */
1122 if (item
->has_focus
|| (NHMENU_IS_SELECTABLE(*item
)
1123 && data
->menu
.items
[lpdis
->itemID
].count
!= -1)) {
1126 GetClientRect(lpdis
->hwndItem
, &client_rt
);
1127 client_rt
.right
= min(client_rt
.right
, lpdis
->rcItem
.right
);
1128 if (NHMENU_IS_SELECTABLE(*item
)
1129 && data
->menu
.items
[lpdis
->itemID
].count
!= 0
1130 && item
->glyph
!= NO_GLYPH
) {
1131 if (data
->menu
.items
[lpdis
->itemID
].count
== -1) {
1132 _stprintf(wbuf
, TEXT("Count: All"));
1134 _stprintf(wbuf
, TEXT("Count: %d"),
1135 data
->menu
.items
[lpdis
->itemID
].count
);
1138 SelectObject(lpdis
->hDC
, mswin_get_font(NHW_MENU
, ATR_BLINK
,
1139 lpdis
->hDC
, FALSE
));
1141 /* calculate text rectangle */
1142 SetRect(&drawRect
, client_rt
.left
, lpdis
->rcItem
.top
,
1143 client_rt
.right
, lpdis
->rcItem
.bottom
);
1144 DrawText(lpdis
->hDC
, wbuf
, _tcslen(wbuf
), &drawRect
,
1145 DT_CALCRECT
| DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
1148 /* erase text rectangle */
1150 max(client_rt
.left
+ 1,
1151 client_rt
.right
- (drawRect
.right
- drawRect
.left
) - 10);
1152 drawRect
.right
= client_rt
.right
- 1;
1153 drawRect
.top
= lpdis
->rcItem
.top
;
1154 drawRect
.bottom
= lpdis
->rcItem
.bottom
;
1155 FillRect(lpdis
->hDC
, &drawRect
,
1156 menu_bg_brush
? menu_bg_brush
1157 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU
));
1160 DrawText(lpdis
->hDC
, wbuf
, _tcslen(wbuf
), &drawRect
,
1161 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
);
1164 if (item
->has_focus
) {
1165 /* draw focus rect */
1168 GetClientRect(lpdis
->hwndItem
, &client_rt
);
1169 SetRect(&drawRect
, client_rt
.left
, lpdis
->rcItem
.top
,
1170 client_rt
.left
+ ListView_GetColumnWidth(lpdis
->hwndItem
, 0),
1171 lpdis
->rcItem
.bottom
);
1172 DrawFocusRect(lpdis
->hDC
, &drawRect
);
1175 SetTextColor(lpdis
->hDC
, OldFg
);
1176 SetBkColor(lpdis
->hDC
, OldBg
);
1177 SelectObject(lpdis
->hDC
, saveFont
);
1181 /*-----------------------------------------------------------------------------*/
1183 onListChar(HWND hWnd
, HWND hwndList
, WORD ch
)
1187 int curIndex
, topIndex
, pageSize
;
1188 boolean is_accelerator
= FALSE
;
1190 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
1193 case MENU_FIRST_PAGE
:
1195 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
, LVIS_FOCUSED
);
1196 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1199 case MENU_LAST_PAGE
:
1200 i
= max(0, data
->menu
.size
- 1);
1201 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
, LVIS_FOCUSED
);
1202 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1205 case MENU_NEXT_PAGE
:
1206 topIndex
= ListView_GetTopIndex(hwndList
);
1207 pageSize
= ListView_GetCountPerPage(hwndList
);
1208 curIndex
= ListView_GetNextItem(hwndList
, -1, LVNI_FOCUSED
);
1209 /* Focus down one page */
1210 i
= min(curIndex
+ pageSize
, data
->menu
.size
- 1);
1211 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
, LVIS_FOCUSED
);
1212 /* Scrollpos down one page */
1213 i
= min(topIndex
+ (2 * pageSize
- 1), data
->menu
.size
- 1);
1214 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1217 case MENU_PREVIOUS_PAGE
:
1218 topIndex
= ListView_GetTopIndex(hwndList
);
1219 pageSize
= ListView_GetCountPerPage(hwndList
);
1220 curIndex
= ListView_GetNextItem(hwndList
, -1, LVNI_FOCUSED
);
1221 /* Focus up one page */
1222 i
= max(curIndex
- pageSize
, 0);
1223 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
, LVIS_FOCUSED
);
1224 /* Scrollpos up one page */
1225 i
= max(topIndex
- pageSize
, 0);
1226 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1229 case MENU_SELECT_ALL
:
1230 if (data
->how
== PICK_ANY
) {
1231 reset_menu_count(hwndList
, data
);
1232 for (i
= 0; i
< data
->menu
.size
; i
++) {
1233 SelectMenuItem(hwndList
, data
, i
, -1);
1239 case MENU_UNSELECT_ALL
:
1240 if (data
->how
== PICK_ANY
) {
1241 reset_menu_count(hwndList
, data
);
1242 for (i
= 0; i
< data
->menu
.size
; i
++) {
1243 SelectMenuItem(hwndList
, data
, i
, 0);
1249 case MENU_INVERT_ALL
:
1250 if (data
->how
== PICK_ANY
) {
1251 reset_menu_count(hwndList
, data
);
1252 for (i
= 0; i
< data
->menu
.size
; i
++) {
1253 SelectMenuItem(hwndList
, data
, i
,
1254 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0
1261 case MENU_SELECT_PAGE
:
1262 if (data
->how
== PICK_ANY
) {
1264 reset_menu_count(hwndList
, data
);
1265 topIndex
= ListView_GetTopIndex(hwndList
);
1266 pageSize
= ListView_GetCountPerPage(hwndList
);
1267 from
= max(0, topIndex
);
1268 to
= min(data
->menu
.size
, from
+ pageSize
);
1269 for (i
= from
; i
< to
; i
++) {
1270 SelectMenuItem(hwndList
, data
, i
, -1);
1276 case MENU_UNSELECT_PAGE
:
1277 if (data
->how
== PICK_ANY
) {
1279 reset_menu_count(hwndList
, data
);
1280 topIndex
= ListView_GetTopIndex(hwndList
);
1281 pageSize
= ListView_GetCountPerPage(hwndList
);
1282 from
= max(0, topIndex
);
1283 to
= min(data
->menu
.size
, from
+ pageSize
);
1284 for (i
= from
; i
< to
; i
++) {
1285 SelectMenuItem(hwndList
, data
, i
, 0);
1291 case MENU_INVERT_PAGE
:
1292 if (data
->how
== PICK_ANY
) {
1294 reset_menu_count(hwndList
, data
);
1295 topIndex
= ListView_GetTopIndex(hwndList
);
1296 pageSize
= ListView_GetCountPerPage(hwndList
);
1297 from
= max(0, topIndex
);
1298 to
= min(data
->menu
.size
, from
+ pageSize
);
1299 for (i
= from
; i
< to
; i
++) {
1300 SelectMenuItem(hwndList
, data
, i
,
1301 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0
1309 if (data
->how
== PICK_ANY
|| data
->how
== PICK_ONE
) {
1312 reset_menu_count(hwndList
, data
);
1313 if (mswin_getlin_window("Search for:", buf
, BUFSZ
) == IDCANCEL
) {
1314 strcpy(buf
, "\033");
1316 if (data
->is_active
)
1317 SetFocus(hwndList
); // set focus back to the list control
1318 if (!*buf
|| *buf
== '\033')
1320 for (i
= 0; i
< data
->menu
.size
; i
++) {
1321 if (NHMENU_IS_SELECTABLE(data
->menu
.items
[i
])
1322 && strstr(data
->menu
.items
[i
].str
, buf
)) {
1323 if (data
->how
== PICK_ANY
) {
1326 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0 : -1);
1327 } else if (data
->how
== PICK_ONE
) {
1328 SelectMenuItem(hwndList
, data
, i
, -1);
1329 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
,
1331 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1342 if (GetNHApp()->regaNetHackMode
) {
1343 /* aNetHack mode: Scroll down one page,
1344 ends menu when on last page. */
1347 si
.cbSize
= sizeof(SCROLLINFO
);
1348 si
.fMask
= SIF_POS
| SIF_RANGE
| SIF_PAGE
;
1349 GetScrollInfo(hwndList
, SB_VERT
, &si
);
1350 if ((si
.nPos
+ (int) si
.nPage
) > (si
.nMax
- si
.nMin
)) {
1351 /* We're at the bottom: dismiss. */
1356 /* We're not at the bottom: page down. */
1357 topIndex
= ListView_GetTopIndex(hwndList
);
1358 pageSize
= ListView_GetCountPerPage(hwndList
);
1359 curIndex
= ListView_GetNextItem(hwndList
, -1, LVNI_FOCUSED
);
1360 /* Focus down one page */
1361 i
= min(curIndex
+ pageSize
, data
->menu
.size
- 1);
1362 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
, LVIS_FOCUSED
);
1363 /* Scrollpos down one page */
1364 i
= min(topIndex
+ (2 * pageSize
- 1), data
->menu
.size
- 1);
1365 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1369 /* Windows mode: ends menu for PICK_ONE/PICK_NONE
1370 select item for PICK_ANY */
1371 if (data
->how
== PICK_ONE
|| data
->how
== PICK_NONE
) {
1375 } else if (data
->how
== PICK_ANY
) {
1376 i
= ListView_GetNextItem(hwndList
, -1, LVNI_FOCUSED
);
1380 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0 : -1);
1387 if (strchr(data
->menu
.gacc
, ch
)
1388 && !(ch
== '0' && data
->menu
.counting
)) {
1389 /* matched a group accelerator */
1390 if (data
->how
== PICK_ANY
|| data
->how
== PICK_ONE
) {
1391 reset_menu_count(hwndList
, data
);
1392 for (i
= 0; i
< data
->menu
.size
; i
++) {
1393 if (NHMENU_IS_SELECTABLE(data
->menu
.items
[i
])
1394 && data
->menu
.items
[i
].group_accel
== ch
) {
1395 if (data
->how
== PICK_ANY
) {
1398 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0
1400 } else if (data
->how
== PICK_ONE
) {
1401 SelectMenuItem(hwndList
, data
, i
, -1);
1415 if (isdigit((uchar
) ch
)) {
1417 i
= ListView_GetNextItem(hwndList
, -1, LVNI_FOCUSED
);
1419 count
= data
->menu
.items
[i
].count
;
1423 count
+= (int) (ch
- '0');
1424 if (count
!= 0) /* ignore leading zeros */ {
1425 data
->menu
.counting
= TRUE
;
1426 data
->menu
.items
[i
].count
= min(100000, count
);
1427 ListView_RedrawItems(hwndList
, i
,
1428 i
); /* update count mark */
1434 is_accelerator
= FALSE
;
1435 for (i
= 0; i
< data
->menu
.size
; i
++) {
1436 if (data
->menu
.items
[i
].accelerator
== ch
) {
1437 is_accelerator
= TRUE
;
1442 if ((ch
>= 'a' && ch
<= 'z') || (ch
>= 'A' && ch
<= 'Z')
1443 || is_accelerator
) {
1444 if (data
->how
== PICK_ANY
|| data
->how
== PICK_ONE
) {
1445 topIndex
= ListView_GetTopIndex(hwndList
);
1446 if( topIndex
< 0 || topIndex
> data
->menu
.size
) break; // impossible?
1447 int iter
= topIndex
;
1449 i
= iter
% data
->menu
.size
;
1450 if (data
->menu
.items
[i
].accelerator
== ch
) {
1451 if (data
->how
== PICK_ANY
) {
1454 NHMENU_IS_SELECTED(data
->menu
.items
[i
]) ? 0
1456 ListView_SetItemState(hwndList
, i
, LVIS_FOCUSED
,
1458 ListView_EnsureVisible(hwndList
, i
, FALSE
);
1460 } else if (data
->how
== PICK_ONE
) {
1461 SelectMenuItem(hwndList
, data
, i
, -1);
1467 } while( (++iter
% data
->menu
.size
) != topIndex
);
1473 reset_menu_count(hwndList
, data
);
1476 /*-----------------------------------------------------------------------------*/
1478 mswin_menu_window_size(HWND hWnd
, LPSIZE sz
)
1485 data
= (PNHMenuWindow
) GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
1487 control
= GetMenuControl(hWnd
);
1489 /* get the control size */
1490 GetClientRect(control
, &rt
);
1491 sz
->cx
= rt
.right
- rt
.left
;
1492 sz
->cy
= rt
.bottom
- rt
.top
;
1494 /* calculate "extra" space around the control */
1495 GetWindowRect(hWnd
, &wrt
);
1496 extra_cx
= (wrt
.right
- wrt
.left
) - sz
->cx
;
1498 if (data
->type
== MENU_TYPE_MENU
) {
1499 sz
->cx
= data
->menu
.menu_cx
+ GetSystemMetrics(SM_CXVSCROLL
);
1501 /* Use the width of the text box */
1502 sz
->cx
= data
->text
.text_box_size
.cx
1503 + 2 * GetSystemMetrics(SM_CXVSCROLL
);
1507 /* uninitilized window */
1508 GetClientRect(hWnd
, &rt
);
1509 sz
->cx
= rt
.right
- rt
.left
;
1510 sz
->cy
= rt
.bottom
- rt
.top
;
1513 /*-----------------------------------------------------------------------------*/
1515 SelectMenuItem(HWND hwndList
, PNHMenuWindow data
, int item
, int count
)
1519 if (item
< 0 || item
>= data
->menu
.size
)
1522 if (data
->how
== PICK_ONE
&& count
!= 0) {
1523 for (i
= 0; i
< data
->menu
.size
; i
++)
1524 if (item
!= i
&& data
->menu
.items
[i
].count
!= 0) {
1525 data
->menu
.items
[i
].count
= 0;
1526 ListView_RedrawItems(hwndList
, i
, i
);
1530 data
->menu
.items
[item
].count
= count
;
1531 ListView_RedrawItems(hwndList
, item
, item
);
1532 reset_menu_count(hwndList
, data
);
1534 /*-----------------------------------------------------------------------------*/
1536 reset_menu_count(HWND hwndList
, PNHMenuWindow data
)
1539 data
->menu
.counting
= FALSE
;
1540 if (IsWindow(hwndList
)) {
1541 i
= ListView_GetNextItem((hwndList
), -1, LVNI_FOCUSED
);
1543 ListView_RedrawItems(hwndList
, i
, i
);
1546 /*-----------------------------------------------------------------------------*/
1547 /* List window Proc */
1549 NHMenuListWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1551 BOOL bUpdateFocusItem
;
1553 /* we will redraw focused item whenever horizontal scrolling occurs
1554 since "Count: XXX" indicator is garbled by scrolling */
1555 bUpdateFocusItem
= FALSE
;
1559 if (wParam
== VK_LEFT
|| wParam
== VK_RIGHT
)
1560 bUpdateFocusItem
= TRUE
;
1563 case WM_CHAR
: /* filter keyboard input for the control */
1564 if (wParam
> 0 && wParam
< 256
1565 && onListChar(GetParent(hWnd
), hWnd
, (char) wParam
) == -2) {
1574 bUpdateFocusItem
= TRUE
;
1578 if (GetParent(hWnd
) != GetNHApp()->hPopupWnd
) {
1579 SetFocus(GetNHApp()->hMainWnd
);
1584 /* update focused item */
1585 if (bUpdateFocusItem
) {
1589 /* invalidate the focus rectangle */
1590 i
= ListView_GetNextItem(hWnd
, -1, LVNI_FOCUSED
);
1592 ListView_GetItemRect(hWnd
, i
, &rt
, LVIR_BOUNDS
);
1593 InvalidateRect(hWnd
, &rt
, TRUE
);
1597 /* call ListView control window proc */
1598 if (wndProcListViewOrig
)
1599 return CallWindowProc(wndProcListViewOrig
, hWnd
, message
, wParam
,
1604 /*-----------------------------------------------------------------------------*/
1605 /* Text control window proc - implements scrolling without a cursor */
1607 NHMenuTextWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1615 GetClientRect(hWnd
, &rc
);
1616 FillRect(hDC
, &rc
, text_bg_brush
1618 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT
));
1623 /* close on space in Windows mode
1624 page down on space in aNetHack mode */
1628 si
.cbSize
= sizeof(SCROLLINFO
);
1629 si
.fMask
= SIF_POS
| SIF_RANGE
| SIF_PAGE
;
1630 GetScrollInfo(hWnd
, SB_VERT
, &si
);
1631 /* If anethackmode and not at the end of the list */
1632 if (GetNHApp()->regaNetHackMode
1633 && (si
.nPos
+ (int) si
.nPage
) <= (si
.nMax
- si
.nMin
))
1634 SendMessage(hWnd
, EM_SCROLL
, SB_PAGEDOWN
, 0);
1636 PostMessage(GetParent(hWnd
), WM_COMMAND
, MAKELONG(IDOK
, 0),
1641 SendMessage(hWnd
, EM_SCROLL
, SB_PAGEDOWN
, 0);
1644 SendMessage(hWnd
, EM_SCROLL
, SB_PAGEUP
, 0);
1647 SendMessage(hWnd
, EM_SCROLL
, SB_LINEUP
, 0);
1650 SendMessage(hWnd
, EM_SCROLL
, SB_LINEDOWN
, 0);
1657 case MENU_FIRST_PAGE
:
1658 SendMessage(hWnd
, EM_SCROLL
, SB_TOP
, 0);
1660 case MENU_LAST_PAGE
:
1661 SendMessage(hWnd
, EM_SCROLL
, SB_BOTTOM
, 0);
1663 case MENU_NEXT_PAGE
:
1664 SendMessage(hWnd
, EM_SCROLL
, SB_PAGEDOWN
, 0);
1666 case MENU_PREVIOUS_PAGE
:
1667 SendMessage(hWnd
, EM_SCROLL
, SB_PAGEUP
, 0);
1672 /* edit control needs to know nothing of its focus */
1678 if (editControlWndProc
)
1679 return CallWindowProc(editControlWndProc
, hWnd
, message
, wParam
,
1684 /*-----------------------------------------------------------------------------*/