420 lines
11 KiB
C
420 lines
11 KiB
C
|
#include "ctlspriv.h"
|
||
|
|
||
|
#define MAININSYS
|
||
|
|
||
|
#ifndef WIN32
|
||
|
/* This returns the index of a submenu in a parent menu. The return is
|
||
|
* < 0 if the submenu does not exist in the parent menu
|
||
|
*/
|
||
|
int NEAR PASCAL GetMenuIndex(HMENU hMenu, HMENU hSubMenu)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (!hMenu || !hSubMenu)
|
||
|
return(-1);
|
||
|
|
||
|
for (i=GetMenuItemCount(hMenu)-1; i>=0; --i)
|
||
|
{
|
||
|
if (hSubMenu == GetSubMenu(hMenu, i))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(i);
|
||
|
}
|
||
|
#endif // WIN32
|
||
|
|
||
|
|
||
|
BOOL NEAR PASCAL IsMaxedMDI(HMENU hMenu)
|
||
|
{
|
||
|
return(GetMenuItemID(hMenu, GetMenuItemCount(hMenu)-1) == SC_RESTORE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Note that if iMessage is WM_COMMAND, it is assumed to have come from
|
||
|
* a header bar or toolbar; do not pass in WM_COMMAND messages from any
|
||
|
* other controls.
|
||
|
*/
|
||
|
|
||
|
#define MS_ID GET_WM_MENUSELECT_CMD
|
||
|
#define MS_FLAGS GET_WM_MENUSELECT_FLAGS
|
||
|
#define MS_MENU GET_WM_MENUSELECT_HMENU
|
||
|
|
||
|
#define CMD_NOTIFY GET_WM_COMMAND_CMD
|
||
|
#define CMD_ID GET_WM_COMMAND_ID
|
||
|
#define CMD_CTRL GET_WM_COMMAND_HWND
|
||
|
|
||
|
|
||
|
void WINAPI MenuHelp(UINT iMessage, WPARAM wParam, LPARAM lParam,
|
||
|
HMENU hMainMenu, HINSTANCE hAppInst, HWND hwndStatus, UINT FAR *lpwIDs)
|
||
|
{
|
||
|
UINT wID;
|
||
|
UINT FAR *lpwPopups;
|
||
|
int i;
|
||
|
TCHAR szString[256];
|
||
|
BOOL bUpdateNow = TRUE;
|
||
|
#if defined(WINDOWS_ME)
|
||
|
MENUITEMINFO mii;
|
||
|
//BugBug: this line should be in
|
||
|
// BOOL bByPos;
|
||
|
#endif
|
||
|
|
||
|
switch (iMessage)
|
||
|
{
|
||
|
case WM_MENUSELECT:
|
||
|
if ((WORD)MS_FLAGS(wParam, lParam)==(WORD)-1 && MS_MENU(wParam, lParam)==0)
|
||
|
{
|
||
|
#ifndef WIN32
|
||
|
EndMenuHelp:
|
||
|
#endif
|
||
|
SendMessage(hwndStatus, SB_SIMPLE, 0, 0L);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
szString[0] = TEXT('\0');
|
||
|
#if defined(WINDOWS_ME)
|
||
|
i = MS_ID(wParam, lParam);
|
||
|
//BugBug: this line should be in
|
||
|
//bByPos = (MS_FLAGS(wParam, lParam) & MF_POPUP);
|
||
|
|
||
|
memset(&mii, 0, SIZEOF(MENUITEMINFO ));
|
||
|
mii.cbSize = sizeof(mii);
|
||
|
mii.fMask = MIIM_TYPE;
|
||
|
mii.cch = 0; //If we ask for MIIM_TYPE, this must be set to zero!
|
||
|
//Otherwise, win95 attempts to copy the string too!
|
||
|
if (GetMenuItemInfo((HMENU)MS_MENU(wParam, lParam), i, TRUE /*bByPos*/, &mii))
|
||
|
mii.fState = mii.fType & MFT_RIGHTORDER ?SBT_RTLREADING :0;
|
||
|
#endif
|
||
|
if (!(MS_FLAGS(wParam, lParam)&MF_SEPARATOR))
|
||
|
{
|
||
|
if (MS_FLAGS(wParam, lParam)&MF_POPUP)
|
||
|
{
|
||
|
/* We don't want to update immediately in case the menu is
|
||
|
* about to pop down, with an item selected. This gets rid
|
||
|
* of some flashing text.
|
||
|
*/
|
||
|
bUpdateNow = FALSE;
|
||
|
|
||
|
/* First check if this popup is in our list of popup menus
|
||
|
*/
|
||
|
for (lpwPopups=lpwIDs+2; *lpwPopups; lpwPopups+=2)
|
||
|
{
|
||
|
/* lpwPopups is a list of string ID/menu handle pairs
|
||
|
* and MS_ID(wParam, lParam) is the menu handle of the selected popup
|
||
|
*/
|
||
|
if (*(lpwPopups+1) == (UINT)MS_ID(wParam, lParam))
|
||
|
{
|
||
|
wID = *lpwPopups;
|
||
|
goto LoadTheString;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check if the specified popup is in the main menu;
|
||
|
* note that if the "main" menu is in the system menu,
|
||
|
* we will be OK as long as the menu is passed in correctly.
|
||
|
* In fact, an app could handle all popups by just passing in
|
||
|
* the proper hMainMenu.
|
||
|
*/
|
||
|
if ((HMENU)MS_MENU(wParam, lParam) == hMainMenu)
|
||
|
{
|
||
|
#ifdef WIN32
|
||
|
i = MS_ID(wParam, lParam);
|
||
|
#else // WIN32
|
||
|
i = GetMenuIndex((HMENU)MS_MENU(wParam, lParam), (HMENU)MS_ID(wParam, lParam));
|
||
|
if (i >= 0)
|
||
|
#endif // WIN32
|
||
|
{
|
||
|
if (IsMaxedMDI(hMainMenu))
|
||
|
{
|
||
|
if (!i)
|
||
|
{
|
||
|
wID = IDS_SYSMENU;
|
||
|
hAppInst = HINST_THISDLL;
|
||
|
goto LoadTheString;
|
||
|
}
|
||
|
else
|
||
|
--i;
|
||
|
}
|
||
|
wID = (UINT)(i + lpwIDs[1]);
|
||
|
goto LoadTheString;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* This assumes all app defined popups in the system menu
|
||
|
* have been listed above
|
||
|
*/
|
||
|
if ((MS_FLAGS(wParam, lParam)&MF_SYSMENU))
|
||
|
{
|
||
|
wID = IDS_SYSMENU;
|
||
|
hAppInst = HINST_THISDLL;
|
||
|
goto LoadTheString;
|
||
|
}
|
||
|
|
||
|
goto NoString;
|
||
|
}
|
||
|
else if (MS_ID(wParam, lParam) >= MINSYSCOMMAND)
|
||
|
{
|
||
|
wID = (UINT)(MS_ID(wParam, lParam) + MH_SYSMENU);
|
||
|
hAppInst = HINST_THISDLL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wID = (UINT)(MS_ID(wParam, lParam) + lpwIDs[0]);
|
||
|
}
|
||
|
|
||
|
LoadTheString:
|
||
|
if (hAppInst == HINST_THISDLL)
|
||
|
LocalizedLoadString(wID, szString, ARRAYSIZE(szString));
|
||
|
else
|
||
|
LoadString(hAppInst, wID, szString, ARRAYSIZE(szString));
|
||
|
}
|
||
|
|
||
|
NoString:
|
||
|
#if defined(WINDOWS_ME)
|
||
|
SendMessage(hwndStatus, SB_SETTEXT, mii.fState|SBT_NOBORDERS|255,
|
||
|
(LPARAM)(LPSTR)szString);
|
||
|
#else
|
||
|
SendMessage(hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255,
|
||
|
(LPARAM)(LPTSTR)szString);
|
||
|
#endif
|
||
|
SendMessage(hwndStatus, SB_SIMPLE, 1, 0L);
|
||
|
|
||
|
if (bUpdateNow)
|
||
|
UpdateWindow(hwndStatus);
|
||
|
break;
|
||
|
|
||
|
#ifndef WIN32
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
switch (CMD_NOTIFY(wParam, lParam))
|
||
|
{
|
||
|
#ifdef WANT_SUCKY_HEADER
|
||
|
// BUGBUG: these are now WM_NOTIFY messages
|
||
|
case HBN_BEGINDRAG:
|
||
|
bUpdateNow = FALSE;
|
||
|
wID = IDS_HEADER;
|
||
|
goto BeginSomething;
|
||
|
|
||
|
case HBN_BEGINADJUST:
|
||
|
wID = IDS_HEADERADJ;
|
||
|
goto BeginSomething;
|
||
|
#endif
|
||
|
case TBN_BEGINADJUST:
|
||
|
/* We don't want to update immediately in case the operation is
|
||
|
* aborted immediately.
|
||
|
*/
|
||
|
bUpdateNow = FALSE;
|
||
|
wID = IDS_TOOLBARADJ;
|
||
|
goto BeginSomething;
|
||
|
|
||
|
BeginSomething:
|
||
|
SendMessage(hwndStatus, SB_SIMPLE, 1, 0L);
|
||
|
hAppInst = HINST_THISDLL;
|
||
|
goto LoadTheString;
|
||
|
|
||
|
case TBN_BEGINDRAG:
|
||
|
MenuHelp(WM_MENUSELECT, (WPARAM)CMD_CTRL(wParam, lParam), 0L,
|
||
|
hMainMenu, hAppInst, hwndStatus, lpwIDs);
|
||
|
break;
|
||
|
#ifdef WANT_SUCKY_HEADER
|
||
|
case HBN_ENDDRAG:
|
||
|
case HBN_ENDADJUST:
|
||
|
#endif
|
||
|
case TBN_ENDDRAG:
|
||
|
case TBN_ENDADJUST:
|
||
|
goto EndMenuHelp;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
#endif // !WIN32
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL WINAPI ShowHideMenuCtl(HWND hWnd, WPARAM wParam, LPINT lpInfo)
|
||
|
{
|
||
|
HWND hCtl;
|
||
|
UINT uTool, uShow = MF_UNCHECKED | MF_BYCOMMAND;
|
||
|
HMENU hMainMenu;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
hMainMenu = IntToPtr_(HMENU, lpInfo[1]);
|
||
|
|
||
|
for (uTool=0; ; ++uTool, lpInfo+=2)
|
||
|
{
|
||
|
if ((WPARAM)lpInfo[0] == wParam)
|
||
|
break;
|
||
|
if (!lpInfo[0])
|
||
|
goto DoTheCheck;
|
||
|
}
|
||
|
|
||
|
if (!(GetMenuState(hMainMenu, (UINT) wParam, MF_BYCOMMAND)&MF_CHECKED))
|
||
|
uShow = MF_CHECKED | MF_BYCOMMAND;
|
||
|
|
||
|
switch (uTool)
|
||
|
{
|
||
|
case 0:
|
||
|
bRet = SetMenu(hWnd, (HMENU)((uShow&MF_CHECKED) ? hMainMenu : 0));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hCtl = GetDlgItem(hWnd, lpInfo[1]);
|
||
|
if (hCtl)
|
||
|
{
|
||
|
ShowWindow(hCtl, (uShow&MF_CHECKED) ? SW_SHOW : SW_HIDE);
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else
|
||
|
uShow = MF_UNCHECKED | MF_BYCOMMAND;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DoTheCheck:
|
||
|
CheckMenuItem(hMainMenu, (UINT) wParam, uShow);
|
||
|
|
||
|
#ifdef MAININSYS
|
||
|
hMainMenu = GetSubMenu(GetSystemMenu(hWnd, FALSE), 0);
|
||
|
if (hMainMenu)
|
||
|
CheckMenuItem(hMainMenu, (UINT) wParam, uShow);
|
||
|
#endif
|
||
|
|
||
|
return(bRet);
|
||
|
}
|
||
|
|
||
|
|
||
|
void WINAPI GetEffectiveClientRect(HWND hWnd, LPRECT lprc, LPINT lpInfo)
|
||
|
{
|
||
|
RECT rc;
|
||
|
HWND hCtl;
|
||
|
|
||
|
GetClientRect(hWnd, lprc);
|
||
|
|
||
|
/* Get past the menu
|
||
|
*/
|
||
|
for (lpInfo+=2; lpInfo[0]; lpInfo+=2)
|
||
|
{
|
||
|
hCtl = GetDlgItem(hWnd, lpInfo[1]);
|
||
|
/* We check the style bit because the parent window may not be visible
|
||
|
* yet (still in the create message)
|
||
|
*/
|
||
|
if (!hCtl || !(GetWindowStyle(hCtl) & WS_VISIBLE))
|
||
|
continue;
|
||
|
|
||
|
GetWindowRect(hCtl, &rc);
|
||
|
|
||
|
//
|
||
|
// This will do the ScrrenToClient functionality, plus
|
||
|
// it will return a good rect (left < right) when the
|
||
|
// hWnd parent is RTL mirrored. [samera]
|
||
|
//
|
||
|
MapWindowPoints(HWND_DESKTOP, hWnd, (PPOINT)&rc, 2);
|
||
|
|
||
|
SubtractRect(lprc, lprc, &rc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// BUGBUG: nuke this stuff for WIN32
|
||
|
|
||
|
#define NibbleToChar(x) (N2C[x])
|
||
|
static char N2C[] =
|
||
|
{
|
||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||
|
} ;
|
||
|
|
||
|
BOOL WINAPI MyWritePrivateProfileStruct(LPCSTR szSection, LPCSTR szKey,
|
||
|
LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile)
|
||
|
{
|
||
|
PSTR pLocal, pTemp;
|
||
|
BOOL bRet;
|
||
|
BYTE FAR *lpByte;
|
||
|
|
||
|
/* NULL lpStruct erases the the key */
|
||
|
|
||
|
if (lpStruct == NULL) {
|
||
|
if (szFile && *szFile)
|
||
|
return WritePrivateProfileString(szSection, szKey, NULL, szFile);
|
||
|
else
|
||
|
WriteProfileString(szSection, szKey, NULL);
|
||
|
}
|
||
|
|
||
|
pLocal = (PSTR)LocalAlloc(LPTR, uSizeStruct*2 + 1);
|
||
|
if (!pLocal)
|
||
|
return(FALSE);
|
||
|
|
||
|
lpByte = lpStruct;
|
||
|
|
||
|
for (pTemp=pLocal; uSizeStruct>0; --uSizeStruct, ++lpByte)
|
||
|
{
|
||
|
BYTE bStruct;
|
||
|
|
||
|
bStruct = *lpByte;
|
||
|
*pTemp++ = NibbleToChar((bStruct>>4)&0x000f);
|
||
|
*pTemp++ = NibbleToChar(bStruct&0x000f);
|
||
|
}
|
||
|
|
||
|
*pTemp = '\0';
|
||
|
|
||
|
if (szFile && *szFile)
|
||
|
bRet = WritePrivateProfileString(szSection, szKey, pLocal, szFile);
|
||
|
else
|
||
|
bRet = WriteProfileString(szSection, szKey, pLocal);
|
||
|
|
||
|
LocalFree((HLOCAL)pLocal);
|
||
|
return(bRet);
|
||
|
}
|
||
|
|
||
|
/* Note that the following works for both upper and lower case, and will
|
||
|
* return valid values for garbage chars
|
||
|
*/
|
||
|
#define CharToNibble(x) ((x)>='0'&&(x)<='9' ? (x)-'0' : ((10+(x)-'A')&0x000f))
|
||
|
|
||
|
BOOL WINAPI MyGetPrivateProfileStruct(LPCSTR szSection, LPCSTR szKey,
|
||
|
LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile)
|
||
|
{
|
||
|
PSTR pLocal, pTemp;
|
||
|
int nLen;
|
||
|
BYTE FAR *lpByte;
|
||
|
|
||
|
nLen = uSizeStruct*2 + 10;
|
||
|
pLocal = (PSTR)LocalAlloc(LPTR, nLen);
|
||
|
if (!pLocal)
|
||
|
return(FALSE);
|
||
|
|
||
|
if (szFile && *szFile)
|
||
|
nLen = GetPrivateProfileString(szSection, szKey, c_szNULL, pLocal, nLen,
|
||
|
szFile);
|
||
|
else
|
||
|
nLen = GetProfileString(szSection, szKey, c_szNULL, pLocal, nLen);
|
||
|
if ((UINT)nLen != uSizeStruct*2)
|
||
|
{
|
||
|
LocalFree((HLOCAL)pLocal);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
lpByte = lpStruct;
|
||
|
|
||
|
for (pTemp=pLocal; uSizeStruct>0; --uSizeStruct, ++lpByte)
|
||
|
{
|
||
|
BYTE bStruct;
|
||
|
char cTemp;
|
||
|
|
||
|
cTemp = *pTemp++;
|
||
|
bStruct = (BYTE)CharToNibble(cTemp);
|
||
|
cTemp = *pTemp++;
|
||
|
bStruct = (BYTE)((bStruct<<4) | CharToNibble(cTemp));
|
||
|
|
||
|
*lpByte = bStruct;
|
||
|
}
|
||
|
|
||
|
LocalFree((HLOCAL)pLocal);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
#endif
|