1 /* NetHack 3.6 mhmenu.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */
2 /* Copyright (c) Alex Kompel, 2002 */
3 /* NetHack 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_nethack_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 if (!GetNHApp()->bWindowsLocked) {
124 style = GetWindowLong(ret, GWL_STYLE);
126 SetWindowLong(ret, GWL_STYLE, style);
127 SetWindowPos(ret, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
132 SetMenuType(ret, type);
135 /*-----------------------------------------------------------------------------*/
137 mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected,
142 MENU_ITEM_P *selected = NULL;
146 assert(_selected != NULL);
150 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
152 /* force activate for certain menu types */
153 if (data->type == MENU_TYPE_MENU
154 && (how == PICK_ONE || how == PICK_ANY)) {
158 data->is_active = activate;
161 SetMenuListType(hWnd, how);
163 /* Ok, now give items a unique accelerators */
164 if (data->type == MENU_TYPE_MENU) {
165 char next_char = 'a';
167 data->menu.gacc[0] = '\0';
168 ap = data->menu.gacc;
169 for (i = 0; i < data->menu.size; i++) {
170 if (data->menu.items[i].accelerator != 0) {
171 next_char = (char) (data->menu.items[i].accelerator + 1);
172 } else if (NHMENU_IS_SELECTABLE(data->menu.items[i])) {
173 if ((next_char >= 'a' && next_char <= 'z')
174 || (next_char >= 'A' && next_char <= 'Z')) {
175 data->menu.items[i].accelerator = next_char;
179 else if (next_char > 'Z')
182 data->menu.items[i].accelerator = next_char;
189 /* collect group accelerators */
190 for (i = 0; i < data->menu.size; i++) {
191 if (data->how != PICK_NONE) {
192 if (data->menu.items[i].group_accel
193 && !strchr(data->menu.gacc,
194 data->menu.items[i].group_accel)) {
195 *ap++ = data->menu.items[i].group_accel;
201 reset_menu_count(NULL, data);
204 LayoutMenu(hWnd); // show dialog buttons
207 mswin_popup_display(hWnd, &data->done);
209 SetFocus(GetNHApp()->hMainWnd);
210 mswin_layout_main_window(hWnd);
214 if (data->result != -1) {
215 if (how == PICK_NONE) {
216 if (data->result >= 0)
220 } else if (how == PICK_ONE || how == PICK_ANY) {
221 /* count selected items */
223 for (i = 0; i < data->menu.size; i++) {
224 if (NHMENU_IS_SELECTABLE(data->menu.items[i])
225 && NHMENU_IS_SELECTED(data->menu.items[i])) {
233 (MENU_ITEM_P *) malloc(ret_val * sizeof(MENU_ITEM_P));
235 panic("out of memory");
238 for (i = 0; i < data->menu.size; i++) {
239 if (NHMENU_IS_SELECTABLE(data->menu.items[i])
240 && NHMENU_IS_SELECTED(data->menu.items[i])) {
241 selected[sel_ind].item =
242 data->menu.items[i].identifier;
243 selected[sel_ind].count = data->menu.items[i].count;
248 *_selected = selected;
254 data->is_active = FALSE;
255 LayoutMenu(hWnd); // hide dialog buttons
256 mswin_popup_destroy(hWnd);
260 /*-----------------------------------------------------------------------------*/
262 MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
267 TCHAR title[MAX_LOADSTRING];
269 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
272 data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow));
273 ZeroMemory(data, sizeof(NHMenuWindow));
274 data->type = MENU_TYPE_TEXT;
275 data->how = PICK_NONE;
279 LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL));
280 data->bmpCheckedCount =
281 LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT));
282 data->bmpNotChecked =
283 LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL));
284 data->is_active = FALSE;
285 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
287 /* set font for the text cotrol */
288 control = GetDlgItem(hWnd, IDC_MENU_TEXT);
289 hdc = GetDC(control);
290 SendMessage(control, WM_SETFONT,
291 (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE),
293 ReleaseDC(control, hdc);
295 /* subclass edit control */
297 (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC);
298 SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHMenuTextWndProc);
300 /* Even though the dialog has no caption, you can still set the title
301 which shows on Alt-Tab */
302 LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING);
303 SetWindowText(hWnd, title);
305 /* set focus to text control for now */
309 case WM_MSNH_COMMAND:
310 onMSNHCommand(hWnd, wParam, lParam);
316 GetWindowRect(hWnd, &rt);
317 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
318 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
319 if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN)
320 mswin_update_window_placement(NHW_INVEN, &rt);
322 mswin_update_window_placement(NHW_MENU, &rt);
328 GetWindowRect(hWnd, &rt);
329 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
330 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
331 if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN)
332 mswin_update_window_placement(NHW_INVEN, &rt);
334 mswin_update_window_placement(NHW_MENU, &rt);
339 if (program_state.gameover) {
342 program_state.stopprint++;
348 switch (LOWORD(wParam)) {
350 if (data->type == MENU_TYPE_MENU
351 && (data->how == PICK_ONE || data->how == PICK_ANY)
352 && data->menu.counting) {
356 /* reset counter if counting is in progress */
357 list = GetMenuControl(hWnd);
358 i = ListView_GetNextItem(list, -1, LVNI_FOCUSED);
360 SelectMenuItem(list, data, i, 0);
377 LPNMHDR lpnmhdr = (LPNMHDR) lParam;
378 switch (LOWORD(wParam)) {
379 case IDC_MENU_LIST: {
380 if (!data || data->type != MENU_TYPE_MENU)
383 switch (lpnmhdr->code) {
384 case LVN_ITEMACTIVATE: {
385 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam;
386 if (data->how == PICK_ONE) {
387 if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menu.size
388 && NHMENU_IS_SELECTABLE(
389 data->menu.items[lpnmlv->iItem])) {
390 SelectMenuItem(lpnmlv->hdr.hwndFrom, data,
400 LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam;
401 if (lpnmitem->iItem == -1)
403 if (data->how == PICK_ANY) {
405 lpnmitem->hdr.hwndFrom, data, lpnmitem->iItem,
406 NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem])
412 case LVN_ITEMCHANGED: {
413 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam;
414 if (lpnmlv->iItem == -1)
416 if (!(lpnmlv->uChanged & LVIF_STATE))
419 if (data->how == PICK_ONE || data->how == PICK_ANY) {
420 data->menu.items[lpnmlv->iItem].has_focus =
421 !!(lpnmlv->uNewState & LVIS_FOCUSED);
422 ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem,
426 /* update count for single-selection menu (follow the listview
428 if (data->how == PICK_ONE) {
429 if (lpnmlv->uNewState & LVIS_SELECTED) {
430 SelectMenuItem(lpnmlv->hdr.hwndFrom, data,
435 /* check item focus */
436 if (data->how == PICK_ONE || data->how == PICK_ANY) {
437 data->menu.items[lpnmlv->iItem].has_focus =
438 !!(lpnmlv->uNewState & LVIS_FOCUSED);
439 ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem,
445 reset_menu_count(lpnmhdr->hwndFrom, data);
453 if (hWnd != GetNHApp()->hPopupWnd) {
454 SetFocus(GetNHApp()->hMainWnd);
456 if (IsWindow(GetMenuControl(hWnd)))
457 SetFocus(GetMenuControl(hWnd));
462 if (wParam == IDC_MENU_LIST)
463 return onMeasureItem(hWnd, wParam, lParam);
468 if (wParam == IDC_MENU_LIST)
469 return onDrawItem(hWnd, wParam, lParam);
473 case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
474 HDC hdcEdit = (HDC) wParam;
475 HWND hwndEdit = (HWND) lParam;
476 if (hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT)) {
477 SetBkColor(hdcEdit, text_bg_brush ? text_bg_color
478 : (COLORREF) GetSysColor(
479 DEFAULT_COLOR_BG_TEXT));
480 SetTextColor(hdcEdit, text_fg_brush ? text_fg_color
481 : (COLORREF) GetSysColor(
482 DEFAULT_COLOR_FG_TEXT));
483 return (INT_PTR)(text_bg_brush
485 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT));
492 DeleteObject(data->bmpChecked);
493 DeleteObject(data->bmpCheckedCount);
494 DeleteObject(data->bmpNotChecked);
495 if (data->type == MENU_TYPE_TEXT) {
497 free(data->text.text);
500 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
506 /*-----------------------------------------------------------------------------*/
508 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
512 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
514 case MSNH_MSG_PUTSTR: {
515 PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam;
523 if (data->type != MENU_TYPE_TEXT)
524 SetMenuType(hWnd, MENU_TYPE_TEXT);
526 if (!data->text.text) {
527 text_size = strlen(msg_data->text) + 4;
529 (TCHAR *) malloc(text_size * sizeof(data->text.text[0]));
530 ZeroMemory(data->text.text,
531 text_size * sizeof(data->text.text[0]));
533 text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4;
534 data->text.text = (TCHAR *) realloc(
535 data->text.text, text_size * sizeof(data->text.text[0]));
537 if (!data->text.text)
540 _tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ));
541 _tcscat(data->text.text, TEXT("\r\n"));
543 text_view = GetDlgItem(hWnd, IDC_MENU_TEXT);
545 panic("cannot get text view window");
546 SetWindowText(text_view, data->text.text);
548 /* calculate dimensions of the added line of text */
549 hdc = GetDC(text_view);
551 SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
552 SetRect(&text_rt, 0, 0, 0, 0);
553 DrawText(hdc, msg_data->text, strlen(msg_data->text), &text_rt,
554 DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX
556 data->text.text_box_size.cx =
557 max(text_rt.right - text_rt.left, data->text.text_box_size.cx);
558 data->text.text_box_size.cy += text_rt.bottom - text_rt.top;
559 SelectObject(hdc, saveFont);
560 ReleaseDC(text_view, hdc);
563 case MSNH_MSG_STARTMENU: {
565 if (data->type != MENU_TYPE_MENU)
566 SetMenuType(hWnd, MENU_TYPE_MENU);
568 if (data->menu.items)
569 free(data->menu.items);
570 data->how = PICK_NONE;
571 data->menu.items = NULL;
573 data->menu.allocated = 0;
576 for (i = 0; i < NUMTABS; ++i)
577 data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE;
580 case MSNH_MSG_ADDMENU: {
581 PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu) lParam;
587 LONG menuitemwidth = 0;
590 if (data->type != MENU_TYPE_MENU)
592 if (strlen(msg_data->str) == 0)
595 if (data->menu.size == data->menu.allocated) {
596 data->menu.allocated += 10;
597 data->menu.items = (PNHMenuItem) realloc(
598 data->menu.items, data->menu.allocated * sizeof(NHMenuItem));
601 new_item = data->menu.size;
602 ZeroMemory(&data->menu.items[new_item],
603 sizeof(data->menu.items[new_item]));
604 data->menu.items[new_item].glyph = msg_data->glyph;
605 data->menu.items[new_item].identifier = *msg_data->identifier;
606 data->menu.items[new_item].accelerator = msg_data->accelerator;
607 data->menu.items[new_item].group_accel = msg_data->group_accel;
608 data->menu.items[new_item].attr = msg_data->attr;
609 strncpy(data->menu.items[new_item].str, msg_data->str,
611 data->menu.items[new_item].presel = msg_data->presel;
613 /* calculate tabstop size */
615 saveFont = SelectObject(
616 hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE));
617 GetTextMetrics(hDC, &tm);
618 p1 = data->menu.items[new_item].str;
619 p = strchr(data->menu.items[new_item].str, '\t');
624 SetRect(&drawRect, 0, 0, 1, 1);
626 *p = '\0'; /* for time being, view tab field as zstring */
627 DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect,
628 DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS
630 data->menu.tab_stop_size[column] =
631 max(data->menu.tab_stop_size[column],
632 drawRect.right - drawRect.left);
634 menuitemwidth += data->menu.tab_stop_size[column];
638 else /* last string so, */
641 /* add the separation only when not the last item */
642 /* in the last item, we break out of the loop, in the statement
644 menuitemwidth += TAB_SEPARATION;
648 p = strchr(p1, '\t');
650 SelectObject(hDC, saveFont);
651 ReleaseDC(hWnd, hDC);
653 /* calculate new menu width */
655 max(data->menu.menu_cx,
656 2 * TILE_X + menuitemwidth
657 + (tm.tmAveCharWidth + tm.tmOverhang) * 12);
663 case MSNH_MSG_ENDMENU: {
664 PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu) lParam;
665 if (msg_data->text) {
666 strncpy(data->menu.prompt, msg_data->text,
667 sizeof(data->menu.prompt) - 1);
669 ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt));
674 /*-----------------------------------------------------------------------------*/
676 LayoutMenu(HWND hWnd)
682 POINT pt_elem, pt_ok, pt_cancel;
683 SIZE sz_elem, sz_ok, sz_cancel;
685 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
686 menu_ok = GetDlgItem(hWnd, IDOK);
687 menu_cancel = GetDlgItem(hWnd, IDCANCEL);
689 /* get window coordinates */
690 GetClientRect(hWnd, &clrt);
693 if (data->is_active) {
694 GetWindowRect(menu_ok, &rt);
695 if (data->type == MENU_TYPE_TEXT
696 || (data->type == MENU_TYPE_MENU && data->how == PICK_NONE)) {
697 sz_ok.cx = (clrt.right - clrt.left) - 2 * MENU_MARGIN;
699 sz_ok.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN;
701 sz_ok.cy = rt.bottom - rt.top;
702 pt_ok.x = clrt.left + MENU_MARGIN;
703 pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy;
704 ShowWindow(menu_ok, SW_SHOW);
705 MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE);
707 sz_ok.cx = sz_ok.cy = 0;
708 pt_ok.x = pt_ok.y = 0;
709 ShowWindow(menu_ok, SW_HIDE);
714 && !(data->type == MENU_TYPE_TEXT
715 || (data->type == MENU_TYPE_MENU && data->how == PICK_NONE))) {
716 GetWindowRect(menu_ok, &rt);
717 sz_cancel.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN;
718 pt_cancel.x = (clrt.left + clrt.right) / 2 + MENU_MARGIN;
719 sz_cancel.cy = rt.bottom - rt.top;
720 pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy;
721 ShowWindow(menu_cancel, SW_SHOW);
722 MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx,
725 sz_cancel.cx = sz_cancel.cy = 0;
726 pt_cancel.x = pt_cancel.y = 0;
727 ShowWindow(menu_cancel, SW_HIDE);
731 pt_elem.x = clrt.left + MENU_MARGIN;
732 pt_elem.y = clrt.top + MENU_MARGIN;
733 sz_elem.cx = (clrt.right - clrt.left) - 2 * MENU_MARGIN;
734 if (data->is_active) {
735 sz_elem.cy = (clrt.bottom - clrt.top) - max(sz_ok.cy, sz_cancel.cy)
738 sz_elem.cy = (clrt.bottom - clrt.top) - 2 * MENU_MARGIN;
741 if (data->type == MENU_TYPE_MENU) {
742 ListView_SetColumnWidth(
743 GetMenuControl(hWnd), 0,
744 max(clrt.right - clrt.left - GetSystemMetrics(SM_CXVSCROLL),
745 data->menu.menu_cx));
748 MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx,
751 /*-----------------------------------------------------------------------------*/
753 SetMenuType(HWND hWnd, int type)
758 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
762 text = GetDlgItem(hWnd, IDC_MENU_TEXT);
763 list = GetDlgItem(hWnd, IDC_MENU_LIST);
764 if (data->type == MENU_TYPE_TEXT) {
765 ShowWindow(list, SW_HIDE);
766 EnableWindow(list, FALSE);
767 EnableWindow(text, TRUE);
768 ShowWindow(text, SW_SHOW);
772 ShowWindow(text, SW_HIDE);
773 EnableWindow(text, FALSE);
774 EnableWindow(list, TRUE);
775 ShowWindow(list, SW_SHOW);
781 /*-----------------------------------------------------------------------------*/
783 SetMenuListType(HWND hWnd, int how)
796 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
797 if (data->type != MENU_TYPE_MENU)
804 dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL
805 | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED
809 dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL
810 | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED
814 dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL
815 | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED
819 panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY");
822 if (strlen(data->menu.prompt) == 0) {
823 dwStyles |= LVS_NOCOLUMNHEADER;
826 GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt);
827 DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST));
828 control = CreateWindow(WC_LISTVIEW, NULL, dwStyles, rt.left, rt.top,
829 rt.right - rt.left, rt.bottom - rt.top, hWnd,
830 (HMENU) IDC_MENU_LIST, GetNHApp()->hApp, NULL);
832 panic("cannot create menu control");
834 /* install the hook for the control window procedure */
835 wndProcListViewOrig = (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC);
836 SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHMenuListWndProc);
838 /* set control colors */
839 ListView_SetBkColor(control, menu_bg_brush ? menu_bg_color
840 : (COLORREF) GetSysColor(
841 DEFAULT_COLOR_BG_MENU));
842 ListView_SetTextBkColor(
843 control, menu_bg_brush ? menu_bg_color : (COLORREF) GetSysColor(
844 DEFAULT_COLOR_BG_MENU));
845 ListView_SetTextColor(
846 control, menu_fg_brush ? menu_fg_color : (COLORREF) GetSysColor(
847 DEFAULT_COLOR_FG_MENU));
849 /* set control font */
850 fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM) 0, (LPARAM) 0);
851 SendMessage(control, WM_SETFONT, (WPARAM) fnt, (LPARAM) 0);
853 /* add column to the list view */
854 ZeroMemory(&lvcol, sizeof(lvcol));
855 lvcol.mask = LVCF_WIDTH | LVCF_TEXT;
856 lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN);
857 lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ);
858 ListView_InsertColumn(control, 0, &lvcol);
860 /* add items to the list view */
861 for (i = 0; i < data->menu.size; i++) {
863 ZeroMemory(&lvitem, sizeof(lvitem));
864 sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '),
865 data->menu.items[i].str);
867 lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
870 lvitem.state = data->menu.items[i].presel ? LVIS_SELECTED : 0;
871 lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ);
872 lvitem.lParam = (LPARAM) &data->menu.items[i];
873 nItem = (int) SendMessage(control, LB_ADDSTRING, (WPARAM) 0,
875 if (ListView_InsertItem(control, &lvitem) == -1) {
876 panic("cannot insert menu item");
882 /*-----------------------------------------------------------------------------*/
884 GetMenuControl(HWND hWnd)
888 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
890 if (data->type == MENU_TYPE_TEXT) {
891 return GetDlgItem(hWnd, IDC_MENU_TEXT);
893 return GetDlgItem(hWnd, IDC_MENU_LIST);
896 /*-----------------------------------------------------------------------------*/
898 onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
900 LPMEASUREITEMSTRUCT lpmis;
908 UNREFERENCED_PARAMETER(wParam);
910 lpmis = (LPMEASUREITEMSTRUCT) lParam;
911 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
912 GetClientRect(GetMenuControl(hWnd), &list_rect);
914 hdc = GetDC(GetMenuControl(hWnd));
916 SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE));
917 GetTextMetrics(hdc, &tm);
919 /* Set the height of the list box items to max height of the individual
921 for (i = 0; i < data->menu.size; i++) {
922 if (NHMENU_HAS_GLYPH(data->menu.items[i])
923 && !IS_MAP_ASCII(iflags.wc_map_mode)) {
925 max(lpmis->itemHeight,
926 (UINT) max(tm.tmHeight, GetNHApp()->mapTile_Y) + 2);
929 max(lpmis->itemHeight, (UINT) max(tm.tmHeight, TILE_Y) + 2);
933 /* set width to the window width */
934 lpmis->itemWidth = list_rect.right - list_rect.left;
936 SelectObject(hdc, saveFont);
937 ReleaseDC(GetMenuControl(hWnd), hdc);
940 /*-----------------------------------------------------------------------------*/
942 onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
944 LPDRAWITEMSTRUCT lpdis;
955 COLORREF OldBg, OldFg, NewBg;
960 int color = NO_COLOR, attr;
961 boolean menucolr = FALSE;
963 UNREFERENCED_PARAMETER(wParam);
965 lpdis = (LPDRAWITEMSTRUCT) lParam;
967 /* If there are no list box items, skip this message. */
968 if (lpdis->itemID == -1)
971 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
973 item = &data->menu.items[lpdis->itemID];
975 tileDC = CreateCompatibleDC(lpdis->hDC);
976 saveFont = SelectObject(
977 lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE));
978 NewBg = menu_bg_brush ? menu_bg_color
979 : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MENU);
980 OldBg = SetBkColor(lpdis->hDC, NewBg);
981 OldFg = SetTextColor(lpdis->hDC,
984 : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MENU));
986 GetTextMetrics(lpdis->hDC, &tm);
987 spacing = tm.tmAveCharWidth;
989 /* set initial offset */
990 x = lpdis->rcItem.left + 1;
992 /* print check mark and letter */
993 if (NHMENU_IS_SELECTABLE(*item)) {
995 if (data->how != PICK_NONE) {
999 switch (item->count) {
1001 hbrCheckMark = CreatePatternBrush(data->bmpChecked);
1004 hbrCheckMark = CreatePatternBrush(data->bmpNotChecked);
1007 hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount);
1011 y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2;
1012 SetBrushOrgEx(lpdis->hDC, x, y, NULL);
1013 saveBrush = SelectObject(lpdis->hDC, hbrCheckMark);
1014 PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY);
1015 SelectObject(lpdis->hDC, saveBrush);
1016 DeleteObject(hbrCheckMark);
1019 x += TILE_X + spacing;
1021 if (item->accelerator != 0) {
1022 buf[0] = item->accelerator;
1025 if (iflags.use_menu_color
1026 && (menucolr = get_menu_coloring(item->str, &color, &attr))) {
1027 /* TODO: use attr too */
1028 if (color != NO_COLOR)
1029 SetTextColor(lpdis->hDC, nhcolor_to_RGB(color));
1032 SetRect(&drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right,
1033 lpdis->rcItem.bottom);
1034 DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect,
1035 DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
1037 x += tm.tmAveCharWidth + tm.tmOverhang + spacing;
1039 x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing;
1042 /* print glyph if present */
1043 if (NHMENU_HAS_GLYPH(*item)) {
1044 if (!IS_MAP_ASCII(iflags.wc_map_mode)) {
1047 saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
1048 ntile = glyph2tile[item->glyph];
1050 (ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X;
1052 (ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y;
1054 y = (lpdis->rcItem.bottom + lpdis->rcItem.top
1055 - GetNHApp()->mapTile_Y) / 2;
1057 if (GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles) {
1058 /* using original nethack tiles - apply image transparently */
1059 (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, TILE_X, TILE_Y,
1060 tileDC, t_x, t_y, TILE_X, TILE_Y,
1063 /* using custom tiles - simple blt */
1064 BitBlt(lpdis->hDC, x, y, GetNHApp()->mapTile_X,
1065 GetNHApp()->mapTile_Y, tileDC, t_x, t_y, SRCCOPY);
1067 SelectObject(tileDC, saveBmp);
1068 x += GetNHApp()->mapTile_X;
1070 const char *sel_ind;
1071 switch (item->count) {
1083 SetRect(&drawRect, x, lpdis->rcItem.top,
1084 min(x + tm.tmAveCharWidth, lpdis->rcItem.right),
1085 lpdis->rcItem.bottom);
1086 DrawText(lpdis->hDC, NH_A2W(sel_ind, wbuf, BUFSZ), 1, &drawRect,
1087 DT_CENTER | DT_VCENTER | DT_SINGLELINE);
1088 x += tm.tmAveCharWidth;
1091 /* no glyph - need to adjust so help window won't look to cramped */
1097 /* draw item text */
1099 p = strchr(item->str, '\t');
1101 SetRect(&drawRect, x, lpdis->rcItem.top,
1102 min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right),
1103 lpdis->rcItem.bottom);
1107 *p = '\0'; /* for time being, view tab field as zstring */
1108 DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect,
1109 DT_LEFT | DT_VCENTER | DT_SINGLELINE);
1112 else /* last string so, */
1116 p = strchr(p1, '\t');
1117 drawRect.left = drawRect.right + TAB_SEPARATION;
1119 drawRect.right = min(drawRect.left + data->menu.tab_stop_size[column],
1120 lpdis->rcItem.right);
1123 /* draw focused item */
1124 if (item->has_focus || (NHMENU_IS_SELECTABLE(*item)
1125 && data->menu.items[lpdis->itemID].count != -1)) {
1128 GetClientRect(lpdis->hwndItem, &client_rt);
1129 client_rt.right = min(client_rt.right, lpdis->rcItem.right);
1130 if (NHMENU_IS_SELECTABLE(*item)
1131 && data->menu.items[lpdis->itemID].count != 0
1132 && item->glyph != NO_GLYPH) {
1133 if (data->menu.items[lpdis->itemID].count == -1) {
1134 _stprintf(wbuf, TEXT("Count: All"));
1136 _stprintf(wbuf, TEXT("Count: %d"),
1137 data->menu.items[lpdis->itemID].count);
1140 SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK,
1141 lpdis->hDC, FALSE));
1143 /* calculate text rectangle */
1144 SetRect(&drawRect, client_rt.left, lpdis->rcItem.top,
1145 client_rt.right, lpdis->rcItem.bottom);
1146 DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect,
1147 DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE
1150 /* erase text rectangle */
1152 max(client_rt.left + 1,
1153 client_rt.right - (drawRect.right - drawRect.left) - 10);
1154 drawRect.right = client_rt.right - 1;
1155 drawRect.top = lpdis->rcItem.top;
1156 drawRect.bottom = lpdis->rcItem.bottom;
1157 FillRect(lpdis->hDC, &drawRect,
1158 menu_bg_brush ? menu_bg_brush
1159 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU));
1162 DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect,
1163 DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
1166 if (item->has_focus) {
1167 /* draw focus rect */
1170 GetClientRect(lpdis->hwndItem, &client_rt);
1171 SetRect(&drawRect, client_rt.left, lpdis->rcItem.top,
1172 client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0),
1173 lpdis->rcItem.bottom);
1174 DrawFocusRect(lpdis->hDC, &drawRect);
1177 SetTextColor(lpdis->hDC, OldFg);
1178 SetBkColor(lpdis->hDC, OldBg);
1179 SelectObject(lpdis->hDC, saveFont);
1183 /*-----------------------------------------------------------------------------*/
1185 onListChar(HWND hWnd, HWND hwndList, WORD ch)
1189 int curIndex, topIndex, pageSize;
1190 boolean is_accelerator = FALSE;
1192 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
1195 case MENU_FIRST_PAGE:
1197 ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
1198 ListView_EnsureVisible(hwndList, i, FALSE);
1201 case MENU_LAST_PAGE:
1202 i = max(0, data->menu.size - 1);
1203 ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
1204 ListView_EnsureVisible(hwndList, i, FALSE);
1207 case MENU_NEXT_PAGE:
1208 topIndex = ListView_GetTopIndex(hwndList);
1209 pageSize = ListView_GetCountPerPage(hwndList);
1210 curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
1211 /* Focus down one page */
1212 i = min(curIndex + pageSize, data->menu.size - 1);
1213 ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
1214 /* Scrollpos down one page */
1215 i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1);
1216 ListView_EnsureVisible(hwndList, i, FALSE);
1219 case MENU_PREVIOUS_PAGE:
1220 topIndex = ListView_GetTopIndex(hwndList);
1221 pageSize = ListView_GetCountPerPage(hwndList);
1222 curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
1223 /* Focus up one page */
1224 i = max(curIndex - pageSize, 0);
1225 ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
1226 /* Scrollpos up one page */
1227 i = max(topIndex - pageSize, 0);
1228 ListView_EnsureVisible(hwndList, i, FALSE);
1231 case MENU_SELECT_ALL:
1232 if (data->how == PICK_ANY) {
1233 reset_menu_count(hwndList, data);
1234 for (i = 0; i < data->menu.size; i++) {
1235 SelectMenuItem(hwndList, data, i, -1);
1241 case MENU_UNSELECT_ALL:
1242 if (data->how == PICK_ANY) {
1243 reset_menu_count(hwndList, data);
1244 for (i = 0; i < data->menu.size; i++) {
1245 SelectMenuItem(hwndList, data, i, 0);
1251 case MENU_INVERT_ALL:
1252 if (data->how == PICK_ANY) {
1253 reset_menu_count(hwndList, data);
1254 for (i = 0; i < data->menu.size; i++) {
1255 SelectMenuItem(hwndList, data, i,
1256 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0
1263 case MENU_SELECT_PAGE:
1264 if (data->how == PICK_ANY) {
1266 reset_menu_count(hwndList, data);
1267 topIndex = ListView_GetTopIndex(hwndList);
1268 pageSize = ListView_GetCountPerPage(hwndList);
1269 from = max(0, topIndex);
1270 to = min(data->menu.size, from + pageSize);
1271 for (i = from; i < to; i++) {
1272 SelectMenuItem(hwndList, data, i, -1);
1278 case MENU_UNSELECT_PAGE:
1279 if (data->how == PICK_ANY) {
1281 reset_menu_count(hwndList, data);
1282 topIndex = ListView_GetTopIndex(hwndList);
1283 pageSize = ListView_GetCountPerPage(hwndList);
1284 from = max(0, topIndex);
1285 to = min(data->menu.size, from + pageSize);
1286 for (i = from; i < to; i++) {
1287 SelectMenuItem(hwndList, data, i, 0);
1293 case MENU_INVERT_PAGE:
1294 if (data->how == PICK_ANY) {
1296 reset_menu_count(hwndList, data);
1297 topIndex = ListView_GetTopIndex(hwndList);
1298 pageSize = ListView_GetCountPerPage(hwndList);
1299 from = max(0, topIndex);
1300 to = min(data->menu.size, from + pageSize);
1301 for (i = from; i < to; i++) {
1302 SelectMenuItem(hwndList, data, i,
1303 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0
1311 if (data->how == PICK_ANY || data->how == PICK_ONE) {
1314 reset_menu_count(hwndList, data);
1315 if (mswin_getlin_window("Search for:", buf, BUFSZ) == IDCANCEL) {
1316 strcpy(buf, "\033");
1318 if (data->is_active)
1319 SetFocus(hwndList); // set focus back to the list control
1320 if (!*buf || *buf == '\033')
1322 for (i = 0; i < data->menu.size; i++) {
1323 if (NHMENU_IS_SELECTABLE(data->menu.items[i])
1324 && strstr(data->menu.items[i].str, buf)) {
1325 if (data->how == PICK_ANY) {
1328 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1);
1329 } else if (data->how == PICK_ONE) {
1330 SelectMenuItem(hwndList, data, i, -1);
1331 ListView_SetItemState(hwndList, i, LVIS_FOCUSED,
1333 ListView_EnsureVisible(hwndList, i, FALSE);
1344 if (GetNHApp()->regNetHackMode) {
1345 /* NetHack mode: Scroll down one page,
1346 ends menu when on last page. */
1349 si.cbSize = sizeof(SCROLLINFO);
1350 si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
1351 GetScrollInfo(hwndList, SB_VERT, &si);
1352 if ((si.nPos + (int) si.nPage) > (si.nMax - si.nMin)) {
1353 /* We're at the bottom: dismiss. */
1358 /* We're not at the bottom: page down. */
1359 topIndex = ListView_GetTopIndex(hwndList);
1360 pageSize = ListView_GetCountPerPage(hwndList);
1361 curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
1362 /* Focus down one page */
1363 i = min(curIndex + pageSize, data->menu.size - 1);
1364 ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
1365 /* Scrollpos down one page */
1366 i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1);
1367 ListView_EnsureVisible(hwndList, i, FALSE);
1371 /* Windows mode: ends menu for PICK_ONE/PICK_NONE
1372 select item for PICK_ANY */
1373 if (data->how == PICK_ONE || data->how == PICK_NONE) {
1377 } else if (data->how == PICK_ANY) {
1378 i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
1382 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1);
1389 if (strchr(data->menu.gacc, ch)
1390 && !(ch == '0' && data->menu.counting)) {
1391 /* matched a group accelerator */
1392 if (data->how == PICK_ANY || data->how == PICK_ONE) {
1393 reset_menu_count(hwndList, data);
1394 for (i = 0; i < data->menu.size; i++) {
1395 if (NHMENU_IS_SELECTABLE(data->menu.items[i])
1396 && data->menu.items[i].group_accel == ch) {
1397 if (data->how == PICK_ANY) {
1400 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0
1402 } else if (data->how == PICK_ONE) {
1403 SelectMenuItem(hwndList, data, i, -1);
1419 i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
1421 count = data->menu.items[i].count;
1425 count += (int) (ch - '0');
1426 if (count != 0) /* ignore leading zeros */ {
1427 data->menu.counting = TRUE;
1428 data->menu.items[i].count = min(100000, count);
1429 ListView_RedrawItems(hwndList, i,
1430 i); /* update count mark */
1436 is_accelerator = FALSE;
1437 for (i = 0; i < data->menu.size; i++) {
1438 if (data->menu.items[i].accelerator == ch) {
1439 is_accelerator = TRUE;
1444 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
1445 || is_accelerator) {
1446 if (data->how == PICK_ANY || data->how == PICK_ONE) {
1447 for (i = 0; i < data->menu.size; i++) {
1448 if (data->menu.items[i].accelerator == ch) {
1449 if (data->how == PICK_ANY) {
1452 NHMENU_IS_SELECTED(data->menu.items[i]) ? 0
1454 ListView_SetItemState(hwndList, i, LVIS_FOCUSED,
1456 ListView_EnsureVisible(hwndList, i, FALSE);
1458 } else if (data->how == PICK_ONE) {
1459 SelectMenuItem(hwndList, data, i, -1);
1471 reset_menu_count(hwndList, data);
1474 /*-----------------------------------------------------------------------------*/
1476 mswin_menu_window_size(HWND hWnd, LPSIZE sz)
1483 data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
1485 control = GetMenuControl(hWnd);
1487 /* get the control size */
1488 GetClientRect(control, &rt);
1489 sz->cx = rt.right - rt.left;
1490 sz->cy = rt.bottom - rt.top;
1492 /* calculate "extra" space around the control */
1493 GetWindowRect(hWnd, &wrt);
1494 extra_cx = (wrt.right - wrt.left) - sz->cx;
1496 if (data->type == MENU_TYPE_MENU) {
1497 sz->cx = data->menu.menu_cx + GetSystemMetrics(SM_CXVSCROLL);
1499 /* Use the width of the text box */
1500 sz->cx = data->text.text_box_size.cx
1501 + 2 * GetSystemMetrics(SM_CXVSCROLL);
1505 /* uninitilized window */
1506 GetClientRect(hWnd, &rt);
1507 sz->cx = rt.right - rt.left;
1508 sz->cy = rt.bottom - rt.top;
1511 /*-----------------------------------------------------------------------------*/
1513 SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count)
1517 if (item < 0 || item >= data->menu.size)
1520 if (data->how == PICK_ONE && count != 0) {
1521 for (i = 0; i < data->menu.size; i++)
1522 if (item != i && data->menu.items[i].count != 0) {
1523 data->menu.items[i].count = 0;
1524 ListView_RedrawItems(hwndList, i, i);
1528 data->menu.items[item].count = count;
1529 ListView_RedrawItems(hwndList, item, item);
1530 reset_menu_count(hwndList, data);
1532 /*-----------------------------------------------------------------------------*/
1534 reset_menu_count(HWND hwndList, PNHMenuWindow data)
1537 data->menu.counting = FALSE;
1538 if (IsWindow(hwndList)) {
1539 i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED);
1541 ListView_RedrawItems(hwndList, i, i);
1544 /*-----------------------------------------------------------------------------*/
1545 /* List window Proc */
1547 NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1549 BOOL bUpdateFocusItem;
1551 /* we will redraw focused item whenever horizontal scrolling occurs
1552 since "Count: XXX" indicator is garbled by scrolling */
1553 bUpdateFocusItem = FALSE;
1557 if (wParam == VK_LEFT || wParam == VK_RIGHT)
1558 bUpdateFocusItem = TRUE;
1561 case WM_CHAR: /* filter keyboard input for the control */
1562 if (wParam > 0 && wParam < 256
1563 && onListChar(GetParent(hWnd), hWnd, (char) wParam) == -2) {
1572 bUpdateFocusItem = TRUE;
1576 if (GetParent(hWnd) != GetNHApp()->hPopupWnd) {
1577 SetFocus(GetNHApp()->hMainWnd);
1582 /* update focused item */
1583 if (bUpdateFocusItem) {
1587 /* invalidate the focus rectangle */
1588 i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED);
1590 ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS);
1591 InvalidateRect(hWnd, &rt, TRUE);
1595 /* call ListView control window proc */
1596 if (wndProcListViewOrig)
1597 return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam,
1602 /*-----------------------------------------------------------------------------*/
1603 /* Text control window proc - implements scrolling without a cursor */
1605 NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1613 GetClientRect(hWnd, &rc);
1614 FillRect(hDC, &rc, text_bg_brush
1616 : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT));
1621 /* close on space in Windows mode
1622 page down on space in NetHack mode */
1626 si.cbSize = sizeof(SCROLLINFO);
1627 si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
1628 GetScrollInfo(hWnd, SB_VERT, &si);
1629 /* If nethackmode and not at the end of the list */
1630 if (GetNHApp()->regNetHackMode
1631 && (si.nPos + (int) si.nPage) <= (si.nMax - si.nMin))
1632 SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
1634 PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0),
1639 SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
1642 SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0);
1645 SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0);
1648 SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0);
1655 case MENU_FIRST_PAGE:
1656 SendMessage(hWnd, EM_SCROLL, SB_TOP, 0);
1658 case MENU_LAST_PAGE:
1659 SendMessage(hWnd, EM_SCROLL, SB_BOTTOM, 0);
1661 case MENU_NEXT_PAGE:
1662 SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
1664 case MENU_PREVIOUS_PAGE:
1665 SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0);
1670 /* edit control needs to know nothing of its focus */
1676 if (editControlWndProc)
1677 return CallWindowProc(editControlWndProc, hWnd, message, wParam,
1682 /*-----------------------------------------------------------------------------*/