diff options
Diffstat (limited to 'app/wlib/mswlib/mswmenu.c')
-rw-r--r-- | app/wlib/mswlib/mswmenu.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/app/wlib/mswlib/mswmenu.c b/app/wlib/mswlib/mswmenu.c new file mode 100644 index 0000000..15053a2 --- /dev/null +++ b/app/wlib/mswlib/mswmenu.c @@ -0,0 +1,1062 @@ +#define OEMRESOURCE + +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <ctype.h> +#include <assert.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Menus + * + ***************************************************************************** + */ + +typedef enum { M_MENU, M_SEPARATOR, M_PUSH, M_LIST, M_LISTITEM, M_TOGGLE, M_RADIO } mtype_e; +typedef enum { MM_BUTT, MM_MENU, MM_BAR, MM_POPUP } mmtype_e; + +typedef struct wMenuItem_t * wMenuItem_p; + +struct radioButtonGroup { + int firstButton; /* id of first button in group */ + int lastButton; /* id of last button in group */ +}; + +/* NOTE: first field must be the same as WOBJ_COMMON */ +#define MOBJ_COMMON \ + WOBJ_COMMON \ + int index; \ + mtype_e mtype; \ + wMenu_p parentMenu; \ + wMenuItem_p mnext; + +struct wMenuItem_t { + MOBJ_COMMON + }; + +struct wMenu_t { + MOBJ_COMMON + mmtype_e mmtype; + wMenuItem_p first, last; + struct radioButtonGroup *radioGroup; + HMENU menu; + wButton_p button; + wMenuTraceCallBack_p traceFunc; + void * traceData; + }; + +struct wMenuPush_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +struct wMenuRadio_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; +struct wMenuToggle_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuToggleCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +typedef struct wMenuListItem_t * wMenuListItem_p; +struct wMenuList_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenu_p mlparent; + int max; + int count; + wMenuListCallBack_p action; + }; + +struct wMenuListItem_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenuListCallBack_p action; + }; + +#define UNCHECK (0) +#define CHECK (1) +#define RADIOCHECK (2) +#define RADIOUNCHECK (3) + +static HBITMAP checked; +static HBITMAP unchecked; +static HBITMAP checkedRadio; +static HBITMAP uncheckedRadio; + + +/* + ***************************************************************************** + * + * Internal Functions + * + ***************************************************************************** + */ + +char * mswStrdup( const char * str ) +{ + char * ret; + if (str) { + ret = (char*)malloc( strlen(str)+1 ); + strcpy( ret, str ); + } else + ret = NULL; + return ret; +} + +static LRESULT menuPush( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wMenuItem_p m = (wMenuItem_p)b; + wBool_t set; + + mswAllowBalloonHelp = TRUE; + + switch( message ) { + + case WM_COMMAND: + + switch (m->mtype) { + default: + mswFail( "pushMenu" ); + break; + case M_PUSH: + if (((wMenuPush_p)m)->action) + ((wMenuPush_p)m)->action(((wMenuPush_p)m)->data); + break; + case M_TOGGLE: + set = wMenuToggleGet((wMenuToggle_p)m); + set = !set; + wMenuToggleSet((wMenuToggle_p)m,set); + if (((wMenuToggle_p)m)->action) + ((wMenuToggle_p)m)->action(set, ((wMenuPush_p)m)->data); + break; + case M_LISTITEM: + if (((wMenuListItem_p)m)->action) + ((wMenuListItem_p)m)->action(0, "", ((wMenuListItem_p)m)->data); + break; + case M_RADIO: + if (((wMenuRadio_p)m)->action) + ((wMenuRadio_p)m)->action(((wMenuRadio_p)m)->data); + break; + } + return 0L; + } + if ( (m->parentMenu)->traceFunc ) { + (m->parentMenu)->traceFunc( m->parentMenu, m->labelStr, ((wMenu_p)m->parentMenu)->traceData ); + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +static void menuDone( wControl_p b ) +{ + wMenuItem_p m = (wMenuItem_p)b; + switch ( m->mtype ) { + case M_MENU: + if ( ((wMenu_p)m)->mmtype == MM_BUTT || + ((wMenu_p)m)->mmtype == MM_POPUP ) + DestroyMenu( ((wMenu_p)m)->menu ); + break; + } +} + +static callBacks_t menuItemCallBacks = { + NULL, + menuDone, + menuPush }; + + +static wMenuItem_p createMenuItem( + wMenu_p m, + mtype_e mtype, + const char * helpStr, + const char * labelStr, + int size ) +{ + wMenuItem_p mi; + + mi = (wMenuItem_p)calloc( 1, size ); + mi->type = B_MENUITEM; + /*mi->messageProc = menuPush;*/ + mi->index = mswRegister( (wControl_p)mi ); + mi->mtype = mtype; + if (m) { + if (m->last != NULL) { + m->last->mnext = mi; + } else { + m->first = m->last = mi; + } + m->last = mi; + } + mi->mnext = NULL; + mi->labelStr = mswStrdup( labelStr ); +// if (helpStr != NULL) { +// char *string; +// string = malloc( strlen(helpStr) + 1 ); +// strcpy( string, helpStr ); +// /*xv_set(mi->menu_item, XV_HELP_DATA, string, 0 );*/ +// } + mswCallBacks[B_MENUITEM] = &menuItemCallBacks; + return mi; +} + +/* + ***************************************************************************** + * + * Accelerators + * + ***************************************************************************** + */ + + +typedef struct { + long acclKey; + wMenuPush_p mp; + wAccelKeyCallBack_p action; + wAccelKey_e key; + void * data; + } acclTable_t, *acclTable_p; +dynArr_t acclTable_da; +#define acclTable(N) DYNARR_N( acclTable_t, acclTable_da, N ) + + +int mswMenuAccelerator( + wWin_p win, + long acclKey ) +{ + acclTable_p at; + if ( ((wControl_p)win)->type != W_MAIN && + ((wControl_p)win)->type != W_POPUP ) + return 0; + for ( at = &acclTable(0); at<&acclTable(acclTable_da.cnt); at++ ) { + if (at->acclKey == acclKey) { + if (at->mp) { + if (at->mp->enabled && at->mp->action) + at->mp->action(at->mp->data); + return 1; + } else if (at->action) { + at->action( at->key, at->data ); + return 1; + } else { + return 0; + } + } + } + return 0; +} + + + +static long acclKeyMap[] = { + 0, /* wAccelKey_None, */ + VK_DELETE, /* wAccelKey_Del, */ + VK_INSERT, /* wAccelKey_Ins, */ + VK_HOME, /* wAccelKey_Home, */ + VK_END, /* wAccelKey_End, */ + VK_PRIOR, /* wAccelKey_Pgup, */ + VK_NEXT, /* wAccelKey_Pgdn, */ + VK_UP, /* wAccelKey_Up, */ + VK_DOWN, /* wAccelKey_Down, */ + VK_RIGHT, /* wAccelKey_Right, */ + VK_LEFT, /* wAccelKey_Left, */ + VK_BACK, /* wAccelKey_Back, */ + VK_F1, /* wAccelKey_F1, */ + VK_F2, /* wAccelKey_F2, */ + VK_F3, /* wAccelKey_F3, */ + VK_F4, /* wAccelKey_F4, */ + VK_F5, /* wAccelKey_F5, */ + VK_F6, /* wAccelKey_F6, */ + VK_F7, /* wAccelKey_F7, */ + VK_F8, /* wAccelKey_F8, */ + VK_F9, /* wAccelKey_F9, */ + VK_F10, /* wAccelKey_F10, */ + VK_F11, /* wAccelKey_F11, */ + VK_F12 /* wAccelKey_F12, */ + }; + + +void wAttachAccelKey( + wAccelKey_e key, + int modifier, + wAccelKeyCallBack_p action, + void * data ) +{ + acclTable_t * ad; + if ( key < 1 || key > wAccelKey_F12 ) { + mswFail( "wAttachAccelKey: key out of range" ); + return; + } + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + ad = &acclTable(acclTable_da.cnt-1); + ad->acclKey = acclKeyMap[key] | (modifier<<8); + ad->key = key; + ad->action = action; + ad->data = data; + ad->mp = NULL; +} + +/* + ***************************************************************************** + * + * Menu Item Create + * + ***************************************************************************** + */ + +HBITMAP GetMyCheckBitmaps(UINT fuCheck) +{ + COLORREF crBackground; /* background color */ + HBRUSH hbrBackground; /* background brush */ + HBRUSH hbrTargetOld; /* original background brush */ + HDC hdcSource; /* source device context */ + HDC hdcTarget; /* target device context */ + HBITMAP hbmpCheckboxes; /* handle to check-box bitmap */ + BITMAP bmCheckbox; /* structure for bitmap data */ + HBITMAP hbmpSourceOld; /* handle to original source bitmap */ + HBITMAP hbmpTargetOld; /* handle to original target bitmap */ + HBITMAP hbmpCheck; /* handle to check-mark bitmap */ + RECT rc; /* rectangle for check-box bitmap */ + WORD wBitmapX; /* width of check-mark bitmap */ + WORD wBitmapY; /* height of check-mark bitmap */ + + /* Get the menu background color and create a solid brush + with that color. */ + + crBackground = GetSysColor(COLOR_MENU); + hbrBackground = CreateSolidBrush(crBackground); + + /* Create memory device contexts for the source and + destination bitmaps. */ + + hdcSource = CreateCompatibleDC((HDC) NULL); + hdcTarget = CreateCompatibleDC(hdcSource); + + /* Get the size of the system default check-mark bitmap and + create a compatible bitmap of the same size. */ + + wBitmapX = GetSystemMetrics(SM_CXMENUCHECK); + wBitmapY = GetSystemMetrics(SM_CYMENUCHECK); + + hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX, + wBitmapY); + + /* Select the background brush and bitmap into the target DC. */ + + hbrTargetOld = SelectObject(hdcTarget, hbrBackground); + hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck); + + /* Use the selected brush to initialize the background color + of the bitmap in the target device context. */ + + PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY); + + /* Load the predefined check box bitmaps and select it + into the source DC. */ + + hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL, + (LPTSTR) OBM_CHECKBOXES); + + hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes); + + /* Fill a BITMAP structure with information about the + check box bitmaps, and then find the upper-left corner of + the unchecked check box or the checked check box. */ + + GetObject(hbmpCheckboxes, sizeof(BITMAP), &bmCheckbox); + + switch( fuCheck ) { + + case UNCHECK: + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case CHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case RADIOCHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + break; + case RADIOUNCHECK: + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + + break; + } + + /* Copy the appropriate bitmap into the target DC. If the + check-box bitmap is larger than the default check-mark + bitmap, use StretchBlt to make it fit; otherwise, just + copy it. */ + + if (((rc.right - rc.left) > (int) wBitmapX) || + ((rc.bottom - rc.top) > (int) wBitmapY)) + { + StretchBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, + hdcSource, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, SRCCOPY); + } + + else + { + BitBlt(hdcTarget, 0, 0, rc.right - rc.left, + rc.bottom - rc.top, + hdcSource, rc.left, rc.top, SRCCOPY); + } + + /* Select the old source and destination bitmaps into the + source and destination DCs, and then delete the DCs and + the background brush. */ + + SelectObject(hdcSource, hbmpSourceOld); + SelectObject(hdcTarget, hbrTargetOld); + hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld); + + DeleteObject(hbrBackground); + DeleteObject(hdcSource); + DeleteObject(hdcTarget); + + /* Return a handle to the new check-mark bitmap. */ + + return hbmpCheck; +} + +void mswCreateCheckBitmaps() +{ + checked = GetMyCheckBitmaps( CHECK ); + unchecked = GetMyCheckBitmaps( UNCHECK ); + checkedRadio = GetMyCheckBitmaps( RADIOCHECK ); + uncheckedRadio = GetMyCheckBitmaps( RADIOUNCHECK ); + +} + +wMenuRadio_p wMenuRadioCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuRadio_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuRadio_p)createMenuItem( m, M_RADIO, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = (wMenuPush_p)mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + + /* add the correct bitmaps for radio buttons */ + + rc = SetMenuItemBitmaps(m->menu, mi->index, FALSE, uncheckedRadio, checkedRadio ); + + if( m->radioGroup == NULL ) { + m->radioGroup = malloc( sizeof( struct radioButtonGroup )); + assert( m->radioGroup ); + m->radioGroup->firstButton = mi->index; + } else { + m->radioGroup->lastButton = mi->index; + } + + return mi; +} + +void wMenuRadioSetActive(wMenuRadio_p mi ) +{ + BOOL rc; + + rc = CheckMenuRadioItem( mi->mparent->menu, + mi->mparent->radioGroup->firstButton, + mi->mparent->radioGroup->lastButton, + mi->index, + MF_BYCOMMAND ); +} + + +wMenuPush_p wMenuPushCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuPush_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuPush_p)createMenuItem( m, M_PUSH, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + return mi; +} + + +void wMenuPushEnable( + wMenuPush_p mi, + BOOL_T enable ) +{ + EnableMenuItem( mi->mparent->menu, mi->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mi->enabled = enable; +} + + +wMenu_p wMenuMenuCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr ) +{ + wMenu_p mm; + int rc; + + mm = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, labelStr, sizeof *mm ); + mm->menu = CreatePopupMenu(); + mm->mmtype = MM_MENU; + /*mm->parent = (wControl_p)m;*/ + mm->first = mm->last = NULL; + + rc = AppendMenu( m->menu, MF_STRING|MF_ENABLED|MF_POPUP, (UINT)mm->menu, mm->labelStr ); + + return mm; +} + +void wMenuSeparatorCreate( + wMenu_p m ) +{ + int rc; + createMenuItem( m, M_SEPARATOR, NULL, NULL, sizeof *(wMenuItem_p)NULL ); + rc = AppendMenu( m->menu, MF_SEPARATOR, (UINT)0, NULL ); +} + +/* + ***************************************************************************** + * + * Menu List + * + ***************************************************************************** + */ + + +static void appendItem( + wMenuListItem_p ml, + wMenuListItem_p mi ) +{ + mi->right = ml->right; + ml->right->left = mi; + mi->left = ml; + ml->right = mi; +} + + +static void removeItem( + wMenuListItem_p mi ) +{ + mi->left->right = mi->right; + mi->right->left = mi->left; + mi->right = mi->left = mi; +} + + +wMenuList_p wMenuListCreate( + wMenu_p m, + const char * helpStr, + int max, + wMenuListCallBack_p action ) +{ + wMenuList_p mi; + mi = (wMenuList_p)createMenuItem( m, M_LIST, helpStr, NULL, sizeof *mi ); + mi->count = 0; + mi->max = max; + mi->mlparent = m; + mi->action = action; + mi->right = mi->left = (wMenuListItem_p)mi; + return mi; +} + + +int getMlistOrigin( wMenu_p m, wMenuList_p ml ) +{ + wMenuItem_p mi; + int count; + count = 0; + for ( mi = m->first; mi != NULL; mi = mi->mnext ) { + switch( mi->mtype ) { + case M_SEPARATOR: + case M_PUSH: + case M_MENU: + count++; + break; + case M_LIST: + if (mi == (wMenuItem_p)ml) + return count; + count += ((wMenuList_p)mi)->count; + break; + default: + mswFail( "getMlistOrigin" ); + } + } + return count; +} + + +void wMenuListAdd( + wMenuList_p ml, + int index, + const char * labelStr, + void * data ) +{ + int origin; + wMenuListItem_p wl_p; + wMenuListItem_p mi; + int count; + int rc; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* move item */ + if (count != index) { + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + goto add; + } + ((wMenuListItem_p)wl_p)->data = data; + return; + } + } + if (ml->max > 0 && ml->count >= ml->max) { + RemoveMenu( ml->mlparent->menu, origin+ml->count-1, MF_BYPOSITION ); + wl_p = ml->left; + removeItem( ml->left ); +add: + ml->count--; + if (wl_p->labelStr ) + free( CAST_AWAY_CONST wl_p->labelStr ); + wl_p->labelStr = mswStrdup( labelStr ); + } else { + wl_p = (wMenuListItem_p)createMenuItem( NULL, M_LISTITEM, NULL, + labelStr, sizeof *wl_p ); + } + ((wMenuListItem_p)wl_p)->data = data; + ((wMenuListItem_p)wl_p)->action = ml->action; + if (index < 0 || index > ml->count) + index = ml->count; + for ( mi=(wMenuListItem_p)ml,count=0; count<index; mi=mi->right,count++); + rc = InsertMenu( ml->mlparent->menu, origin+index, + MF_BYPOSITION|MF_STRING, wl_p->index, wl_p->labelStr ); + appendItem( mi, wl_p ); + ml->count++; +} + + +void wMenuListDelete( + wMenuList_p ml, + const char * labelStr ) +{ + int origin, count; + wMenuListItem_p wl_p; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + ml->count--; + free( wl_p ); + return; + } + } +} + + +const char * wMenuListGet( + wMenuList_p ml, + int index, + void ** data ) +{ + int origin, count; + wMenuListItem_p wl_p; + + if (index >= ml->count) + return NULL; + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p&&count<index; count++,wl_p=wl_p->right ); + if (wl_p==NULL) + return NULL; + if ( data ) + *data = wl_p->data; + return wl_p->labelStr; +} + + +void wMenuListClear( + wMenuList_p ml ) +{ + int origin, count; + wMenuListItem_p wl_p, wl_q; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; count<ml->count; count++,wl_p=wl_q ) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin, MF_BYPOSITION ); + wl_q = wl_p->right; + free( wl_p ); + } + ml->count = 0; + ml->right = ml->left = (wMenuListItem_p)ml; +} + + + +wMenuToggle_p wMenuToggleCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wBool_t set, + wMenuToggleCallBack_p action, + void * data ) +{ + wMenuToggle_p mt; + int rc; + + mt = (wMenuToggle_p)createMenuItem( m, M_TOGGLE, helpStr, labelStr, sizeof *mt ); + /*setAcclKey( m->parent, m->menu, mt->menu_item, acclKey );*/ + mt->action = action; + mt->data = data; + mt->mparent = m; + mt->enabled = TRUE; + mt->parentMenu = m; + rc = AppendMenu( m->menu, MF_STRING, mt->index, labelStr ); + wMenuToggleSet( mt, set ); + return mt; +} + + +wBool_t wMenuToggleGet( + wMenuToggle_p mt ) +{ + return (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; +} + + +wBool_t wMenuToggleSet( + wMenuToggle_p mt, + wBool_t set ) +{ + wBool_t rc; + CheckMenuItem( mt->mparent->menu, mt->index, MF_BYCOMMAND|(set?MF_CHECKED:MF_UNCHECKED) ); + rc = (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; + return rc; +} + +void wMenuToggleEnable( + wMenuToggle_p mt, + wBool_t enable ) +{ + EnableMenuItem( mt->mparent->menu, mt->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mt->enabled = enable; +} + +/* + ***************************************************************************** + * + * Menu Create + * + ***************************************************************************** + */ + + +void mswMenuMove( + wMenu_p m, + wPos_t x, + wPos_t y ) +{ + wControl_p b; + b = (wControl_p)m->parent; + if (b && b->hWnd) + if (!SetWindowPos( b->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("mswMenuMove"); +} + + +static void pushMenuButt( + void * data ) +{ + wMenu_p m = (wMenu_p)data; + RECT rect; + mswAllowBalloonHelp = FALSE; + GetWindowRect( m->hWnd, &rect ); + TrackPopupMenu( m->menu, TPM_LEFTALIGN, rect.left, rect.bottom, + 0, ((wControl_p)(m->parent))->hWnd, NULL ); +} + + +wMenu_p wMenuCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option ) +{ + wMenu_p m; + wControl_p b; + long buttOption = 0; + const char * label = labelStr; + + if (option & BM_ICON) { + buttOption = BO_ICON; + label = "ICON"; + } + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, label, sizeof *m ); + m->button = wButtonCreate( parent, x, y, helpStr, labelStr, + buttOption, 0, pushMenuButt, (void*)m ); + b = (wControl_p)m->button; + m->parent = b->parent; + m->x = b->x; + m->y = b->y; + m->w = b->w; + m->h = b->h; + m->hWnd = b->hWnd; + m->helpStr = b->helpStr; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_BUTT; + m->first = m->last = NULL; + + return m; +} + + +wMenu_p wMenuBarAdd( + wWin_p w, + const char * helpStr, + const char * labelStr ) +{ + HMENU menu; + wMenu_p m; + int rc; + + menu = GetMenu( ((wControl_p)w)->hWnd ); + if (menu == (HMENU)0) { + menu = CreateMenu(); + SetMenu( ((wControl_p)w)->hWnd, menu ); + } + + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, labelStr, sizeof *m ); + m->menu = CreateMenu(); + m->parent = w; + m->mmtype = MM_BAR; + m->first = m->last = NULL; + + rc = AppendMenu( menu, MF_STRING|MF_POPUP|MF_ENABLED, (UINT)m->menu, labelStr ); + + DrawMenuBar( ((wControl_p)w)->hWnd ); + return m; +} + + + +wMenu_p wMenuPopupCreate( + wWin_p w, + const char * labelStr ) +{ + wMenu_p m; + long buttOption = 0; + const char * label = labelStr; + + m = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, label, sizeof *m ); + m->button = NULL; + m->parent = w; + m->x = 0; + m->y = 0; + m->w = 0; + m->h = 0; + m->hWnd = ((wControl_p)w)->hWnd; + m->helpStr = NULL; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_POPUP; + m->first = m->last = NULL; + + return m; +} + + +void wMenuPopupShow( wMenu_p mp ) +{ + POINT pt; + GetCursorPos( &pt ); + TrackPopupMenu( mp->menu, TPM_LEFTALIGN, pt.x, pt.y, 0, mp->hWnd, NULL ); +} + +/*-----------------------------------------------------------------*/ + +void wMenuSetTraceCallBack( + wMenu_p m, + wMenuTraceCallBack_p func, + void * data ) +{ + m->traceFunc = func; + m->traceData = data; +} + +wBool_t wMenuAction( + wMenu_p m, + const char * label ) +{ + wMenuItem_p mi; + wMenuToggle_p mt; + wBool_t set; + for ( mi = m->first; mi != NULL; mi = (wMenuItem_p)mi->mnext ) { + if ( mi->labelStr != NULL && strcmp( mi->labelStr, label ) == 0 ) { + switch( mi->mtype ) { + case M_SEPARATOR: + break; + case M_PUSH: + if ( ((wMenuPush_p)mi)->enabled == FALSE ) + wBeep(); + else + ((wMenuPush_p)mi)->action( ((wMenuPush_p)mi)->data ); + break; + case M_TOGGLE: + mt = (wMenuToggle_p)mi; + if ( mt->enabled == FALSE ) { + wBeep(); + } else { + set = wMenuToggleGet( mt ); + wMenuToggleSet( mt, !set ); + mt->action( set, mt->data ); + } + break; + case M_MENU: + break; + case M_LIST: + break; + default: + fprintf(stderr, "Oops: wMenuAction\n"); + } + return TRUE; + } + } + return FALSE; +} |