The following files are gone (sys\wince):
- stat.h (moved to ceinc\sys\stat.h)
- fcntl.h (moved to ceinc\fcntl.h)
- errno.h (moved to ceinc\errno.h)
- assert.h (moved to ceinc\assert.h)
The following files were added:
- mhtxtbuf.c
- mhtxtbuf.h
- menubar.uu
- ceinc
- ceinc\sys
- ceinc\fcntl.h
- ceinc\errno.h
- ceinc\assert.h
- ceinc\sys\stat.h
CE notes:
Fixes:
- added new options "wraptext", "fullscreen" and "softkeyboard"
- CE341-1 fix ("wraptext" option)
- hide map scrollbars on Smartphone
- added View->Options menu
- PocketPC: added "Fit to screen" and "Show/Hide keypad" icons
on the menu bar
- Smartphone: '<', '>' keys were mapped incorrectly
- build: use source files directly from <buildroot>\sys\wince instead of
copying them to <buildroot>\wince\
1569 lines
40 KiB
C
1569 lines
40 KiB
C
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "winMS.h"
|
|
#include <assert.h>
|
|
#include "mhmenu.h"
|
|
#include "mhmain.h"
|
|
#include "mhmsg.h"
|
|
#include "mhcmd.h"
|
|
#include "mhinput.h"
|
|
#include "mhfont.h"
|
|
#include "mhcolor.h"
|
|
#include "mhtxtbuf.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 */
|
|
|
|
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;
|
|
BOOL has_tab;
|
|
} 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 */
|
|
} menu;
|
|
|
|
struct menu_text {
|
|
PNHTextBuffer text;
|
|
} text;
|
|
};
|
|
int result;
|
|
int done;
|
|
|
|
HBITMAP bmpChecked;
|
|
HBITMAP bmpCheckedCount;
|
|
HBITMAP bmpNotChecked;
|
|
} 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)
|
|
|
|
LRESULT CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
static void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
static LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
static LRESULT 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 LRESULT onListChar(HWND hWnd, HWND hwndList, WORD ch);
|
|
static char* parse_menu_str(char* dest, const char* src, size_t size);
|
|
|
|
HWND mswin_init_menu_window (int type) {
|
|
HWND ret;
|
|
|
|
ret = CreateDialog(
|
|
GetNHApp()->hApp,
|
|
MAKEINTRESOURCE(IDD_MENU),
|
|
GetNHApp()->hMainWnd,
|
|
MenuWndProc
|
|
);
|
|
if( !ret ) {
|
|
panic("Cannot create menu window");
|
|
}
|
|
|
|
SetMenuType(ret, type);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected)
|
|
{
|
|
PNHMenuWindow data;
|
|
int ret_val;
|
|
MENU_ITEM_P *selected = NULL;
|
|
int i;
|
|
char* ap;
|
|
char accell_str[256];
|
|
|
|
assert( _selected!=NULL );
|
|
*_selected = NULL;
|
|
ret_val = -1;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
|
|
/* set menu type */
|
|
SetMenuListType(hWnd, how);
|
|
|
|
/* Ok, now give items a unique accelerators */
|
|
ZeroMemory(accell_str, sizeof(accell_str));
|
|
ap = accell_str;
|
|
|
|
#if defined(WIN_CE_SMARTPHONE)
|
|
if( data->menu.size>10 ) {
|
|
*ap++ = MENU_FIRST_PAGE;
|
|
*ap++ = MENU_LAST_PAGE;
|
|
*ap++ = MENU_NEXT_PAGE;
|
|
*ap++ = MENU_PREVIOUS_PAGE;
|
|
if( data->how == PICK_ANY ) {
|
|
*ap++ = MENU_SELECT_ALL;
|
|
*ap++ = MENU_UNSELECT_ALL;
|
|
*ap++ = MENU_INVERT_ALL;
|
|
*ap++ = MENU_SELECT_PAGE;
|
|
*ap++ = MENU_UNSELECT_PAGE;
|
|
*ap++ = MENU_INVERT_PAGE;
|
|
}
|
|
*ap++ = MENU_SEARCH;
|
|
}
|
|
#endif
|
|
|
|
if( data->type == MENU_TYPE_MENU ) {
|
|
char next_char = 'a';
|
|
|
|
for( i=0; i<data->menu.size; i++) {
|
|
if( data->menu.items[i].accelerator!=0 ) {
|
|
*ap++ = data->menu.items[i].accelerator;
|
|
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;
|
|
*ap++ = data->menu.items[i].accelerator;
|
|
} else {
|
|
if( next_char > 'z' ) next_char = 'A';
|
|
else if ( next_char > 'Z' ) break;
|
|
|
|
data->menu.items[i].accelerator = next_char;
|
|
*ap++ = data->menu.items[i].accelerator;
|
|
}
|
|
|
|
next_char ++;
|
|
}
|
|
}
|
|
|
|
/* collect group accelerators */
|
|
data->menu.gacc[0] = '\0';
|
|
ap = data->menu.gacc;
|
|
if( data->how != PICK_NONE ) {
|
|
for( i=0; i<data->menu.size; i++) {
|
|
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);
|
|
}
|
|
|
|
#if defined(WIN_CE_SMARTPHONE)
|
|
if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadFromString( accell_str );
|
|
#endif
|
|
|
|
mswin_popup_display(hWnd, &data->done);
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
mswin_popup_destroy(hWnd);
|
|
|
|
#if defined(WIN_CE_SMARTPHONE)
|
|
if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadDefault();
|
|
#endif
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMenuWindow data;
|
|
|
|
CheckInputDialog(hWnd, message, wParam, lParam);
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG: {
|
|
HWND text_control;
|
|
HDC hDC;
|
|
|
|
text_control = GetDlgItem(hWnd, IDC_MENU_TEXT);
|
|
|
|
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));
|
|
SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
|
|
|
|
/* subclass edit control */
|
|
editControlWndProc = (WNDPROC)GetWindowLong(text_control, GWL_WNDPROC);
|
|
SetWindowLong(text_control, GWL_WNDPROC, (LONG)NHMenuTextWndProc);
|
|
|
|
/* set text window font */
|
|
hDC = GetDC(text_control);
|
|
SendMessage(
|
|
text_control,
|
|
WM_SETFONT,
|
|
(WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hDC, FALSE),
|
|
(LPARAM)0
|
|
);
|
|
ReleaseDC(text_control, hDC);
|
|
|
|
#if defined(WIN_CE_SMARTPHONE)
|
|
/* special initialization for SmartPhone dialogs */
|
|
NHSPhoneDialogSetup(hWnd, FALSE, GetNHApp()->bFullScreen);
|
|
#endif
|
|
} break;
|
|
|
|
case WM_MSNH_COMMAND:
|
|
onMSNHCommand(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
LayoutMenu(hWnd);
|
|
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 FALSE;
|
|
} else {
|
|
data->result = -1;
|
|
data->done = 1;
|
|
}
|
|
return FALSE;
|
|
|
|
case IDOK:
|
|
data->done = 1;
|
|
data->result = 0;
|
|
return FALSE;
|
|
}
|
|
} 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;
|
|
}
|
|
} else if( data->how==PICK_ANY ) {
|
|
if( lpnmlv->iItem>=0 &&
|
|
lpnmlv->iItem<data->menu.size &&
|
|
NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) {
|
|
SelectMenuItem(
|
|
lpnmlv->hdr.hwndFrom,
|
|
data,
|
|
lpnmlv->iItem,
|
|
NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1
|
|
);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case NM_CLICK: {
|
|
LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam;
|
|
if( lpnmlv->iItem==-1 ) return 0;
|
|
if( data->how==PICK_ANY ) {
|
|
SelectMenuItem(
|
|
lpnmlv->hdr.hwndFrom,
|
|
data,
|
|
lpnmlv->iItem,
|
|
NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1
|
|
);
|
|
}
|
|
} break;
|
|
|
|
case LVN_ITEMCHANGED:
|
|
{
|
|
LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
|
|
if( lpnmlv->iItem==-1 ) return 0;
|
|
if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0;
|
|
|
|
/* update item that has the focus */
|
|
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 */
|
|
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()->hPopupWnd );
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
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_CTLCOLORBTN:
|
|
case WM_CTLCOLOREDIT:
|
|
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, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG));
|
|
SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG));
|
|
return (BOOL)mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG);
|
|
}
|
|
} 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 ) {
|
|
mswin_free_text_buffer(data->text.text);
|
|
data->text.text = NULL;
|
|
}
|
|
}
|
|
free(data);
|
|
SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#if defined(WIN_CE_POCKETPC)
|
|
PNHMenuWindow data;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
|
|
if( !( data &&
|
|
data->type==MENU_TYPE_MENU &&
|
|
(data->how==PICK_ONE || data->how==PICK_ANY) ) ) return;
|
|
|
|
switch(message) {
|
|
case WM_SETFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
|
|
return;
|
|
|
|
case WM_DESTROY:
|
|
case WM_KILLFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
|
|
return;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
|
|
switch(lpnmhdr->code) {
|
|
case NM_SETFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
|
|
break;
|
|
case NM_KILLFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
|
|
break;
|
|
}
|
|
} return;
|
|
|
|
case WM_COMMAND:
|
|
switch(HIWORD(wParam)) {
|
|
case BN_SETFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP);
|
|
break;
|
|
case BN_KILLFOCUS:
|
|
if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN);
|
|
break;
|
|
}
|
|
return;
|
|
|
|
} /* end switch */
|
|
#endif
|
|
}
|
|
|
|
void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMenuWindow data;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
switch( wParam ) {
|
|
case MSNH_MSG_PUTSTR:
|
|
{
|
|
PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam;
|
|
HWND text_view;
|
|
|
|
if( data->type!=MENU_TYPE_TEXT )
|
|
SetMenuType(hWnd, MENU_TYPE_TEXT);
|
|
|
|
if( !data->text.text ) {
|
|
data->text.text = mswin_init_text_buffer(
|
|
program_state.gameover? FALSE : GetNHApp()->bWrapText
|
|
);
|
|
if( !data->text.text ) break;
|
|
}
|
|
|
|
mswin_add_text(data->text.text, msg_data->attr, msg_data->text);
|
|
|
|
text_view = GetDlgItem(hWnd, IDC_MENU_TEXT);
|
|
if( !text_view ) panic("cannot get text view window");
|
|
mswin_render_text(data->text.text, text_view);
|
|
} 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;
|
|
|
|
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;
|
|
parse_menu_str(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE);
|
|
data->menu.items[new_item].presel = msg_data->presel;
|
|
|
|
/* calculate tabstop size */
|
|
p = strchr(data->menu.items[new_item].str, '\t');
|
|
if( p ) {
|
|
data->menu.items[new_item].has_tab = TRUE;
|
|
hDC = GetDC(hWnd);
|
|
saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE));
|
|
p1 = data->menu.items[new_item].str;
|
|
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 );
|
|
if (p != NULL) *p = '\t';
|
|
else /* last string so, */ break;
|
|
|
|
++column;
|
|
p1 = p + 1;
|
|
p = strchr(p1, '\t');
|
|
}
|
|
SelectObject(hDC, saveFont);
|
|
ReleaseDC(hWnd, hDC);
|
|
} else {
|
|
data->menu.items[new_item].has_tab = FALSE;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
} /* end switch */
|
|
}
|
|
|
|
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)GetWindowLong(hWnd, GWL_USERDATA);
|
|
menu_ok = GetDlgItem(hWnd, IDOK);
|
|
menu_cancel = GetDlgItem(hWnd, IDCANCEL);
|
|
|
|
/* get window coordinates */
|
|
GetClientRect(hWnd, &clrt );
|
|
|
|
/* set window placements */
|
|
if( IsWindow(menu_ok) ) {
|
|
GetWindowRect(menu_ok, &rt);
|
|
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;
|
|
MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE );
|
|
} else {
|
|
pt_ok.x = 0;
|
|
pt_ok.y = clrt.bottom;
|
|
sz_ok.cx = sz_ok.cy = 0;
|
|
}
|
|
|
|
if( IsWindow(menu_cancel) ) {
|
|
GetWindowRect(menu_cancel, &rt);
|
|
sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN;
|
|
sz_cancel.cy = rt.bottom-rt.top;
|
|
pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN;
|
|
pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy;
|
|
MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE );
|
|
} else {
|
|
pt_cancel.x = 0;
|
|
pt_cancel.y = clrt.bottom;
|
|
sz_cancel.cx = sz_cancel.cy = 0;
|
|
}
|
|
|
|
pt_elem.x = clrt.left + MENU_MARGIN;
|
|
pt_elem.y = clrt.top + MENU_MARGIN;
|
|
sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN;
|
|
sz_elem.cy = min(pt_cancel.y, pt_ok.y) - MENU_MARGIN - pt_elem.y;
|
|
MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE );
|
|
|
|
/* reformat text for the text menu */
|
|
if( data &&
|
|
data->type==MENU_TYPE_TEXT &&
|
|
data->text.text )
|
|
mswin_render_text(data->text.text, GetMenuControl(hWnd));
|
|
}
|
|
|
|
void SetMenuType(HWND hWnd, int type)
|
|
{
|
|
PNHMenuWindow data;
|
|
HWND list, text;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_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);
|
|
SetFocus(text);
|
|
} else {
|
|
ShowWindow(text, SW_HIDE);
|
|
EnableWindow(text, FALSE);
|
|
EnableWindow(list, TRUE);
|
|
ShowWindow(list, SW_SHOW);
|
|
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;
|
|
SIZE wnd_size;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_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)GetWindowLong(control, GWL_WNDPROC);
|
|
SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuListWndProc);
|
|
|
|
/* set control font */
|
|
fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0);
|
|
SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0);
|
|
|
|
/* set control colors */
|
|
ListView_SetBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG));
|
|
ListView_SetTextBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG));
|
|
ListView_SetTextColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG));
|
|
|
|
/* add column to the list view */
|
|
mswin_menu_window_size(hWnd, &wnd_size);
|
|
|
|
ZeroMemory(&lvcol, sizeof(lvcol));
|
|
lvcol.mask = LVCF_WIDTH | LVCF_TEXT;
|
|
lvcol.cx = max( wnd_size.cx, GetSystemMetrics(SM_CXSCREEN));
|
|
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 = SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf);
|
|
if( ListView_InsertItem(control, &lvitem)==-1 ) {
|
|
panic("cannot insert menu item");
|
|
}
|
|
}
|
|
SetFocus(control);
|
|
}
|
|
|
|
|
|
HWND GetMenuControl(HWND hWnd)
|
|
{
|
|
PNHMenuWindow data;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
|
|
if(data->type==MENU_TYPE_TEXT) {
|
|
return GetDlgItem(hWnd, IDC_MENU_TEXT);
|
|
} else {
|
|
return GetDlgItem(hWnd, IDC_MENU_LIST);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPMEASUREITEMSTRUCT lpmis;
|
|
TEXTMETRIC tm;
|
|
HGDIOBJ saveFont;
|
|
HDC hdc;
|
|
PNHMenuWindow data;
|
|
RECT list_rect;
|
|
|
|
lpmis = (LPMEASUREITEMSTRUCT) lParam;
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_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. */
|
|
lpmis->itemHeight = max(tm.tmHeight, TILE_Y)+2;
|
|
lpmis->itemWidth = list_rect.right - list_rect.left;
|
|
|
|
SelectObject(hdc, saveFont);
|
|
ReleaseDC(GetMenuControl(hWnd), hdc);
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT 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;
|
|
|
|
lpdis = (LPDRAWITEMSTRUCT) lParam;
|
|
|
|
/* If there are no list box items, skip this message. */
|
|
if (lpdis->itemID == -1) return FALSE;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_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 = mswin_get_color(NHW_MENU, MSWIN_COLOR_BG);
|
|
OldBg = SetBkColor(lpdis->hDC, NewBg);
|
|
OldFg = SetTextColor(lpdis->hDC, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG));
|
|
|
|
GetTextMetrics(lpdis->hDC, &tm);
|
|
|
|
x = lpdis->rcItem.left + 1;
|
|
|
|
/* print check mark if it is a "selectable" menu */
|
|
if( data->how!=PICK_NONE ) {
|
|
if( NHMENU_IS_SELECTABLE(*item) ) {
|
|
HGDIOBJ saveBrush;
|
|
HBRUSH hbrCheckMark;
|
|
char buf[2];
|
|
|
|
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 + 5;
|
|
|
|
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 + 5;
|
|
} else {
|
|
x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10;
|
|
}
|
|
}
|
|
|
|
/* print glyph if present */
|
|
if( item->glyph != NO_GLYPH ) {
|
|
HGDIOBJ saveBmp;
|
|
|
|
saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles);
|
|
ntile = glyph2tile[ item->glyph ];
|
|
t_x = (ntile % TILES_PER_LINE)*TILE_X;
|
|
t_y = (ntile / TILES_PER_LINE)*TILE_Y;
|
|
|
|
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2;
|
|
|
|
nhapply_image_transparent(
|
|
lpdis->hDC, x, y, TILE_X, TILE_Y,
|
|
tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR );
|
|
SelectObject(tileDC, saveBmp);
|
|
}
|
|
|
|
x += TILE_X + 5;
|
|
|
|
/* draw item text */
|
|
if( item->has_tab ) {
|
|
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);
|
|
}
|
|
} else {
|
|
TCHAR wbuf[BUFSZ];
|
|
SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom);
|
|
DrawText(lpdis->hDC,
|
|
NH_A2W(item->str, wbuf, BUFSZ),
|
|
strlen(item->str),
|
|
&drawRect,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE
|
|
);
|
|
}
|
|
|
|
/* draw focused item */
|
|
if( item->has_focus ) {
|
|
RECT client_rt;
|
|
HBRUSH bkBrush;
|
|
|
|
GetClientRect(lpdis->hwndItem, &client_rt);
|
|
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;
|
|
bkBrush = CreateSolidBrush( GetBkColor(lpdis->hDC) );
|
|
FillRect(lpdis->hDC, &drawRect, bkBrush );
|
|
DeleteObject( bkBrush );
|
|
|
|
/* draw text */
|
|
DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect,
|
|
DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX );
|
|
}
|
|
|
|
/* draw focus rect */
|
|
SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, 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)GetWindowLong(hWnd, GWL_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];
|
|
int selected_item;
|
|
|
|
reset_menu_count(hwndList, data);
|
|
mswin_getlin("Search for:", buf);
|
|
if (!*buf || *buf == '\033') return -2;
|
|
selected_item = -1;
|
|
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
|
|
);
|
|
/* save the first item - we will move focus to it */
|
|
if( selected_item == -1 ) selected_item = i;
|
|
} else if( data->how == PICK_ONE ) {
|
|
SelectMenuItem(
|
|
hwndList,
|
|
data,
|
|
i,
|
|
-1
|
|
);
|
|
selected_item = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( selected_item>0 ) {
|
|
ListView_SetItemState(hwndList, selected_item, LVIS_FOCUSED, LVIS_FOCUSED);
|
|
ListView_EnsureVisible(hwndList, selected_item, FALSE);
|
|
}
|
|
} else {
|
|
mswin_nhbell();
|
|
}
|
|
return -2;
|
|
|
|
case ' ':
|
|
/* 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
|
|
);
|
|
}
|
|
return -2;
|
|
}
|
|
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)
|
|
{
|
|
TEXTMETRIC tm;
|
|
HWND control;
|
|
HGDIOBJ saveFont;
|
|
HDC hdc;
|
|
PNHMenuWindow data;
|
|
int i;
|
|
RECT rt, wrt;
|
|
int extra_cx;
|
|
|
|
GetClientRect(hWnd, &rt);
|
|
sz->cx = rt.right - rt.left;
|
|
sz->cy = rt.bottom - rt.top;
|
|
|
|
GetWindowRect(hWnd, &wrt);
|
|
extra_cx = (wrt.right-wrt.left) - sz->cx;
|
|
|
|
data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA);
|
|
if(data) {
|
|
control = GetMenuControl(hWnd);
|
|
hdc = GetDC(control);
|
|
|
|
if( data->type==MENU_TYPE_MENU ) {
|
|
/* Calculate the width of the list box. */
|
|
saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE));
|
|
GetTextMetrics(hdc, &tm);
|
|
for(i=0; i<data->menu.size; i++ ) {
|
|
LONG menuitemwidth = 0;
|
|
int column;
|
|
char *p, *p1;
|
|
|
|
p1 = data->menu.items[i].str;
|
|
p = strchr(data->menu.items[i].str, '\t');
|
|
column = 0;
|
|
for (;;) {
|
|
TCHAR wbuf[BUFSZ];
|
|
RECT tabRect;
|
|
SetRect ( &tabRect, 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),
|
|
&tabRect,
|
|
DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE
|
|
);
|
|
/* it probably isn't necessary to recompute the tab width now, but do so
|
|
* just in case, honoring the previously computed value
|
|
*/
|
|
menuitemwidth += max(data->menu.tab_stop_size[column],
|
|
tabRect.right - tabRect.left);
|
|
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');
|
|
}
|
|
|
|
sz->cx = max(sz->cx,
|
|
(LONG)(2*TILE_X + menuitemwidth + tm.tmAveCharWidth*12 + tm.tmOverhang));
|
|
}
|
|
SelectObject(hdc, saveFont);
|
|
} else {
|
|
/* do not change size for text output - the text will be formatted to
|
|
fit any window */
|
|
}
|
|
sz->cx += extra_cx;
|
|
|
|
ReleaseDC(control, hdc);
|
|
}
|
|
}
|
|
|
|
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 = FALSE;
|
|
|
|
switch(message) {
|
|
|
|
/* filter keyboard input for the control */
|
|
#if !defined(WIN_CE_SMARTPHONE)
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP: {
|
|
MSG msg;
|
|
|
|
if( PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) ) {
|
|
if( onListChar(GetParent(hWnd), hWnd, (char)msg.wParam)==-2 ) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if( wParam==VK_LEFT || wParam==VK_RIGHT )
|
|
bUpdateFocusItem = TRUE;
|
|
} break;
|
|
|
|
#else /* defined(WIN_CE_SMARTPHONE) */
|
|
case WM_KEYDOWN:
|
|
if( wParam==VK_TACTION ) {
|
|
if( onListChar(GetParent(hWnd), hWnd, ' ')==-2 ) {
|
|
return 0;
|
|
}
|
|
} else if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) {
|
|
PMSNHEvent evt;
|
|
BOOL processed = FALSE;
|
|
if( mswin_have_input() ) {
|
|
evt = mswin_input_pop();
|
|
if( evt->type==NHEVENT_CHAR &&
|
|
onListChar(GetParent(hWnd), hWnd, evt->kbd.ch)==-2 ) {
|
|
processed = TRUE;
|
|
}
|
|
|
|
/* eat the rest of the events */
|
|
if( mswin_have_input() ) mswin_input_pop();
|
|
}
|
|
if( processed ) return 0;
|
|
}
|
|
|
|
if( wParam==VK_LEFT || wParam==VK_RIGHT )
|
|
bUpdateFocusItem = TRUE;
|
|
break;
|
|
|
|
case WM_KEYUP:
|
|
/* translate SmartPhone keyboard message */
|
|
if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) )
|
|
return 0;
|
|
break;
|
|
|
|
/* tell Windows not to process default button on VK_RETURN */
|
|
case WM_GETDLGCODE:
|
|
return DLGC_DEFPUSHBUTTON | DLGC_WANTALLKEYS |
|
|
(wndProcListViewOrig?
|
|
CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam)
|
|
: 0 );
|
|
#endif
|
|
|
|
case WM_SIZE:
|
|
case WM_HSCROLL:
|
|
bUpdateFocusItem = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
if( wndProcListViewOrig )
|
|
return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Text control window proc - implements close on space */
|
|
LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(message) {
|
|
case WM_KEYUP:
|
|
switch( wParam ) {
|
|
case VK_SPACE:
|
|
case VK_RETURN:
|
|
/* close on space */
|
|
PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0);
|
|
return 0;
|
|
|
|
case VK_UP:
|
|
/* scoll up */
|
|
PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
|
|
return 0;
|
|
|
|
case VK_DOWN:
|
|
/* scoll down */
|
|
PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
|
|
return 0;
|
|
|
|
case VK_LEFT:
|
|
/* scoll left */
|
|
PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)NULL);
|
|
return 0;
|
|
|
|
case VK_RIGHT:
|
|
/* scoll right */
|
|
PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)NULL);
|
|
return 0;
|
|
}
|
|
break; /* case WM_KEYUP: */
|
|
}
|
|
|
|
if( editControlWndProc )
|
|
return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam);
|
|
else
|
|
return 0;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
char* parse_menu_str(char* dest, const char* src, size_t size)
|
|
{
|
|
char *p1, *p2;
|
|
if( !dest || size==0 ) return NULL;
|
|
|
|
strncpy(dest, src, size);
|
|
dest[size-1] = '\x0';
|
|
|
|
/* replace "[ ]*\[" with "\t\[" */
|
|
p1 = p2 = strstr(dest, " [");
|
|
if( p1 ) {
|
|
while( p1!=dest && *p1==' ') p1--;
|
|
p1++; /* backup to space */
|
|
*p2 = '\t';
|
|
memmove(p1, p2, strlen(p2));
|
|
p1[strlen(p2)] = '\x0';
|
|
}
|
|
return dest;
|
|
}
|