Files
nethack/win/win32/mhmenu.c
2012-01-11 01:53:44 +00:00

1600 lines
44 KiB
C

/* NetHack 3.5 mhmenu.c $Date$ $Revision$ */
/* Copyright (c) Alex Kompel, 2002 */
/* NetHack may be freely redistributed. See license for details. */
#include "winMS.h"
#include <assert.h>
#include "resource.h"
#include "mhmenu.h"
#include "mhmain.h"
#include "mhmsg.h"
#include "mhfont.h"
#include "mhdlg.h"
#define MENU_MARGIN 0
#define NHMENU_STR_SIZE BUFSZ
#define MIN_TABSTOP_SIZE 0
#define NUMTABS 15
#define TAB_SEPARATION 10 /* pixels between each tab stop */
#define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW
#define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT
#define DEFAULT_COLOR_BG_MENU COLOR_WINDOW
#define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT
typedef struct mswin_menu_item {
int glyph;
ANY_P identifier;
CHAR_P accelerator;
CHAR_P group_accel;
int attr;
char str[NHMENU_STR_SIZE];
BOOLEAN_P presel;
int count;
BOOL has_focus;
} NHMenuItem, *PNHMenuItem;
typedef struct mswin_nethack_menu_window {
int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */
int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */
union {
struct menu_list {
int size; /* number of items in items[] */
int allocated; /* number of allocated slots in items[] */
PNHMenuItem items; /* menu items */
char gacc[QBUFSZ]; /* group accelerators */
BOOL counting; /* counting flag */
char prompt[QBUFSZ]; /* menu prompt */
int tab_stop_size[NUMTABS];/* tabstops to align option values */
int menu_cx; /* menu width */
} menu;
struct menu_text {
TCHAR* text;
SIZE text_box_size;
} text;
};
int result;
int done;
HBITMAP bmpChecked;
HBITMAP bmpCheckedCount;
HBITMAP bmpNotChecked;
BOOL is_active;
} NHMenuWindow, *PNHMenuWindow;
extern short glyph2tile[];
static WNDPROC wndProcListViewOrig = NULL;
static WNDPROC editControlWndProc = NULL;
#define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj!=NULL)
#define NHMENU_IS_SELECTED(item) ((item).count!=0)
#define NHMENU_HAS_GLYPH(item) ((item).glyph!=NO_GLYPH)
LRESULT CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM);
static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
static BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
static BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
static void LayoutMenu(HWND hwnd);
static void SetMenuType(HWND hwnd, int type);
static void SetMenuListType(HWND hwnd, int now);
static HWND GetMenuControl(HWND hwnd);
static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count);
static void reset_menu_count(HWND hwndList, PNHMenuWindow data);
static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch);
/*-----------------------------------------------------------------------------*/
HWND mswin_init_menu_window (int type) {
HWND ret;
RECT rt;
/* get window position */
if( GetNHApp()->bAutoLayout ) {
SetRect( &rt, 0, 0, 0, 0);
} else {
mswin_get_window_placement(NHW_MENU, &rt);
}
/* create menu window object */
ret = CreateDialog(
GetNHApp()->hApp,
MAKEINTRESOURCE(IDD_MENU),
GetNHApp()->hMainWnd,
MenuWndProc
);
if( !ret ) {
panic("Cannot create menu window");
}
/* move it in the predefined position */
if( !GetNHApp()->bAutoLayout ) {
MoveWindow(ret, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, TRUE);
}
/* Set window caption */
SetWindowText(ret, "Menu/Text");
if( !GetNHApp()->bWindowsLocked ) {
DWORD style;
style = (DWORD)GetWindowLongPtr(ret, GWL_STYLE);
style |= WS_CAPTION;
SetWindowLongPtr(ret, GWL_STYLE, style);
SetWindowPos(ret, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
SetMenuType(ret, type);
return ret;
}
/*-----------------------------------------------------------------------------*/
int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected, BOOL activate)
{
PNHMenuWindow data;
int ret_val;
MENU_ITEM_P *selected = NULL;
int i;
char* ap;
assert( _selected!=NULL );
*_selected = NULL;
ret_val = -1;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
/* force activate for certain menu types */
if( data->type == MENU_TYPE_MENU &&
(how == PICK_ONE || how == PICK_ANY) ) {
activate = TRUE;
}
data->is_active = activate;
/* set menu type */
SetMenuListType(hWnd, how);
/* Ok, now give items a unique accelerators */
if( data->type == MENU_TYPE_MENU ) {
char next_char = 'a';
data->menu.gacc[0] = '\0';
ap = data->menu.gacc;
for( i=0; i<data->menu.size; i++) {
if( data->menu.items[i].accelerator!=0 ) {
next_char = (char)(data->menu.items[i].accelerator+1);
} else if( NHMENU_IS_SELECTABLE(data->menu.items[i]) ) {
if ( (next_char>='a' && next_char<='z') ||
(next_char>='A' && next_char<='Z') ) {
data->menu.items[i].accelerator = next_char;
} else {
if( next_char > 'z' ) next_char = 'A';
else if ( next_char > 'Z' ) break;
data->menu.items[i].accelerator = next_char;
}
next_char ++;
}
}
/* collect group accelerators */
for( i=0; i<data->menu.size; i++) {
if( data->how != PICK_NONE ) {
if( data->menu.items[i].group_accel &&
!strchr(data->menu.gacc, data->menu.items[i].group_accel) ) {
*ap++ = data->menu.items[i].group_accel;
*ap = '\x0';
}
}
}
reset_menu_count(NULL, data);
}
LayoutMenu(hWnd); // show dialog buttons
if( activate ) {
mswin_popup_display(hWnd, &data->done);
} else {
SetFocus(GetNHApp()->hMainWnd);
mswin_layout_main_window(hWnd);
}
/* get the result */
if( data->result != -1 ) {
if(how==PICK_NONE) {
if(data->result>=0) ret_val=0;
else ret_val=-1;
} else if(how==PICK_ONE || how==PICK_ANY) {
/* count selected items */
ret_val = 0;
for(i=0; i<data->menu.size; i++ ) {
if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
NHMENU_IS_SELECTED(data->menu.items[i]) ) {
ret_val++;
}
}
if( ret_val > 0 ) {
int sel_ind;
selected = (MENU_ITEM_P*)malloc(ret_val*sizeof(MENU_ITEM_P));
if( !selected ) panic("out of memory");
sel_ind = 0;
for(i=0; i<data->menu.size; i++ ) {
if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
NHMENU_IS_SELECTED(data->menu.items[i]) ) {
selected[sel_ind].item = data->menu.items[i].identifier;
selected[sel_ind].count = data->menu.items[i].count;
sel_ind++;
}
}
ret_val = sel_ind;
*_selected = selected;
}
}
}
if( activate ) {
data->is_active = FALSE;
LayoutMenu(hWnd); // hide dialog buttons
mswin_popup_destroy(hWnd);
}
return ret_val;
}
/*-----------------------------------------------------------------------------*/
LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PNHMenuWindow data;
HWND control;
HDC hdc;
TCHAR title[MAX_LOADSTRING];
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (message)
{
case WM_INITDIALOG:
data = (PNHMenuWindow)malloc(sizeof(NHMenuWindow));
ZeroMemory(data, sizeof(NHMenuWindow));
data->type = MENU_TYPE_TEXT;
data->how = PICK_NONE;
data->result = 0;
data->done = 0;
data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL));
data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT));
data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL));
data->is_active = FALSE;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)data);
/* set font for the text cotrol */
control = GetDlgItem(hWnd, IDC_MENU_TEXT);
hdc = GetDC(control);
SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM)0);
ReleaseDC(control, hdc);
/* subclass edit control */
editControlWndProc = (WNDPROC)GetWindowLongPtr(control, GWLP_WNDPROC);
SetWindowLongPtr(control,GWLP_WNDPROC, (LONG)NHMenuTextWndProc);
/* Even though the dialog has no caption, you can still set the title
which shows on Alt-Tab */
LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING);
SetWindowText(hWnd, title);
/* set focus to text control for now */
SetFocus(control);
return FALSE;
case WM_MSNH_COMMAND:
onMSNHCommand(hWnd, wParam, lParam);
break;
case WM_SIZE: {
RECT rt;
LayoutMenu(hWnd);
GetWindowRect(hWnd, &rt);
ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT)&rt);
ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT)&rt)+1);
if( flags.perm_invent && mswin_winid_from_handle(hWnd)==WIN_INVEN )
mswin_update_window_placement(NHW_INVEN, &rt);
else
mswin_update_window_placement(NHW_MENU, &rt);
} return FALSE;
case WM_MOVE: {
RECT rt;
GetWindowRect(hWnd, &rt);
ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT)&rt);
ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT)&rt)+1);
if( flags.perm_invent && mswin_winid_from_handle(hWnd)==WIN_INVEN )
mswin_update_window_placement(NHW_INVEN, &rt);
else
mswin_update_window_placement(NHW_MENU, &rt);
} return FALSE;
case WM_CLOSE:
if (program_state.gameover) {
data->result = -1;
data->done = 1;
program_state.stopprint++;
return TRUE;
} else
return FALSE;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
if( data->type == MENU_TYPE_MENU &&
(data->how==PICK_ONE || data->how==PICK_ANY) &&
data->menu.counting) {
HWND list;
int i;
/* reset counter if counting is in progress */
list = GetMenuControl(hWnd);
i = ListView_GetNextItem(list, -1, LVNI_FOCUSED);
if( i>=0 ) {
SelectMenuItem(list, data, i, 0);
}
return TRUE;
} else {
data->result = -1;
data->done = 1;
}
return TRUE;
case IDOK:
data->done = 1;
data->result = 0;
return TRUE;
case IDC_MENU_TEXT:
switch (HIWORD(wParam))
{
case EN_SETFOCUS:
HideCaret((HWND)lParam);
return TRUE;
}
}
} break;
case WM_NOTIFY:
{
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
switch (LOWORD(wParam)) {
case IDC_MENU_LIST:
{
if( !data || data->type!=MENU_TYPE_MENU ) break;
switch(lpnmhdr->code) {
case LVN_ITEMACTIVATE:
{
LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
if(data->how==PICK_ONE) {
if( lpnmlv->iItem>=0 &&
lpnmlv->iItem<data->menu.size &&
NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) {
SelectMenuItem(
lpnmlv->hdr.hwndFrom,
data,
lpnmlv->iItem,
-1
);
data->done = 1;
data->result = 0;
return TRUE;
}
}
} break;
case NM_CLICK: {
LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam;
if( lpnmitem->iItem==-1 ) return 0;
if( data->how==PICK_ANY ) {
SelectMenuItem(
lpnmitem->hdr.hwndFrom,
data,
lpnmitem->iItem,
NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem])? 0 : -1
);
}
} break;
case LVN_ITEMCHANGED:
{
LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
if( lpnmlv->iItem==-1 ) return 0;
if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0;
if( data->how==PICK_ONE || data->how==PICK_ANY ) {
data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
}
/* update count for single-selection menu (follow the listview selection) */
if( data->how==PICK_ONE ) {
if( lpnmlv->uNewState & LVIS_SELECTED ) {
SelectMenuItem(
lpnmlv->hdr.hwndFrom,
data,
lpnmlv->iItem,
-1
);
}
}
/* check item focus */
if( data->how==PICK_ONE || data->how==PICK_ANY ) {
data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED);
ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem);
}
} break;
case NM_KILLFOCUS:
reset_menu_count(lpnmhdr->hwndFrom, data);
break;
}
} break;
}
} break;
case WM_SETFOCUS:
if( hWnd!=GetNHApp()->hPopupWnd) {
SetFocus(GetNHApp()->hMainWnd);
} else {
if( IsWindow(GetMenuControl(hWnd)) )
SetFocus(GetMenuControl(hWnd));
}
return FALSE;
case WM_MEASUREITEM:
if( wParam==IDC_MENU_LIST )
return onMeasureItem(hWnd, wParam, lParam);
else
return FALSE;
case WM_DRAWITEM:
if( wParam==IDC_MENU_LIST )
return onDrawItem(hWnd, wParam, lParam);
else
return FALSE;
case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */
HDC hdcEdit = (HDC) wParam;
HWND hwndEdit = (HWND) lParam;
if( hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT) ) {
SetBkColor(hdcEdit,
text_bg_brush ? text_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_TEXT)
);
SetTextColor(hdcEdit,
text_fg_brush ? text_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_TEXT)
);
return (BOOL)(text_bg_brush
? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT));
}
} return FALSE;
case WM_DESTROY:
if( data ) {
DeleteObject(data->bmpChecked);
DeleteObject(data->bmpCheckedCount);
DeleteObject(data->bmpNotChecked);
if( data->type == MENU_TYPE_TEXT ) {
if( data->text.text ) free(data->text.text);
}
free(data);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)0);
}
return TRUE;
}
return FALSE;
}
/*-----------------------------------------------------------------------------*/
void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
PNHMenuWindow data;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch( wParam ) {
case MSNH_MSG_PUTSTR:
{
PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
HWND text_view;
TCHAR wbuf[BUFSZ];
size_t text_size;
RECT text_rt;
HGDIOBJ saveFont;
HDC hdc;
if( data->type!=MENU_TYPE_TEXT )
SetMenuType(hWnd, MENU_TYPE_TEXT);
if( !data->text.text ) {
text_size = strlen(msg_data->text) + 4;
data->text.text = (TCHAR*)malloc(text_size*sizeof(data->text.text[0]));
ZeroMemory(data->text.text, text_size*sizeof(data->text.text[0]));
} else {
text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4;
data->text.text = (TCHAR*)realloc(data->text.text, text_size*sizeof(data->text.text[0]));
}
if( !data->text.text ) break;
_tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ));
_tcscat(data->text.text, TEXT("\r\n"));
text_view = GetDlgItem(hWnd, IDC_MENU_TEXT);
if( !text_view ) panic("cannot get text view window");
SetWindowText(text_view, data->text.text);
/* calculate dimensions of the added line of text */
hdc = GetDC(text_view);
saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
SetRect(&text_rt, 0, 0, 0, 0);
DrawText(hdc, msg_data->text, strlen(msg_data->text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE);
data->text.text_box_size.cx = max(text_rt.right - text_rt.left, data->text.text_box_size.cx);
data->text.text_box_size.cy += text_rt.bottom - text_rt.top;
SelectObject(hdc, saveFont);
ReleaseDC(text_view, hdc);
} break;
case MSNH_MSG_STARTMENU:
{
int i;
if( data->type!=MENU_TYPE_MENU )
SetMenuType(hWnd, MENU_TYPE_MENU);
if( data->menu.items ) free(data->menu.items);
data->how = PICK_NONE;
data->menu.items = NULL;
data->menu.size = 0;
data->menu.allocated = 0;
data->done = 0;
data->result = 0;
for (i = 0; i < NUMTABS; ++i)
data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE;
} break;
case MSNH_MSG_ADDMENU:
{
PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu)lParam;
char *p, *p1;
int new_item;
HDC hDC;
int column;
HFONT saveFont;
LONG menuitemwidth = 0;
TEXTMETRIC tm;
if( data->type!=MENU_TYPE_MENU ) break;
if( strlen(msg_data->str)==0 ) break;
if( data->menu.size==data->menu.allocated ) {
data->menu.allocated += 10;
data->menu.items = (PNHMenuItem)realloc(data->menu.items, data->menu.allocated*sizeof(NHMenuItem));
}
new_item = data->menu.size;
ZeroMemory( &data->menu.items[new_item], sizeof(data->menu.items[new_item]));
data->menu.items[new_item].glyph = msg_data->glyph;
data->menu.items[new_item].identifier = *msg_data->identifier;
data->menu.items[new_item].accelerator = msg_data->accelerator;
data->menu.items[new_item].group_accel = msg_data->group_accel;
data->menu.items[new_item].attr = msg_data->attr;
strncpy(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE);
data->menu.items[new_item].presel = msg_data->presel;
/* calculate tabstop size */
hDC = GetDC(hWnd);
saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE));
GetTextMetrics(hDC, &tm);
p1 = data->menu.items[new_item].str;
p = strchr(data->menu.items[new_item].str, '\t');
column = 0;
for (;;) {
TCHAR wbuf[BUFSZ];
RECT drawRect;
SetRect ( &drawRect, 0, 0, 1, 1 );
if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
DrawText(hDC,
NH_A2W(p1, wbuf, BUFSZ),
strlen(p1),
&drawRect,
DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE
);
data->menu.tab_stop_size[column] =
max( data->menu.tab_stop_size[column], drawRect.right - drawRect.left );
menuitemwidth += data->menu.tab_stop_size[column];
if (p != NULL) *p = '\t';
else /* last string so, */ break;
/* add the separation only when not the last item */
/* in the last item, we break out of the loop, in the statement just above */
menuitemwidth += TAB_SEPARATION;
++column;
p1 = p + 1;
p = strchr(p1, '\t');
}
SelectObject(hDC, saveFont);
ReleaseDC(hWnd, hDC);
/* calculate new menu width */
data->menu.menu_cx = max(
data->menu.menu_cx,
2*TILE_X + menuitemwidth + (tm.tmAveCharWidth+tm.tmOverhang)*12
);
/* increment size */
data->menu.size++;
} break;
case MSNH_MSG_ENDMENU:
{
PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu)lParam;
if( msg_data->text ) {
strncpy( data->menu.prompt, msg_data->text, sizeof(data->menu.prompt)-1 );
} else {
ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt));
}
} break;
}
}
/*-----------------------------------------------------------------------------*/
void LayoutMenu(HWND hWnd)
{
PNHMenuWindow data;
HWND menu_ok;
HWND menu_cancel;
RECT clrt, rt;
POINT pt_elem, pt_ok, pt_cancel;
SIZE sz_elem, sz_ok, sz_cancel;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
menu_ok = GetDlgItem(hWnd, IDOK);
menu_cancel = GetDlgItem(hWnd, IDCANCEL);
/* get window coordinates */
GetClientRect(hWnd, &clrt );
// OK button
if( data->is_active ) {
GetWindowRect(menu_ok, &rt);
if( data->type == MENU_TYPE_TEXT ||
(data->type == MENU_TYPE_MENU && data->how == PICK_NONE ) ) {
sz_ok.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN;
} else {
sz_ok.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
}
sz_ok.cy = rt.bottom-rt.top;
pt_ok.x = clrt.left + MENU_MARGIN;
pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy;
ShowWindow(menu_ok, SW_SHOW);
MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
} else {
sz_ok.cx = sz_ok.cy = 0;
pt_ok.x = pt_ok.y = 0;
ShowWindow(menu_ok, SW_HIDE);
}
// CANCEL button
if( data->is_active &&
!( data->type == MENU_TYPE_TEXT ||
(data->type == MENU_TYPE_MENU && data->how == PICK_NONE ) ) ) {
GetWindowRect(menu_ok, &rt);
sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN;
sz_cancel.cy = rt.bottom - rt.top;
pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy;
ShowWindow(menu_cancel, SW_SHOW);
MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE );
} else {
sz_cancel.cx = sz_cancel.cy = 0;
pt_cancel.x = pt_cancel.y = 0;
ShowWindow(menu_cancel, SW_HIDE);
}
// main menu control
pt_elem.x = clrt.left + MENU_MARGIN;
pt_elem.y = clrt.top + MENU_MARGIN;
sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN;
if( data->is_active ) {
sz_elem.cy = (clrt.bottom - clrt.top) - max(sz_ok.cy, sz_cancel.cy) - 3*MENU_MARGIN;
} else {
sz_elem.cy = (clrt.bottom - clrt.top) - 2*MENU_MARGIN;
}
if( data->type == MENU_TYPE_MENU ) {
ListView_SetColumnWidth(
GetMenuControl(hWnd),
0,
max(clrt.right - clrt.left - GetSystemMetrics(SM_CXVSCROLL), data->menu.menu_cx )
);
}
MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
}
/*-----------------------------------------------------------------------------*/
void SetMenuType(HWND hWnd, int type)
{
PNHMenuWindow data;
HWND list, text;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
data->type = type;
text = GetDlgItem(hWnd, IDC_MENU_TEXT);
list = GetDlgItem(hWnd, IDC_MENU_LIST);
if(data->type==MENU_TYPE_TEXT) {
ShowWindow(list, SW_HIDE);
EnableWindow(list, FALSE);
EnableWindow(text, TRUE);
ShowWindow(text, SW_SHOW);
if( data->is_active ) SetFocus(text);
} else {
ShowWindow(text, SW_HIDE);
EnableWindow(text, FALSE);
EnableWindow(list, TRUE);
ShowWindow(list, SW_SHOW);
if( data->is_active ) SetFocus(list);
}
LayoutMenu(hWnd);
}
/*-----------------------------------------------------------------------------*/
void SetMenuListType(HWND hWnd, int how)
{
PNHMenuWindow data;
RECT rt;
DWORD dwStyles;
char buf[BUFSZ];
TCHAR wbuf[BUFSZ];
int nItem;
int i;
HWND control;
LVCOLUMN lvcol;
LRESULT fnt;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if( data->type != MENU_TYPE_MENU ) return;
data->how = how;
switch(how) {
case PICK_NONE:
dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD
| WS_VSCROLL | WS_HSCROLL | LVS_REPORT
| LVS_OWNERDRAWFIXED | LVS_SINGLESEL;
break;
case PICK_ONE:
dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD
| WS_VSCROLL | WS_HSCROLL | LVS_REPORT
| LVS_OWNERDRAWFIXED | LVS_SINGLESEL;
break;
case PICK_ANY:
dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD
| WS_VSCROLL | WS_HSCROLL | LVS_REPORT
| LVS_OWNERDRAWFIXED | LVS_SINGLESEL;
break;
default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY");
};
if( strlen(data->menu.prompt)==0 ) {
dwStyles |= LVS_NOCOLUMNHEADER ;
}
GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt);
DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST));
control = CreateWindow(WC_LISTVIEW, NULL,
dwStyles,
rt.left,
rt.top,
rt.right - rt.left,
rt.bottom - rt.top,
hWnd,
(HMENU)IDC_MENU_LIST,
GetNHApp()->hApp,
NULL );
if( !control ) panic( "cannot create menu control" );
/* install the hook for the control window procedure */
wndProcListViewOrig = (WNDPROC)GetWindowLongPtr(control, GWLP_WNDPROC);
SetWindowLongPtr(control, GWLP_WNDPROC, (LONG)NHMenuListWndProc);
/* set control colors */
ListView_SetBkColor(control,
menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU));
ListView_SetTextBkColor(control,
menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU));
ListView_SetTextColor(control,
menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU));
/* set control font */
fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0);
SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0);
/* add column to the list view */
ZeroMemory(&lvcol, sizeof(lvcol));
lvcol.mask = LVCF_WIDTH | LVCF_TEXT;
lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN);
lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ);
ListView_InsertColumn(control, 0, &lvcol);
/* add items to the list view */
for(i=0; i<data->menu.size; i++ ) {
LVITEM lvitem;
ZeroMemory( &lvitem, sizeof(lvitem) );
sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str );
lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.state = data->menu.items[i].presel? LVIS_SELECTED : 0;
lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ);
lvitem.lParam = (LPARAM)&data->menu.items[i];
nItem = (int)SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf);
if( ListView_InsertItem(control, &lvitem)==-1 ) {
panic("cannot insert menu item");
}
}
if( data->is_active ) SetFocus(control);
}
/*-----------------------------------------------------------------------------*/
HWND GetMenuControl(HWND hWnd)
{
PNHMenuWindow data;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(data->type==MENU_TYPE_TEXT) {
return GetDlgItem(hWnd, IDC_MENU_TEXT);
} else {
return GetDlgItem(hWnd, IDC_MENU_LIST);
}
}
/*-----------------------------------------------------------------------------*/
BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
LPMEASUREITEMSTRUCT lpmis;
TEXTMETRIC tm;
HGDIOBJ saveFont;
HDC hdc;
PNHMenuWindow data;
RECT list_rect;
int i;
lpmis = (LPMEASUREITEMSTRUCT) lParam;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
GetClientRect(GetMenuControl(hWnd), &list_rect);
hdc = GetDC(GetMenuControl(hWnd));
saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE));
GetTextMetrics(hdc, &tm);
/* Set the height of the list box items to max height of the individual items */
for( i=0; i<data->menu.size; i++) {
if( NHMENU_HAS_GLYPH(data->menu.items[i]) && !IS_MAP_ASCII(iflags.wc_map_mode) ) {
lpmis->itemHeight = max( lpmis->itemHeight, (UINT)max(tm.tmHeight, GetNHApp()->mapTile_Y) );
} else {
lpmis->itemHeight = max( lpmis->itemHeight, (UINT)max(tm.tmHeight, TILE_Y) );
}
}
lpmis->itemHeight += 2;
/* set width to the window width */
lpmis->itemWidth = list_rect.right - list_rect.left;
SelectObject(hdc, saveFont);
ReleaseDC(GetMenuControl(hWnd), hdc);
return TRUE;
}
/*-----------------------------------------------------------------------------*/
BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
LPDRAWITEMSTRUCT lpdis;
PNHMenuItem item;
PNHMenuWindow data;
TEXTMETRIC tm;
HGDIOBJ saveFont;
HDC tileDC;
short ntile;
int t_x, t_y;
int x, y;
TCHAR wbuf[BUFSZ];
RECT drawRect;
COLORREF OldBg, OldFg, NewBg;
char *p, *p1;
int column;
int spacing = 0;
lpdis = (LPDRAWITEMSTRUCT) lParam;
/* If there are no list box items, skip this message. */
if (lpdis->itemID == -1) return FALSE;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
item = &data->menu.items[lpdis->itemID];
tileDC = CreateCompatibleDC(lpdis->hDC);
saveFont = SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE));
NewBg = menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU);
OldBg = SetBkColor(lpdis->hDC, NewBg);
OldFg = SetTextColor(lpdis->hDC,
menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU));
GetTextMetrics(lpdis->hDC, &tm);
spacing = tm.tmAveCharWidth;
/* set initial offset */
x = lpdis->rcItem.left + 1;
/* print check mark and letter */
if( NHMENU_IS_SELECTABLE(*item) ) {
char buf[2];
if (data->how != PICK_NONE) {
HGDIOBJ saveBrush;
HBRUSH hbrCheckMark;
switch(item->count) {
case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break;
case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break;
default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break;
}
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2;
SetBrushOrgEx(lpdis->hDC, x, y, NULL);
saveBrush = SelectObject(lpdis->hDC, hbrCheckMark);
PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY);
SelectObject(lpdis->hDC, saveBrush);
DeleteObject(hbrCheckMark);
}
x += TILE_X + spacing;
if(item->accelerator!=0) {
buf[0] = item->accelerator;
buf[1] = '\x0';
SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom );
DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
}
x += tm.tmAveCharWidth + tm.tmOverhang + spacing;
} else {
x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 2*spacing;
}
/* print glyph if present */
if( NHMENU_HAS_GLYPH(*item) ) {
if( !IS_MAP_ASCII(iflags.wc_map_mode) ) {
HGDIOBJ saveBmp;
saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
ntile = glyph2tile[ item->glyph ];
t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X;
t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y;
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - GetNHApp()->mapTile_Y) / 2;
if( GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles ) {
/* using original nethack tiles - apply image transparently */
nhapply_image_transparent(
lpdis->hDC, x, y, TILE_X, TILE_Y,
tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR );
} else {
/* using custom tiles - simple blt */
BitBlt(
lpdis->hDC, x, y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y,
tileDC, t_x, t_y, SRCCOPY );
}
SelectObject(tileDC, saveBmp);
x += GetNHApp()->mapTile_X;
} else {
const char *sel_ind;
switch(item->count) {
case -1: sel_ind = "+"; break;
case 0: sel_ind = "-"; break;
default: sel_ind = "#"; break;
}
SetRect(
&drawRect,
x,
lpdis->rcItem.top,
min(x + tm.tmAveCharWidth, lpdis->rcItem.right),
lpdis->rcItem.bottom
);
DrawText(lpdis->hDC,
NH_A2W(sel_ind, wbuf, BUFSZ),
1,
&drawRect,
DT_CENTER| DT_VCENTER | DT_SINGLELINE
);
x += tm.tmAveCharWidth;
}
} else {
/* no glyph - need to adjust so help window won't look to cramped */
x += TILE_X;
}
x += spacing;
/* draw item text */
p1 = item->str;
p = strchr(item->str, '\t');
column = 0;
SetRect( &drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right),
lpdis->rcItem.bottom );
for (;;) {
TCHAR wbuf[BUFSZ];
if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */
DrawText(lpdis->hDC,
NH_A2W(p1, wbuf, BUFSZ),
strlen(p1),
&drawRect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE
);
if (p != NULL) *p = '\t';
else /* last string so, */ break;
p1 = p + 1;
p = strchr(p1, '\t');
drawRect.left = drawRect.right + TAB_SEPARATION;
++column;
drawRect.right = min (drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right);
}
/* draw focused item */
if( item->has_focus
|| (NHMENU_IS_SELECTABLE(*item) &&
data->menu.items[lpdis->itemID].count!=-1)) {
RECT client_rt;
GetClientRect(lpdis->hwndItem, &client_rt);
client_rt.right = min(client_rt.right, lpdis->rcItem.right);
if( NHMENU_IS_SELECTABLE(*item) &&
data->menu.items[lpdis->itemID].count!=0 &&
item->glyph != NO_GLYPH ) {
if( data->menu.items[lpdis->itemID].count==-1 ) {
_stprintf(wbuf, TEXT("Count: All") );
} else {
_stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count );
}
SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE));
/* calculate text rectangle */
SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom );
DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect,
DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
/* erase text rectangle */
drawRect.left = max(client_rt.left+1, client_rt.right - (drawRect.right - drawRect.left) - 10);
drawRect.right = client_rt.right-1;
drawRect.top = lpdis->rcItem.top;
drawRect.bottom = lpdis->rcItem.bottom;
FillRect(lpdis->hDC, &drawRect,
menu_bg_brush ? menu_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU));
/* draw text */
DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect,
DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
}
}
if (item->has_focus) {
/* draw focus rect */
RECT client_rt;
GetClientRect(lpdis->hwndItem, &client_rt);
SetRect( &drawRect,
client_rt.left,
lpdis->rcItem.top,
client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0),
lpdis->rcItem.bottom );
DrawFocusRect(lpdis->hDC, &drawRect);
}
SetTextColor (lpdis->hDC, OldFg);
SetBkColor (lpdis->hDC, OldBg);
SelectObject(lpdis->hDC, saveFont);
DeleteDC(tileDC);
return TRUE;
}
/*-----------------------------------------------------------------------------*/
BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch)
{
int i = 0;
PNHMenuWindow data;
int curIndex, topIndex, pageSize;
boolean is_accelerator = FALSE;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch( ch ) {
case MENU_FIRST_PAGE:
i = 0;
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
ListView_EnsureVisible(hwndList, i, FALSE);
return -2;
case MENU_LAST_PAGE:
i = max(0, data->menu.size-1);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
ListView_EnsureVisible(hwndList, i, FALSE);
return -2;
case MENU_NEXT_PAGE:
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
/* Focus down one page */
i = min(curIndex+pageSize, data->menu.size-1);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
/* Scrollpos down one page */
i = min(topIndex+(2*pageSize - 1), data->menu.size-1);
ListView_EnsureVisible(hwndList, i, FALSE);
return -2;
case MENU_PREVIOUS_PAGE:
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
/* Focus up one page */
i = max(curIndex-pageSize, 0);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
/* Scrollpos up one page */
i = max(topIndex-pageSize, 0);
ListView_EnsureVisible(hwndList, i, FALSE);
break;
case MENU_SELECT_ALL:
if( data->how == PICK_ANY ) {
reset_menu_count(hwndList, data);
for(i=0; i<data->menu.size; i++ ) {
SelectMenuItem(hwndList, data, i, -1);
}
return -2;
}
break;
case MENU_UNSELECT_ALL:
if( data->how == PICK_ANY ) {
reset_menu_count(hwndList, data);
for(i=0; i<data->menu.size; i++ ) {
SelectMenuItem(hwndList, data, i, 0);
}
return -2;
}
break;
case MENU_INVERT_ALL:
if( data->how == PICK_ANY ) {
reset_menu_count(hwndList, data);
for(i=0; i<data->menu.size; i++ ) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
}
return -2;
}
break;
case MENU_SELECT_PAGE:
if( data->how == PICK_ANY ) {
int from, to;
reset_menu_count(hwndList, data);
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
from = max(0, topIndex);
to = min(data->menu.size, from+pageSize);
for(i=from; i<to; i++ ) {
SelectMenuItem(hwndList, data, i, -1);
}
return -2;
}
break;
case MENU_UNSELECT_PAGE:
if( data->how == PICK_ANY ) {
int from, to;
reset_menu_count(hwndList, data);
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
from = max(0, topIndex);
to = min(data->menu.size, from+pageSize);
for(i=from; i<to; i++ ) {
SelectMenuItem(hwndList, data, i, 0);
}
return -2;
}
break;
case MENU_INVERT_PAGE:
if( data->how == PICK_ANY ) {
int from, to;
reset_menu_count(hwndList, data);
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
from = max(0, topIndex);
to = min(data->menu.size, from+pageSize);
for(i=from; i<to; i++ ) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
}
return -2;
}
break;
case MENU_SEARCH:
if( data->how==PICK_ANY || data->how==PICK_ONE ) {
char buf[BUFSZ];
reset_menu_count(hwndList, data);
if( mswin_getlin_window("Search for:", buf, BUFSZ)==IDCANCEL ) {
strcpy(buf, "\033");
}
if( data->is_active ) SetFocus(hwndList); // set focus back to the list control
if (!*buf || *buf == '\033') return -2;
for(i=0; i<data->menu.size; i++ ) {
if( NHMENU_IS_SELECTABLE(data->menu.items[i])
&& strstr(data->menu.items[i].str, buf) ) {
if (data->how == PICK_ANY) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
} else if( data->how == PICK_ONE ) {
SelectMenuItem(
hwndList,
data,
i,
-1
);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
ListView_EnsureVisible(hwndList, i, FALSE);
break;
}
}
}
} else {
mswin_nhbell();
}
return -2;
case ' ':
{
if (GetNHApp()->regNetHackMode) {
/* NetHack mode: Scroll down one page,
ends menu when on last page. */
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
GetScrollInfo(hwndList, SB_VERT, &si);
if ((si.nPos + (int)si.nPage) > (si.nMax - si.nMin)) {
/* We're at the bottom: dismiss. */
data->done = 1;
data->result = 0;
return -2;
}
/* We're not at the bottom: page down. */
topIndex = ListView_GetTopIndex( hwndList );
pageSize = ListView_GetCountPerPage( hwndList );
curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
/* Focus down one page */
i = min(curIndex+pageSize, data->menu.size-1);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
/* Scrollpos down one page */
i = min(topIndex+(2*pageSize - 1), data->menu.size-1);
ListView_EnsureVisible(hwndList, i, FALSE);
return -2;
} else {
/* Windows mode: ends menu for PICK_ONE/PICK_NONE
select item for PICK_ANY */
if( data->how==PICK_ONE || data->how==PICK_NONE ) {
data->done = 1;
data->result = 0;
return -2;
} else if( data->how==PICK_ANY ) {
i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
if( i>=0 ) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
}
}
}
}
break;
default:
if( strchr(data->menu.gacc, ch) &&
!(ch=='0' && data->menu.counting) ) {
/* matched a group accelerator */
if (data->how == PICK_ANY || data->how == PICK_ONE) {
reset_menu_count(hwndList, data);
for(i=0; i<data->menu.size; i++ ) {
if( NHMENU_IS_SELECTABLE(data->menu.items[i]) &&
data->menu.items[i].group_accel == ch ) {
if( data->how == PICK_ANY ) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
} else if( data->how == PICK_ONE ) {
SelectMenuItem(
hwndList,
data,
i,
-1
);
data->result = 0;
data->done = 1;
return -2;
}
}
}
return -2;
} else {
mswin_nhbell();
return -2;
}
}
if (isdigit(ch)) {
int count;
i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED);
if( i>=0 ) {
count = data->menu.items[i].count;
if( count==-1 ) count=0;
count *= 10L;
count += (int)(ch - '0');
if (count != 0) /* ignore leading zeros */ {
data->menu.counting = TRUE;
data->menu.items[i].count = min(100000, count);
ListView_RedrawItems( hwndList, i, i ); /* update count mark */
}
}
return -2;
}
is_accelerator = FALSE;
for(i=0; i<data->menu.size; i++) {
if( data->menu.items[i].accelerator == ch ) {
is_accelerator = TRUE;
break;
}
}
if( (ch>='a' && ch<='z') ||
(ch>='A' && ch<='Z') || is_accelerator) {
if (data->how == PICK_ANY || data->how == PICK_ONE) {
for(i=0; i<data->menu.size; i++ ) {
if( data->menu.items[i].accelerator == ch ) {
if( data->how == PICK_ANY ) {
SelectMenuItem(
hwndList,
data,
i,
NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1
);
ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED);
ListView_EnsureVisible(hwndList, i, FALSE);
return -2;
} else if( data->how == PICK_ONE ) {
SelectMenuItem(
hwndList,
data,
i,
-1
);
data->result = 0;
data->done = 1;
return -2;
}
}
}
}
}
break;
}
reset_menu_count(hwndList, data);
return -1;
}
/*-----------------------------------------------------------------------------*/
void mswin_menu_window_size (HWND hWnd, LPSIZE sz)
{
HWND control;
PNHMenuWindow data;
RECT rt, wrt;
int extra_cx;
data = (PNHMenuWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(data) {
control = GetMenuControl(hWnd);
/* get the control size */
GetClientRect(control, &rt);
sz->cx = rt.right - rt.left;
sz->cy = rt.bottom - rt.top;
/* calculate "extra" space around the control */
GetWindowRect(hWnd, &wrt);
extra_cx = (wrt.right-wrt.left) - sz->cx;
if( data->type==MENU_TYPE_MENU ) {
sz->cx = max(sz->cx, data->menu.menu_cx + GetSystemMetrics(SM_CXVSCROLL) );
} else {
/* Use the width of the text box */
sz->cx = max( sz->cx, data->text.text_box_size.cx + 2*GetSystemMetrics(SM_CXVSCROLL));
}
sz->cx += extra_cx;
} else {
/* uninitilized window */
GetClientRect(hWnd, &rt);
sz->cx = rt.right - rt.left;
sz->cy = rt.bottom - rt.top;
}
}
/*-----------------------------------------------------------------------------*/
void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count)
{
int i;
if( item<0 || item>=data->menu.size ) return;
if( data->how==PICK_ONE && count!=0 ) {
for(i=0; i<data->menu.size; i++)
if( item!=i && data->menu.items[i].count!=0 ) {
data->menu.items[i].count = 0;
ListView_RedrawItems( hwndList, i, i );
};
}
data->menu.items[item].count = count;
ListView_RedrawItems( hwndList, item, item );
reset_menu_count(hwndList, data);
}
/*-----------------------------------------------------------------------------*/
void reset_menu_count(HWND hwndList, PNHMenuWindow data)
{
int i;
data->menu.counting = FALSE;
if( IsWindow(hwndList) ) {
i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED);
if( i>=0 ) ListView_RedrawItems( hwndList, i, i );
}
}
/*-----------------------------------------------------------------------------*/
/* List window Proc */
LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL bUpdateFocusItem;
/* we will redraw focused item whenever horizontal scrolling occurs
since "Count: XXX" indicator is garbled by scrolling */
bUpdateFocusItem = FALSE;
switch(message) {
case WM_KEYDOWN:
if( wParam==VK_LEFT || wParam==VK_RIGHT )
bUpdateFocusItem = TRUE;
break;
case WM_CHAR: /* filter keyboard input for the control */
if( wParam>0 && wParam<256 && onListChar(GetParent(hWnd), hWnd, (char)wParam)==-2 ) {
return 0;
} else {
return 1;
}
break;
case WM_SIZE:
case WM_HSCROLL:
bUpdateFocusItem = TRUE;
break;
case WM_SETFOCUS:
if( GetParent(hWnd)!=GetNHApp()->hPopupWnd) {
SetFocus(GetNHApp()->hMainWnd);
}
return FALSE;
}
/* update focused item */
if( bUpdateFocusItem ) {
int i;
RECT rt;
/* invalidate the focus rectangle */
i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED);
if( i!=-1 ) {
ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS);
InvalidateRect(hWnd, &rt, TRUE);
}
}
/* call ListView control window proc */
if( wndProcListViewOrig )
return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam);
else
return 0;
}
/*-----------------------------------------------------------------------------*/
/* Text control window proc - implements scrolling without a cursor */
LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_KEYDOWN:
switch (wParam)
{
/* close on space in Windows mode
page down on space in NetHack mode */
case VK_SPACE:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
GetScrollInfo(hWnd, SB_VERT, &si);
/* If nethackmode and not at the end of the list */
if (GetNHApp()->regNetHackMode &&
(si.nPos + (int)si.nPage) <= (si.nMax - si.nMin))
SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
else
PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
return 0;
}
case VK_NEXT:
SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0);
return 0;
case VK_PRIOR:
SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0);
return 0;
case VK_UP:
SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0);
return 0;
case VK_DOWN:
SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0);
return 0;
}
break;
}
if( editControlWndProc )
return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
else
return 0;
}
/*-----------------------------------------------------------------------------*/