2152 lines
58 KiB
C
2152 lines
58 KiB
C
|
#include "progman.h"
|
||
|
#include "ime.h"
|
||
|
|
||
|
BOOL FAR PASCAL IMEStringWindow(HWND,HANDLE);
|
||
|
int FAR PASCAL IMEWindowGetCnt(LPTSTR,LPTSTR);
|
||
|
|
||
|
#define HK_SHIFT 0x0100
|
||
|
#define HK_CONTROL 0x0200
|
||
|
#define HK_ALT 0x0400
|
||
|
#define HK_EXT 0x0800
|
||
|
|
||
|
#define F_EXT 0x01000000L
|
||
|
|
||
|
#define OBJ_ITEM 1
|
||
|
|
||
|
|
||
|
BOOL bNoScrollCalc = FALSE;
|
||
|
RECT rcArrangeRect;
|
||
|
HWND hwndScrolling = NULL;
|
||
|
|
||
|
BOOL APIENTRY InQuotes(LPTSTR sz);
|
||
|
void NEAR PASCAL ViewActiveItem(PGROUP pGroup);
|
||
|
|
||
|
/* Make the first item in a list the last and return a pointer to it.*/
|
||
|
|
||
|
PITEM PASCAL MakeFirstItemLast(PGROUP pGroup)
|
||
|
{
|
||
|
PITEM pItemCur;
|
||
|
|
||
|
/* Just quit if there's no list.*/
|
||
|
|
||
|
if ((pItemCur = pGroup->pItems) == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
/* Find the end of the list.*/
|
||
|
for( ; pItemCur->pNext ; pItemCur = pItemCur->pNext)
|
||
|
;
|
||
|
|
||
|
/* End of the list.*/
|
||
|
/* This works even if there is only one item in the */
|
||
|
/* list, it's a waste of time though.*/
|
||
|
pItemCur->pNext = pGroup->pItems;
|
||
|
pGroup->pItems = pGroup->pItems->pNext;
|
||
|
pItemCur->pNext->pNext = NULL;
|
||
|
|
||
|
return pItemCur->pNext;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID PASCAL GetItemText(PGROUP pGroup, PITEM pItem, LPTSTR lpT, int index)
|
||
|
{
|
||
|
LPITEMDEF lpid;
|
||
|
LPGROUPDEF lpgd;
|
||
|
|
||
|
lpid = LockItem(pGroup,pItem);
|
||
|
if (!lpid) {
|
||
|
UnlockGroup(pGroup->hwnd);
|
||
|
*lpT = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
|
||
|
switch (index) {
|
||
|
|
||
|
case 0:
|
||
|
lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pName));
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pCommand));
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pIconPath));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
*lpT = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
|
||
|
UnlockGroup(pGroup->hwnd);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG Color16Palette[] = {
|
||
|
0x00000000, 0x00800000, 0x00008000, 0x00808000,
|
||
|
0x00000080, 0x00800080, 0x00008080, 0x00808080,
|
||
|
0x00c0c0c0, 0x00ff0000, 0x0000ff00, 0x00ffff00,
|
||
|
0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
|
||
|
};
|
||
|
|
||
|
ULONG Color256Palette[] = {
|
||
|
0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
|
||
|
0x00c0dcc0, 0x00a6caf0, 0x00cccccc, 0x00580800, 0x00600800, 0x00680800, 0x00700800, 0x00780800,
|
||
|
0x00801000, 0x00881000, 0x00901000, 0x00981000, 0x00a01000, 0x00a81000, 0x00b01000, 0x00b81000,
|
||
|
0x00c01800, 0x00c81800, 0x00d01800, 0x00d81800, 0x00e01800, 0x00e81800, 0x00f01800, 0x00f81800,
|
||
|
0x00002000, 0x00082000, 0x00102000, 0x00182000, 0x00202000, 0x00282000, 0x00302000, 0x00382000,
|
||
|
0x00402800, 0x00482800, 0x00502800, 0x00582800, 0x00602800, 0x00682800, 0x00702800, 0x00782800,
|
||
|
0x00803000, 0x00883000, 0x00903000, 0x00983000, 0x00a03000, 0x00a83000, 0x00b03000, 0x00b83000,
|
||
|
0x00c03800, 0x00c83800, 0x00d03800, 0x00d83800, 0x00e03800, 0x00e83800, 0x00f03800, 0x00f83800,
|
||
|
0x00004010, 0x00084010, 0x00104010, 0x00184010, 0x00204010, 0x00284010, 0x00304010, 0x00384010,
|
||
|
0x00404810, 0x00484810, 0x00504810, 0x00584810, 0x00604810, 0x00684810, 0x00704810, 0x00784810,
|
||
|
0x00805010, 0x00885010, 0x00905010, 0x00985010, 0x00a05010, 0x00a85010, 0x00b05010, 0x00b85010,
|
||
|
0x00c05810, 0x00c85810, 0x00d05810, 0x00d85810, 0x00e05810, 0x00e85810, 0x00f05810, 0x00f85810,
|
||
|
0x00006010, 0x00086010, 0x00106010, 0x00186010, 0x00206010, 0x00286010, 0x00306010, 0x00386010,
|
||
|
0x00406810, 0x00486810, 0x00506810, 0x00586810, 0x00606810, 0x00686810, 0x00706810, 0x00786810,
|
||
|
0x00807010, 0x00887010, 0x00907010, 0x00987010, 0x00a07010, 0x00a87010, 0x00b07010, 0x00b87010,
|
||
|
0x00c07810, 0x00c87810, 0x00d07810, 0x00d87810, 0x00e07810, 0x00e87810, 0x00f07810, 0x00f87810,
|
||
|
0x00008020, 0x00088020, 0x00108020, 0x00188020, 0x00208020, 0x00288020, 0x00308020, 0x00388020,
|
||
|
0x00408820, 0x00488820, 0x00508820, 0x00588820, 0x00608820, 0x00688820, 0x00708820, 0x00788820,
|
||
|
0x00809020, 0x00889020, 0x00909020, 0x00989020, 0x00a09020, 0x00a89020, 0x00b09020, 0x00b89020,
|
||
|
0x00c09820, 0x00c89820, 0x00d09820, 0x00d89820, 0x00e09820, 0x00e89820, 0x00f09820, 0x00f89820,
|
||
|
0x0000a020, 0x0008a020, 0x0010a020, 0x0018a020, 0x0020a020, 0x0028a020, 0x0030a020, 0x0038a020,
|
||
|
0x0040a820, 0x0048a820, 0x0050a820, 0x0058a820, 0x0060a820, 0x0068a820, 0x0070a820, 0x0078a820,
|
||
|
0x0080b020, 0x0088b020, 0x0090b020, 0x0098b020, 0x00a0b020, 0x00a8b020, 0x00b0b020, 0x00b8b020,
|
||
|
0x00c0b820, 0x00b820c8, 0x00b820d0, 0x00b820d8, 0x00b820e0, 0x00b820e8, 0x00b820f0, 0x00b820f8,
|
||
|
0x0000c030, 0x00c03008, 0x00c03010, 0x00c03018, 0x00c03020, 0x00c03028, 0x00c03030, 0x00c03038,
|
||
|
0x0040c830, 0x00c83048, 0x00c83050, 0x00c83058, 0x00c83060, 0x00c83068, 0x00c83070, 0x00c83078,
|
||
|
0x0080d030, 0x00d03088, 0x00d03090, 0x00d03098, 0x00d030a0, 0x00d030a8, 0x00d030b0, 0x00d030b8,
|
||
|
0x00c0d830, 0x00c8d830, 0x00d0d830, 0x00d8d830, 0x00e0d830, 0x00e8d830, 0x00f0d830, 0x00f8d830,
|
||
|
0x0000e030, 0x0008e030, 0x0010e030, 0x0018e030, 0x0020e030, 0x0028e030, 0x0030e030, 0x0038e030,
|
||
|
0x0040e830, 0x0048e830, 0x0050e830, 0x0058e830, 0x0060e830, 0x0068e830, 0x0070e830, 0x0078e830,
|
||
|
0x0080f030, 0x0088f030, 0x0090f030, 0x0098f030, 0x00a0f030, 0x00a8f030, 0x00fffbf0, 0x00a0a0a4,
|
||
|
0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00, 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
|
||
|
};
|
||
|
|
||
|
|
||
|
HICON APIENTRY GetItemIcon(HWND hwnd, PITEM pitem)
|
||
|
{
|
||
|
|
||
|
LPGROUPDEF lpgd;
|
||
|
LPITEMDEF lpid;
|
||
|
HICON hIcon = NULL;
|
||
|
DWORD dwVer;
|
||
|
HANDLE h;
|
||
|
LPBYTE p;
|
||
|
INT id = 0;
|
||
|
INT cb;
|
||
|
DWORD colors, size;
|
||
|
PBITMAPINFOHEADER pbih, pbihNew;
|
||
|
LPVOID palette;
|
||
|
|
||
|
lpgd = LockGroup(hwnd);
|
||
|
if (!lpgd)
|
||
|
return DuplicateIcon(hAppInstance, hItemIcon);
|
||
|
//return hItemIcon;
|
||
|
lpid = ITEM(lpgd,pitem->iItem);
|
||
|
|
||
|
if ((SHORT)lpid->cbIconRes > 0) {
|
||
|
if (lpid->wIconVer == 2)
|
||
|
dwVer = 0x00020000;
|
||
|
else
|
||
|
dwVer = 0x00030000;
|
||
|
|
||
|
pbihNew = NULL;
|
||
|
pbih = (PBITMAPINFOHEADER)PTR(lpgd, lpid->pIconRes);
|
||
|
size = lpid->cbIconRes;
|
||
|
|
||
|
if (pbih->biClrUsed == -1) {
|
||
|
colors = (1 << (pbih->biPlanes * pbih->biBitCount));
|
||
|
size += colors * sizeof(RGBQUAD);
|
||
|
|
||
|
if (colors == 16) {
|
||
|
palette = Color16Palette;
|
||
|
} else if (colors == 256) {
|
||
|
palette = Color256Palette;
|
||
|
} else {
|
||
|
palette = NULL;
|
||
|
}
|
||
|
|
||
|
if (palette != NULL)
|
||
|
pbihNew = (PBITMAPINFOHEADER)LocalAlloc(LPTR, size);
|
||
|
|
||
|
if (pbihNew != NULL) {
|
||
|
RtlCopyMemory(pbihNew, pbih, sizeof( *pbih ));
|
||
|
pbihNew->biClrUsed = 0;
|
||
|
RtlCopyMemory((pbihNew+1), palette, colors * sizeof(RGBQUAD));
|
||
|
RtlCopyMemory((PCHAR)(pbihNew+1) + (colors * sizeof(RGBQUAD)),
|
||
|
(pbih+1),
|
||
|
lpid->cbIconRes - sizeof(*pbih)
|
||
|
);
|
||
|
|
||
|
pbih = pbihNew;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// reset size
|
||
|
//
|
||
|
size = lpid->cbIconRes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hIcon = CreateIconFromResource((PBYTE)pbih, size, TRUE, dwVer);
|
||
|
if (pbihNew != NULL)
|
||
|
LocalFree(pbihNew);
|
||
|
}
|
||
|
|
||
|
if (!hIcon) {
|
||
|
if (h = FindResource(hAppInstance, (LPTSTR) MAKEINTRESOURCE(ITEMICON), RT_GROUP_ICON)) {
|
||
|
h = LoadResource(hAppInstance, h);
|
||
|
p = LockResource(h);
|
||
|
id = LookupIconIdFromDirectory(p, TRUE);
|
||
|
UnlockResource(h);
|
||
|
FreeResource(h);
|
||
|
}
|
||
|
if (h = FindResource(hAppInstance, (LPTSTR) MAKEINTRESOURCE(id), (LPTSTR) MAKEINTRESOURCE(RT_ICON))) {
|
||
|
cb = SizeofResource(hAppInstance, h);
|
||
|
h = LoadResource(hAppInstance, h);
|
||
|
p = LockResource(h);
|
||
|
hIcon = CreateIconFromResource(p, cb, TRUE, 0x00030000);
|
||
|
UnlockResource(h);
|
||
|
FreeResource(h);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
UnlockGroup(hwnd);
|
||
|
return hIcon;
|
||
|
}
|
||
|
|
||
|
|
||
|
COLORREF PASCAL GetTitleTextColor(VOID)
|
||
|
{
|
||
|
COLORREF color;
|
||
|
|
||
|
color = GetSysColor(COLOR_WINDOW);
|
||
|
if (((WORD)LOBYTE(LOWORD(color)) +
|
||
|
(WORD)HIBYTE(LOWORD(color)) +
|
||
|
(WORD)LOBYTE(HIWORD(color))) >= 3*127)
|
||
|
{
|
||
|
return RGB(0,0,0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return RGB(255,255,255);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define REVERSEPAINT
|
||
|
|
||
|
/*-------------------------------------------------------------------------*/
|
||
|
/*-------------------------------------------------------------------------*/
|
||
|
|
||
|
|
||
|
void NEAR PASCAL ReverseGroupList(PGROUP pGroup)
|
||
|
{
|
||
|
PITEM pitem, p1, p2;
|
||
|
|
||
|
for (p1 = pGroup->pItems, p2 = p1->pNext, p1->pNext = NULL; p2; ) {
|
||
|
pitem = p2->pNext;
|
||
|
p2->pNext = p1;
|
||
|
p1 = p2;
|
||
|
p2 = pitem;
|
||
|
}
|
||
|
pGroup->pItems = p1;
|
||
|
}
|
||
|
|
||
|
VOID PASCAL PaintGroup(HWND hwnd)
|
||
|
{
|
||
|
register HDC hdc;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pitem;
|
||
|
PAINTSTRUCT ps;
|
||
|
LPGROUPDEF lpgd;
|
||
|
LPITEMDEF lpid;
|
||
|
int fontheight;
|
||
|
HBRUSH hbrTitle;
|
||
|
HFONT hFontT;
|
||
|
RECT rcWin;
|
||
|
TEXTMETRIC tm;
|
||
|
|
||
|
HDC hdcMem;
|
||
|
HBITMAP hbmTemp;
|
||
|
HBRUSH hbr, hbrTemp;
|
||
|
INT nMax;
|
||
|
HICON hIcon;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
|
||
|
hdc = BeginPaint(hwnd, &ps);
|
||
|
if (!pGroup->pItems) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
GetClientRect(hwnd, &rcWin);
|
||
|
#ifdef WEIRDBUG
|
||
|
/* DavidPe - 05/15/91
|
||
|
* For some reason RectVisible() will return FALSE in
|
||
|
* situations it shouldn't. Since this is only a
|
||
|
* performance optimization, we can ignore the problem
|
||
|
* for now.
|
||
|
*/
|
||
|
if (!RectVisible(hdc, &rcWin))
|
||
|
goto Exit;
|
||
|
#endif
|
||
|
|
||
|
if (!(lpgd = LockGroup(hwnd)))
|
||
|
goto Exit;
|
||
|
|
||
|
hFontT = SelectObject(hdc, hFontTitle);
|
||
|
|
||
|
GetTextMetrics(hdc, &tm);
|
||
|
|
||
|
// ToddB: This seems like a good point, I don't see why tmExternalLeading should ever
|
||
|
// need to be considered. The result of decreasing the FontHeight is that DrawText
|
||
|
// will be used instead of TextOut in some cases, which should be harmless but might
|
||
|
// effect the apearence of some single line icon titles.
|
||
|
|
||
|
//#ifdef JAPAN
|
||
|
// Why we should think about ExternalLeading though we calculate the
|
||
|
// title rectange by DrawText() without DT_EXTERNALLEADING. -YN
|
||
|
fontheight = tm.tmHeight;
|
||
|
//#else
|
||
|
// fontheight = tm.tmHeight + tm.tmExternalLeading;
|
||
|
//#endif
|
||
|
|
||
|
SetBkMode(hdc, TRANSPARENT);
|
||
|
SetTextColor(hdc, GetTitleTextColor());
|
||
|
hbrTitle = NULL;
|
||
|
|
||
|
hdcMem = CreateCompatibleDC(hdc);
|
||
|
if (!hdcMem)
|
||
|
goto BitmapSetupComplete;
|
||
|
|
||
|
if (pGroup->hbm) {
|
||
|
hbmTemp = SelectObject(hdcMem, pGroup->hbm);
|
||
|
if (hbmTemp)
|
||
|
goto BitmapSetupComplete;
|
||
|
else
|
||
|
DeleteObject(pGroup->hbm);
|
||
|
}
|
||
|
|
||
|
for (nMax = 1, pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
|
||
|
if (nMax <= pitem->iItem)
|
||
|
nMax = pitem->iItem + 1;
|
||
|
}
|
||
|
|
||
|
pGroup->hbm = CreateDiscardableBitmap(hdc, cxIcon*lpgd->cItems, cyIcon);
|
||
|
if (!pGroup->hbm)
|
||
|
goto NukeMemDC;
|
||
|
|
||
|
hbmTemp = SelectObject(hdcMem, pGroup->hbm);
|
||
|
if (!hbmTemp)
|
||
|
goto NukeBitmap;
|
||
|
|
||
|
hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
||
|
if (!hbr)
|
||
|
goto NukeBitmap;
|
||
|
|
||
|
hbrTemp = SelectObject(hdcMem, hbr);
|
||
|
if (!hbrTemp)
|
||
|
goto NukeBrush;
|
||
|
|
||
|
PatBlt(hdcMem, 0, 0, cxIcon * lpgd->cItems, cyIcon, PATCOPY);
|
||
|
SelectObject(hdcMem, hbrTemp);
|
||
|
DeleteObject(hbr);
|
||
|
|
||
|
for (pitem = pGroup->pItems; pitem != NULL; pitem = pitem->pNext) {
|
||
|
if (hIcon = GetItemIcon(hwnd, pitem)) {
|
||
|
DrawIcon(hdcMem, pitem->iItem * cxIcon, 0, hIcon);
|
||
|
DestroyIcon(hIcon);
|
||
|
} else {
|
||
|
goto DeselectAndNukeBitmap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
goto BitmapSetupComplete;
|
||
|
|
||
|
NukeBrush:
|
||
|
DeleteObject(hbr);
|
||
|
|
||
|
DeselectAndNukeBitmap:
|
||
|
SelectObject(hdcMem, hbmTemp);
|
||
|
|
||
|
NukeBitmap:
|
||
|
DeleteObject(pGroup->hbm);
|
||
|
pGroup->hbm = NULL;
|
||
|
|
||
|
NukeMemDC:
|
||
|
DeleteDC(hdcMem);
|
||
|
hdcMem = NULL;
|
||
|
|
||
|
BitmapSetupComplete:
|
||
|
|
||
|
ReverseGroupList(pGroup); // reverse the icon list
|
||
|
|
||
|
/* Paint the icons */
|
||
|
for (pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
|
||
|
if (!pitem->pNext
|
||
|
&& pGroup == pCurrentGroup
|
||
|
&& hwndProgman == GetActiveWindow()) {
|
||
|
hbrTitle = (HANDLE)1; // Use it as a flag
|
||
|
}
|
||
|
else
|
||
|
hbrTitle = (HANDLE)0;
|
||
|
|
||
|
lpid = ITEM(lpgd,pitem->iItem);
|
||
|
|
||
|
if (!bMove || !hbrTitle) {
|
||
|
if (hdcMem) {
|
||
|
BitBlt(hdc, pitem->rcIcon.left + cxOffset,
|
||
|
pitem->rcIcon.top + cyOffset,
|
||
|
lpgd->cxIcon, lpgd->cyIcon, hdcMem,
|
||
|
lpgd->cxIcon*pitem->iItem, 0,
|
||
|
SRCCOPY);
|
||
|
}
|
||
|
else {
|
||
|
if (RectVisible(hdc,&pitem->rcIcon)) {
|
||
|
if (hIcon = GetItemIcon(hwnd,pitem)) {
|
||
|
DrawIcon(hdc, pitem->rcIcon.left + cxOffset,
|
||
|
pitem->rcIcon.top + cyOffset, hIcon);
|
||
|
}
|
||
|
else {
|
||
|
PatBlt(hdc,pitem->rcIcon.left + cxOffset,
|
||
|
pitem->rcIcon.top + cyOffset,
|
||
|
cxIcon, cyIcon, BLACKNESS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Paint the titles. */
|
||
|
for (pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
|
||
|
/* test for the active icon */
|
||
|
|
||
|
if (!pitem->pNext
|
||
|
&& pGroup == pCurrentGroup
|
||
|
&& hwndProgman == GetActiveWindow()) {
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
|
||
|
hbrTitle = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
|
||
|
}
|
||
|
else {
|
||
|
hbrTitle = (HANDLE)0;
|
||
|
}
|
||
|
|
||
|
lpid = ITEM(lpgd,pitem->iItem);
|
||
|
|
||
|
if (!bMove || !hbrTitle) {
|
||
|
if (hbrTitle)
|
||
|
FillRect(hdc, &(pitem->rcTitle), hbrTitle);
|
||
|
|
||
|
/* draw multi line titles like USER does */
|
||
|
|
||
|
if (pitem->rcTitle.bottom - pitem->rcTitle.top < fontheight*2)
|
||
|
TextOut(hdc, pitem->rcTitle.left+cxOffset, pitem->rcTitle.top,
|
||
|
(LPTSTR) PTR(lpgd, lpid->pName), lstrlen((LPTSTR) PTR(lpgd, lpid->pName)));
|
||
|
else {
|
||
|
if (RectVisible(hdc,&pitem->rcTitle)) {
|
||
|
DrawText(hdc,
|
||
|
(LPTSTR)PTR(lpgd, lpid->pName), -1,
|
||
|
&(pitem->rcTitle),
|
||
|
bIconTitleWrap ?
|
||
|
DT_CENTER | DT_WORDBREAK | DT_NOPREFIX :
|
||
|
DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (hbrTitle) {
|
||
|
SetTextColor(hdc, GetTitleTextColor());
|
||
|
DeleteObject(hbrTitle);
|
||
|
hbrTitle = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReverseGroupList(pGroup); // re-reverse the icon list
|
||
|
|
||
|
if (hFontT) {
|
||
|
SelectObject(hdc, hFontT);
|
||
|
}
|
||
|
|
||
|
if (hdcMem) {
|
||
|
SelectObject(hdcMem, hbmTemp);
|
||
|
DeleteDC(hdcMem);
|
||
|
}
|
||
|
|
||
|
UnlockGroup(hwnd);
|
||
|
|
||
|
Exit:
|
||
|
SetBkMode(hdc, OPAQUE);
|
||
|
EndPaint(hwnd, &ps);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
ProfStop();
|
||
|
{
|
||
|
TCHAR buf[80];
|
||
|
wsprintf(buf, TEXT("msec to paint group = %ld\r\n"), GetTickCount() - dwStartTime);
|
||
|
OutputDebugString(buf);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* Draw the group icon. */
|
||
|
/* */
|
||
|
/*-------------------------------------------------------------------------*/
|
||
|
VOID DrawGroupIcon(HWND hwnd)
|
||
|
{
|
||
|
PAINTSTRUCT ps;
|
||
|
HDC hDC;
|
||
|
PGROUP pGroup;
|
||
|
|
||
|
hDC = BeginPaint(hwnd, &ps);
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
if (pGroup->fCommon) {
|
||
|
DrawIcon(hDC, cxOffset, cyOffset, hCommonGrpIcon);
|
||
|
}
|
||
|
else {
|
||
|
DrawIcon(hDC, cxOffset, cyOffset, hGroupIcon);
|
||
|
}
|
||
|
EndPaint(hwnd, &ps);
|
||
|
}
|
||
|
|
||
|
|
||
|
PITEM PASCAL ItemHitTest(
|
||
|
PGROUP pGroup,
|
||
|
POINTS pts)
|
||
|
{
|
||
|
PITEM pItem;
|
||
|
POINT pt;
|
||
|
|
||
|
pt.x = (int)pts.x;
|
||
|
pt.y = (int)pts.y;
|
||
|
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
|
||
|
if (PtInRect(&pItem->rcIcon, pt) || PtInRect(&pItem->rcTitle, pt)) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pItem;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRGN PASCAL IconExcludedRgn(PGROUP pGroup, PITEM pItem)
|
||
|
{
|
||
|
RECT rc;
|
||
|
PITEM pItemT;
|
||
|
HRGN hrgn, hrgnT;
|
||
|
|
||
|
hrgn = CreateRectRgn(0,0,0,0);
|
||
|
|
||
|
if (!hrgn)
|
||
|
return NULL;
|
||
|
|
||
|
hrgnT = CreateRectRgn(0,0,0,0);
|
||
|
if (!hrgnT)
|
||
|
{
|
||
|
return hrgn;
|
||
|
}
|
||
|
|
||
|
for (pItemT = pGroup->pItems;
|
||
|
pItemT && pItemT != pItem;
|
||
|
pItemT = pItemT->pNext)
|
||
|
{
|
||
|
if (IntersectRect(&rc,&pItem->rcIcon,&pItemT->rcIcon))
|
||
|
{
|
||
|
SetRectRgn(hrgnT,rc.left,rc.top,rc.right,rc.bottom);
|
||
|
CombineRgn(hrgn,hrgn,hrgnT,RGN_OR);
|
||
|
}
|
||
|
if (IntersectRect(&rc,&pItem->rcIcon,&pItemT->rcTitle))
|
||
|
{
|
||
|
SetRectRgn(hrgnT,rc.left,rc.top,rc.right,rc.bottom);
|
||
|
CombineRgn(hrgn,hrgn,hrgnT,RGN_OR);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DeleteObject(hrgnT);
|
||
|
|
||
|
return hrgn;
|
||
|
}
|
||
|
|
||
|
VOID APIENTRY InvalidateIcon(PGROUP pGroup, PITEM pItem)
|
||
|
{
|
||
|
RECT rc;
|
||
|
|
||
|
if (!pGroup || !pItem)
|
||
|
return;
|
||
|
UnionRect(&rc, &pItem->rcIcon, &pItem->rcTitle);
|
||
|
if (bAutoArranging)
|
||
|
UnionRect(&rcArrangeRect, &rcArrangeRect, &rc);
|
||
|
else
|
||
|
InvalidateRect(pGroup->hwnd,&rc,TRUE);
|
||
|
}
|
||
|
|
||
|
VOID PASCAL BringItemToTop(PGROUP pGroup, PITEM pItem, BOOL fUpdate)
|
||
|
{
|
||
|
PITEM pItemT;
|
||
|
HRGN hrgn;
|
||
|
|
||
|
if (pItem == pGroup->pItems) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (hrgn = IconExcludedRgn(pGroup, pItem)) {
|
||
|
InvalidateRgn(pGroup->hwnd, hrgn, TRUE);
|
||
|
DeleteObject(hrgn);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* At this point we know there is at least two items, and we're not the
|
||
|
* first one...
|
||
|
*/
|
||
|
|
||
|
for (pItemT = pGroup->pItems; pItemT->pNext != pItem; pItemT = pItemT->pNext)
|
||
|
;
|
||
|
|
||
|
pItemT->pNext = pItem->pNext;
|
||
|
pItem->pNext = pGroup->pItems;
|
||
|
pGroup->pItems = pItem;
|
||
|
|
||
|
/*
|
||
|
* Invalidate the whole titles in order to change the color.
|
||
|
*/
|
||
|
if (fUpdate) {
|
||
|
InvalidateRect(pGroup->hwnd, &pItem->rcTitle, TRUE);
|
||
|
InvalidateRect(pGroup->hwnd, &pItem->pNext->rcTitle, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID PASCAL ClickOn(HWND hwnd, POINTS pts)
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem;
|
||
|
POINT pt;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
|
||
|
pItem = ItemHitTest(pGroup, pts);
|
||
|
if (!pItem) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BringItemToTop(pGroup, pItem, TRUE);
|
||
|
ViewActiveItem(pGroup);
|
||
|
|
||
|
pt.x = (int)pts.x;
|
||
|
pt.y = (int)pts.y;
|
||
|
|
||
|
*(LPPOINT)&rcDrag.left = pt;
|
||
|
*(LPPOINT)&rcDrag.right = pt;
|
||
|
hwndDrag = hwnd;
|
||
|
|
||
|
InflateRect(&rcDrag, GetSystemMetrics(SM_CXDOUBLECLK) / 2,
|
||
|
GetSystemMetrics(SM_CYDOUBLECLK) / 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID PASCAL DragItem(HWND hwnd)
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem;
|
||
|
HICON hIcon;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
pItem = pGroup->pItems;
|
||
|
|
||
|
if (!pItem || hwndDrag != hwnd)
|
||
|
goto ProcExit;
|
||
|
|
||
|
/* If the control key isn't down, do a Move operation. */
|
||
|
bMove = !(GetKeyState(VK_CONTROL) & 0x8000);
|
||
|
|
||
|
/* Don't allow "moves" from RO groups. */
|
||
|
if (pGroup->fRO && bMove == TRUE)
|
||
|
goto ProcExit;
|
||
|
|
||
|
/*
|
||
|
* Redraw the window minus the item we're moving.
|
||
|
* REVIEW - if you just painted the background colour into the
|
||
|
* pItem->rcIcon area then you could remove the bMove code from
|
||
|
* PaintGroup().
|
||
|
*/
|
||
|
if (bMove) {
|
||
|
InvalidateIcon(pGroup,pItem);
|
||
|
UpdateWindow(hwnd);
|
||
|
}
|
||
|
|
||
|
hIcon = GetItemIcon(hwnd,pItem);
|
||
|
|
||
|
// BUG BUG MAKELONG(pGroup,pItem) doesn't make sense since all
|
||
|
// pointers all LOMG in WIN32. Will need to change the parameters!
|
||
|
// johannec 08-19-91
|
||
|
if (DragObject(hwndMDIClient, hwnd, (UINT)OBJ_ITEM,
|
||
|
MAKELONG(pGroup,pItem), hIcon) == DRAG_COPY) {
|
||
|
if (bMove)
|
||
|
DeleteItem(pGroup,pItem);
|
||
|
}
|
||
|
else {
|
||
|
/* Drag was SWP or drag failed... just show the item. */
|
||
|
if (bMove) {
|
||
|
bMove = FALSE;
|
||
|
InvalidateIcon(pGroup,pItem);
|
||
|
}
|
||
|
}
|
||
|
DestroyIcon(hIcon);
|
||
|
ProcExit:
|
||
|
bMove = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void PASCAL GetRealClientRect(
|
||
|
HWND hwnd,
|
||
|
DWORD dwStyle,
|
||
|
LPRECT lprcClient)
|
||
|
{
|
||
|
DWORD Style;
|
||
|
|
||
|
Style = GetWindowLong(hwnd, GWL_STYLE);
|
||
|
|
||
|
/*BUG BUG will GWL_STYLE work???*/
|
||
|
|
||
|
SetWindowLong(hwnd,GWL_STYLE,dwStyle);
|
||
|
GetWindowRect(hwnd,lprcClient);
|
||
|
ScreenToClient(hwnd,(LPPOINT)&lprcClient->left);
|
||
|
ScreenToClient(hwnd,(LPPOINT)&lprcClient->right);
|
||
|
SendMessage(hwnd,WM_NCCALCSIZE,0,(LPARAM)lprcClient);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID APIENTRY CalcGroupScrolls(HWND hwnd)
|
||
|
{
|
||
|
register PGROUP pGroup;
|
||
|
register PITEM pItem;
|
||
|
RECT rcClient;
|
||
|
RECT rcRange;
|
||
|
RECT rcT;
|
||
|
DWORD dwStyle, dwStyleNew, dwStyleT;
|
||
|
int iMinPos, iMaxPos;
|
||
|
|
||
|
if (bNoScrollCalc || IsIconic(hwnd))
|
||
|
return;
|
||
|
|
||
|
// Stop re-entrance of this routine.
|
||
|
bNoScrollCalc = TRUE;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (!pGroup->pItems) {
|
||
|
// No items...
|
||
|
SetRectEmpty(&rcRange);
|
||
|
goto ChangeStyle;
|
||
|
}
|
||
|
|
||
|
hwndScrolling = hwnd;
|
||
|
|
||
|
// If the user has selected auto arranging then make
|
||
|
// the next item in the z-order visable.
|
||
|
if (bAutoArrange)
|
||
|
ViewActiveItem(pGroup);
|
||
|
|
||
|
SetRectEmpty(&rcRange);
|
||
|
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
|
||
|
{
|
||
|
UnionRect(&rcRange,&rcRange,&pItem->rcIcon);
|
||
|
rcT.top = pItem->rcTitle.top; // don't include the
|
||
|
rcT.bottom = pItem->rcTitle.bottom; // title overhang part
|
||
|
rcT.left = pItem->rcIcon.left;
|
||
|
rcT.right = pItem->rcIcon.right;
|
||
|
UnionRect(&rcRange,&rcRange,&rcT);
|
||
|
}
|
||
|
|
||
|
if (rcRange.left != rcRange.right)
|
||
|
{
|
||
|
// Add on a bit for the left border here.
|
||
|
rcRange.left -= ((cxArrange-cxIconSpace)/2)+cxOffset;
|
||
|
// Don't add on a right border so we can cram as many icons in as poss.
|
||
|
// rcRange.right += ((cxArrange-cxIconSpace)/2);
|
||
|
|
||
|
// ADJUST THE RECT SO THAT WE DON'T GET SCROLL BARS IF ONLY THE BORDERS
|
||
|
// OF TEXT ARE NOT VISIBLE ~~~
|
||
|
}
|
||
|
|
||
|
ChangeStyle:
|
||
|
|
||
|
dwStyleNew = dwStyle = GetWindowLong(hwnd,GWL_STYLE);
|
||
|
|
||
|
dwStyleNew &= ~(WS_HSCROLL | WS_VSCROLL);
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
dwStyleT = dwStyleNew;
|
||
|
GetRealClientRect(hwnd, dwStyleNew, &rcClient);
|
||
|
|
||
|
if (rcRange.left < rcClient.left || rcRange.right > rcClient.right)
|
||
|
dwStyleNew |= WS_HSCROLL;
|
||
|
if (rcRange.top < rcClient.top || rcRange.bottom > rcClient.bottom)
|
||
|
dwStyleNew |= WS_VSCROLL;
|
||
|
|
||
|
if (dwStyleNew == dwStyleT)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (dwStyleNew == dwStyle && !(dwStyle & (WS_VSCROLL|WS_HSCROLL)))
|
||
|
{
|
||
|
/* none there and don't need to add 'em!
|
||
|
*/
|
||
|
goto ProcExit;
|
||
|
}
|
||
|
|
||
|
UnionRect(&rcRange,&rcClient,&rcRange);
|
||
|
|
||
|
/* union garantees that left==right or top==bottom in case of no
|
||
|
* scrollbar.
|
||
|
*/
|
||
|
rcRange.right -= rcClient.right-rcClient.left;
|
||
|
rcRange.bottom -= rcClient.bottom-rcClient.top;
|
||
|
|
||
|
/* if the style changed, don't redraw in sb code, just redraw the
|
||
|
* frame at the end cause the whole ncarea has to be repainted
|
||
|
* if it hasn't changed, just move the thumb
|
||
|
*/
|
||
|
|
||
|
if (dwStyleNew==dwStyle)
|
||
|
{
|
||
|
if (dwStyleNew & WS_HSCROLL)
|
||
|
{
|
||
|
if (GetScrollPos(hwnd,SB_HORZ)!=0)
|
||
|
goto SetScrollInfo;
|
||
|
GetScrollRange(hwnd,SB_HORZ,&iMinPos,&iMaxPos);
|
||
|
if ((iMinPos != rcRange.left) || (iMaxPos != rcRange.right))
|
||
|
goto SetScrollInfo;
|
||
|
}
|
||
|
if (dwStyleNew & WS_VSCROLL)
|
||
|
{
|
||
|
if (GetScrollPos(hwnd,SB_VERT)!=0)
|
||
|
goto SetScrollInfo;
|
||
|
GetScrollRange(hwnd,SB_VERT,&iMinPos,&iMaxPos);
|
||
|
if ((iMinPos != rcRange.top) || (iMaxPos != rcRange.bottom))
|
||
|
goto SetScrollInfo;
|
||
|
}
|
||
|
goto ProcExit;
|
||
|
}
|
||
|
|
||
|
SetScrollInfo:
|
||
|
SetScrollPos(hwnd,SB_HORZ,0,FALSE);
|
||
|
SetScrollPos(hwnd,SB_VERT,0,FALSE);
|
||
|
SetScrollRange(hwnd,SB_HORZ,rcRange.left,rcRange.right,FALSE);
|
||
|
SetScrollRange(hwnd,SB_VERT,rcRange.top,rcRange.bottom,FALSE);
|
||
|
|
||
|
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE
|
||
|
| SWP_NOMOVE | SWP_NOACTIVATE
|
||
|
| SWP_DRAWFRAME);
|
||
|
ProcExit:
|
||
|
// Allow other scroll calculations.
|
||
|
bNoScrollCalc = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID PASCAL ScrollGroup(PGROUP pGroup, int xMove, int yMove, BOOL fCalc)
|
||
|
{
|
||
|
register PITEM pItem;
|
||
|
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
|
||
|
{
|
||
|
OffsetRect(&pItem->rcIcon,xMove,yMove);
|
||
|
OffsetRect(&pItem->rcTitle,xMove,yMove);
|
||
|
}
|
||
|
ScrollWindow(pGroup->hwnd,xMove,yMove,NULL,NULL);
|
||
|
|
||
|
UpdateWindow(pGroup->hwnd);
|
||
|
|
||
|
if (fCalc)
|
||
|
CalcGroupScrolls(pGroup->hwnd);
|
||
|
}
|
||
|
|
||
|
VOID APIENTRY ViewActiveItem(PGROUP pGroup)
|
||
|
{
|
||
|
RECT rcClient, rc;
|
||
|
int xMove = 0, yMove = 0;
|
||
|
|
||
|
GetClientRect(pGroup->hwnd,&rcClient);
|
||
|
|
||
|
UnionRect(&rc, &pGroup->pItems->rcIcon, &pGroup->pItems->rcTitle);
|
||
|
// Clip width to that of icon i.e. ignore width of text.
|
||
|
rc.left = pGroup->pItems->rcIcon.left;
|
||
|
rc.right = pGroup->pItems->rcIcon.right;
|
||
|
|
||
|
|
||
|
if (rc.left < rcClient.left)
|
||
|
xMove = rcClient.left - rc.left;
|
||
|
else if (rc.right > rcClient.right)
|
||
|
xMove = rcClient.right - rc.right;
|
||
|
|
||
|
if (rc.top < rcClient.top)
|
||
|
yMove = rcClient.top - rc.top;
|
||
|
else if (rc.bottom > rcClient.bottom)
|
||
|
yMove = rcClient.bottom - rc.bottom;
|
||
|
|
||
|
if (xMove || yMove)
|
||
|
ScrollGroup(pGroup, xMove, yMove,TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL FAR PASCAL CheckHotKey(WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
HWND hwndT;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem;
|
||
|
|
||
|
switch (wParam)
|
||
|
{
|
||
|
case VK_SHIFT:
|
||
|
case VK_CONTROL:
|
||
|
case VK_MENU:
|
||
|
case VK_RETURN:
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (GetKeyState(VK_SHIFT) < 0) {
|
||
|
// DBG((" + SHIFT"));
|
||
|
wParam |= HK_SHIFT;
|
||
|
}
|
||
|
if (GetKeyState(VK_CONTROL) < 0) {
|
||
|
// DBG((" + CONTROL"));
|
||
|
wParam |= HK_CONTROL;
|
||
|
}
|
||
|
if (GetKeyState(VK_MENU) < 0) {
|
||
|
// DBG((" + ALT"));
|
||
|
wParam |= HK_ALT;
|
||
|
}
|
||
|
if (lParam & F_EXT) {
|
||
|
// DBG((" EXTENDED"));
|
||
|
wParam |= HK_EXT;
|
||
|
}
|
||
|
|
||
|
// DBG(("... Full code %4.4X...\r\n",wParam));
|
||
|
|
||
|
for (hwndT = GetWindow(hwndMDIClient,GW_CHILD);
|
||
|
hwndT;
|
||
|
hwndT = GetWindow(hwndT,GW_HWNDNEXT)) {
|
||
|
if (GetWindow(hwndT,GW_OWNER))
|
||
|
continue;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwndT,GWLP_PGROUP);
|
||
|
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
|
||
|
// DBG(("Checking (%4.4X,%4.4X)...\r\n",pGroup,pItem));
|
||
|
if (GroupFlag(pGroup,pItem,(WORD)ID_HOTKEY) == (WORD)wParam) {
|
||
|
// DBG(("F*O*U*N*D\r\n"));
|
||
|
ExecItem(pGroup,pItem,FALSE,FALSE);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID APIENTRY KeyWindow(HWND hwnd, WORD wDirection)
|
||
|
{
|
||
|
int wT;
|
||
|
int wNext;
|
||
|
RECT rc;
|
||
|
RECT rcT;
|
||
|
POINT ptA;
|
||
|
POINT ptT;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem, pItemNext;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (!pGroup->pItems)
|
||
|
return;
|
||
|
|
||
|
wNext = 0x7FFF;
|
||
|
pItemNext = NULL;
|
||
|
CopyRect(&rc,&pGroup->pItems->rcIcon);
|
||
|
|
||
|
for (pItem = pGroup->pItems->pNext; pItem; pItem = pItem->pNext) {
|
||
|
CopyRect(&rcT,&pItem->rcIcon);
|
||
|
ptT.x = rcT.left - rc.left;
|
||
|
ptT.y = rcT.top - rc.top;
|
||
|
ptA.x = (ptT.x < 0) ? -ptT.x : ptT.x;
|
||
|
ptA.y = (ptT.y < 0) ? -ptT.y : ptT.y;
|
||
|
|
||
|
switch (wDirection) {
|
||
|
case VK_LEFT:
|
||
|
if ((ptT.x >= 0) || (ptA.x < ptA.y))
|
||
|
continue;
|
||
|
break;
|
||
|
|
||
|
case VK_RIGHT:
|
||
|
if ((ptT.x <= 0) || (ptA.x < ptA.y))
|
||
|
continue;
|
||
|
break;
|
||
|
|
||
|
case VK_DOWN:
|
||
|
if ((ptT.y <= 0) || (ptA.y < ptA.x))
|
||
|
continue;
|
||
|
break;
|
||
|
|
||
|
case VK_UP:
|
||
|
if ((ptT.y >= 0) || (ptA.y < ptA.x))
|
||
|
continue;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
/* illegal key
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
wT = ptA.y + ptA.x;
|
||
|
|
||
|
if (wT <= wNext) {
|
||
|
wNext = wT;
|
||
|
pItemNext = pItem;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pItemNext) {
|
||
|
BringItemToTop(pGroup,pItemNext, TRUE);
|
||
|
ViewActiveItem(pGroup);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID APIENTRY CharWindow(register HWND hwnd, register WORD wChar)
|
||
|
{
|
||
|
LPGROUPDEF lpgd;
|
||
|
LPITEMDEF lpid;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem, pItemLast;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (!pGroup->pItems)
|
||
|
return;
|
||
|
|
||
|
lpgd = LockGroup(hwnd);
|
||
|
if (!lpgd)
|
||
|
return;
|
||
|
|
||
|
/* Search for item, skip the currently selected one.*/
|
||
|
for ( pItem = pGroup->pItems->pNext; pItem; pItem=pItem->pNext)
|
||
|
{
|
||
|
lpid = ITEM(lpgd,pItem->iItem);
|
||
|
if (CharUpper((LPTSTR)(DWORD_PTR)wChar)
|
||
|
== CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*PTR(lpgd, lpid->pName)))
|
||
|
{
|
||
|
pItemLast = MakeFirstItemLast(pGroup);
|
||
|
BringItemToTop(pGroup,pItem, FALSE);
|
||
|
/* Handle updates.*/
|
||
|
InvalidateRect(pGroup->hwnd,&pItem->rcTitle,TRUE);
|
||
|
InvalidateRect(pGroup->hwnd,&pItemLast->rcTitle,TRUE);
|
||
|
ViewActiveItem(pGroup);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
UnlockGroup(hwnd);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID APIENTRY ScrollMessage(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
int wMin;
|
||
|
int wMax;
|
||
|
int wPos;
|
||
|
int wInc;
|
||
|
int wPage;
|
||
|
int wNewPos;
|
||
|
RECT rcClient;
|
||
|
int yMove;
|
||
|
int xMove;
|
||
|
BOOL fTemp;
|
||
|
|
||
|
GetClientRect(hwnd, &rcClient);
|
||
|
|
||
|
if (uiMsg == WM_HSCROLL) {
|
||
|
GetScrollRange(hwnd, SB_HORZ, &wMin, &wMax);
|
||
|
wPos = GetScrollPos(hwnd, SB_HORZ);
|
||
|
wInc = cxIconSpace + cxArrange / 2;
|
||
|
wPage = rcClient.right-rcClient.left;
|
||
|
}
|
||
|
else {
|
||
|
GetScrollRange(hwnd, SB_VERT, &wMin, &wMax);
|
||
|
wPos = GetScrollPos(hwnd, SB_VERT);
|
||
|
wInc = cyArrange;
|
||
|
wPage = rcClient.bottom-rcClient.top;
|
||
|
}
|
||
|
|
||
|
switch (GET_WM_VSCROLL_CODE(wParam, lParam)) {
|
||
|
case SB_BOTTOM:
|
||
|
wNewPos = wMax;
|
||
|
break;
|
||
|
|
||
|
case SB_TOP:
|
||
|
wNewPos = wMin;
|
||
|
break;
|
||
|
|
||
|
case SB_LINEDOWN:
|
||
|
wNewPos = wPos + wInc;
|
||
|
break;
|
||
|
|
||
|
case SB_LINEUP:
|
||
|
wNewPos = wPos - wInc;
|
||
|
break;
|
||
|
|
||
|
case SB_PAGEDOWN:
|
||
|
wNewPos = wPos + wPage;
|
||
|
break;
|
||
|
|
||
|
case SB_PAGEUP:
|
||
|
wNewPos = wPos - wPage;
|
||
|
break;
|
||
|
|
||
|
case SB_THUMBTRACK:
|
||
|
case SB_THUMBPOSITION:
|
||
|
wNewPos = (INT)(SHORT)GET_WM_VSCROLL_POS(wParam, lParam);
|
||
|
break;
|
||
|
|
||
|
case SB_ENDSCROLL:
|
||
|
// We might suddenly not need the scroll bars anymore so
|
||
|
// check now.
|
||
|
// Stop CGS from moving the view.
|
||
|
fTemp = bAutoArrange;
|
||
|
bAutoArrange = FALSE;
|
||
|
CalcGroupScrolls(hwnd);
|
||
|
bAutoArrange = fTemp;
|
||
|
|
||
|
/*** FALL THRU ***/
|
||
|
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (wNewPos < wMin)
|
||
|
wNewPos = wMin;
|
||
|
else if (wNewPos > wMax)
|
||
|
wNewPos = wMax;
|
||
|
|
||
|
if (uiMsg == WM_VSCROLL) {
|
||
|
SetScrollPos(hwnd, SB_VERT, wNewPos, TRUE);
|
||
|
yMove = wPos - wNewPos;
|
||
|
xMove = 0;
|
||
|
}
|
||
|
else {
|
||
|
SetScrollPos(hwnd, SB_HORZ, wNewPos, TRUE);
|
||
|
yMove = 0;
|
||
|
xMove = wPos - wNewPos;
|
||
|
}
|
||
|
|
||
|
ScrollGroup((PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP),xMove,yMove,FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID PASCAL OfficialRect(
|
||
|
LPRECT lprc,
|
||
|
int x,
|
||
|
int y,
|
||
|
int xOffset,
|
||
|
int yOffset)
|
||
|
{
|
||
|
// Work out were the icon should go in the icon grid, taking
|
||
|
// note of where the scroll bars are.
|
||
|
|
||
|
lprc->right = (lprc->left = x-xOffset + (cxIconSpace - cxArrange) / 2) +
|
||
|
cxArrange - 1;
|
||
|
lprc->bottom = (lprc->top = y-yOffset) + cyArrange - 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL PASCAL IconOverlaps(
|
||
|
PGROUP pGroup,
|
||
|
LPRECT lprc,
|
||
|
int xOffset,
|
||
|
int yOffset)
|
||
|
{
|
||
|
PITEM pItem;
|
||
|
RECT rcT;
|
||
|
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
|
||
|
// Ignore icons at -1. This is where icon's get put when
|
||
|
// we don't know where to put them and they will get moved
|
||
|
// later.
|
||
|
if (pItem->rcIcon.left == -1) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
OfficialRect(&rcT, pItem->rcIcon.left, pItem->rcIcon.top, xOffset, yOffset);
|
||
|
if (IntersectRect(&rcT, &rcT, lprc)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* NB This is called for every icon at init time so put anything to do with
|
||
|
* finding icon positions inside the `if' because that's skipped on init.
|
||
|
* If you don't it'll get tres slow.
|
||
|
*/
|
||
|
|
||
|
VOID PASCAL ComputeIconPosition(
|
||
|
PGROUP pGroup,
|
||
|
POINT pt,
|
||
|
LPRECT lprcIcon,
|
||
|
LPRECT lprcTitle,
|
||
|
LPTSTR lpText)
|
||
|
{
|
||
|
HDC hdc;
|
||
|
int cch;
|
||
|
RECT rcClient, rcT;
|
||
|
HFONT hFontT;
|
||
|
int xsp, ysp; // Current position of scrollbar.
|
||
|
int vMax, vMin; // Range.
|
||
|
int hMax, hMin; // Range.
|
||
|
int xOffset, yOffset;
|
||
|
DWORD dwStyle;
|
||
|
|
||
|
if (pt.x == -1) {
|
||
|
/*
|
||
|
* Icon is in "find me a default position" mode...
|
||
|
* so search the icon space for it...
|
||
|
*/
|
||
|
// Get the current window style.
|
||
|
dwStyle = GetWindowLong(pGroup->hwnd,GWL_STYLE);
|
||
|
|
||
|
if (dwStyle & WS_MINIMIZE) {
|
||
|
// DBG(("PM.CIP: Window Minimised\n\r"));
|
||
|
// We want to use the restored state of the window.
|
||
|
GetInternalWindowPos(pGroup->hwnd, &rcClient, NULL);
|
||
|
// Convert from screen coords to client coords.
|
||
|
OffsetRect(&rcClient, -rcClient.left, -rcClient.top);
|
||
|
}
|
||
|
else {
|
||
|
// DBG(("PM.CIP: Window normal or maxed.\n\r"));
|
||
|
// Take into account scroll bars.
|
||
|
GetClientRect(pGroup->hwnd, &rcClient);
|
||
|
}
|
||
|
|
||
|
if (dwStyle & WS_HSCROLL) {
|
||
|
xsp = GetScrollPos(pGroup->hwnd, SB_HORZ);
|
||
|
GetScrollRange(pGroup->hwnd, SB_HORZ, &hMin, &hMax);
|
||
|
xOffset = xsp-hMin; // Offset icon grid to match scroll bar pos.
|
||
|
}
|
||
|
else {
|
||
|
xOffset = 0;
|
||
|
}
|
||
|
|
||
|
if (dwStyle & WS_VSCROLL) {
|
||
|
ysp = GetScrollPos(pGroup->hwnd, SB_VERT);
|
||
|
GetScrollRange(pGroup->hwnd, SB_VERT, &vMin, &vMax);
|
||
|
yOffset = ysp-vMin; // Offset icon grid.
|
||
|
}
|
||
|
else {
|
||
|
yOffset = 0;
|
||
|
}
|
||
|
|
||
|
pt.x = (cxArrange - cxIconSpace) / 2 + cxOffset - xOffset;
|
||
|
pt.y = 0 - yOffset;
|
||
|
/* Set this icon's left to -1 so that it'll be excluded
|
||
|
* by the IconOverlaps check.
|
||
|
*/
|
||
|
lprcIcon->left = -1;
|
||
|
|
||
|
for (;;) {
|
||
|
OfficialRect(&rcT, pt.x, pt.y, xOffset, yOffset);
|
||
|
|
||
|
if (!IconOverlaps(pGroup, &rcT, xOffset, yOffset)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (rcT.right + cxArrange > rcClient.right) {
|
||
|
pt.x = (cxArrange-cxIconSpace)/2 + cxOffset - xOffset;
|
||
|
pt.y += cyArrange;
|
||
|
}
|
||
|
else {
|
||
|
pt.x += cxArrange;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetRect(lprcIcon, pt.x, pt.y, pt.x+cxIconSpace, pt.y+cyIconSpace);
|
||
|
|
||
|
if (IsRectEmpty(lprcTitle)) {
|
||
|
cch = lstrlen(lpText);
|
||
|
|
||
|
hdc = GetDC(pGroup->hwnd);
|
||
|
hFontT = SelectObject(hdc, hFontTitle);
|
||
|
|
||
|
/*
|
||
|
* Compute the icon rect using DrawText.
|
||
|
*/
|
||
|
lprcTitle->right = cxArrange - (2 * cxOffset);
|
||
|
DrawText(hdc, lpText, -1, lprcTitle, bIconTitleWrap ?
|
||
|
(WORD)(DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX) :
|
||
|
(WORD)(DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE));
|
||
|
|
||
|
if (hFontT) {
|
||
|
SelectObject(hdc, hFontT);
|
||
|
}
|
||
|
ReleaseDC(pGroup->hwnd, hdc);
|
||
|
lprcTitle->right += cxOffset * 2;
|
||
|
lprcTitle->bottom += dyBorder * 2;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
SetRect(lprcTitle, 0, 0, lprcTitle->right - lprcTitle->left,
|
||
|
lprcTitle->bottom - lprcTitle->top);
|
||
|
}
|
||
|
|
||
|
|
||
|
OffsetRect(lprcTitle, pt.x+(cxIconSpace/2)-((lprcTitle->right-lprcTitle->left)/2),
|
||
|
pt.y + cyIconSpace - dyBorder);
|
||
|
|
||
|
// REVIEW Very expensive to do this here.
|
||
|
// if ((bAutoArrange) && (!bAutoArranging))
|
||
|
// ArrangeItems(pGroup->hwnd);
|
||
|
}
|
||
|
|
||
|
VOID APIENTRY MoveItem(PGROUP pGroup, PITEM pItem, POINT pt)
|
||
|
{
|
||
|
LPITEMDEF lpid;
|
||
|
LPGROUPDEF lpgd;
|
||
|
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
|
||
|
/*
|
||
|
* If the position is the same, ignore
|
||
|
*/
|
||
|
if ((pt.x == pItem->rcIcon.left) && (pt.y == pItem->rcIcon.top)) {
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Repaint the original position
|
||
|
*/
|
||
|
InvalidateIcon(pGroup, pItem);
|
||
|
|
||
|
lpid = LockItem(pGroup,pItem);
|
||
|
if (!lpid) {
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ComputeIconPosition(pGroup, pt, &pItem->rcIcon, &pItem->rcTitle,
|
||
|
(LPTSTR) PTR(lpgd, lpid->pName));
|
||
|
|
||
|
|
||
|
UnlockGroup(pGroup->hwnd);
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
|
||
|
/*
|
||
|
* Repaint the new position
|
||
|
*/
|
||
|
InvalidateIcon(pGroup,pItem);
|
||
|
|
||
|
// CalcGroupScrolls(pGroup->hwnd);
|
||
|
}
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DropObject() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
LONG NEAR PASCAL DropObject(HWND hWnd, LPDROPSTRUCT lpds)
|
||
|
{
|
||
|
BOOL fNC;
|
||
|
BOOL fOk;
|
||
|
POINT pt;
|
||
|
LPPOINT lppt;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem;
|
||
|
RECT rcClient;
|
||
|
|
||
|
pGroup = pCurrentGroup;
|
||
|
pItem = pGroup->pItems;
|
||
|
|
||
|
pt = lpds->ptDrop;
|
||
|
|
||
|
// A drop anywhere in the window is valid.
|
||
|
GetWindowRect(hWnd, &rcClient);
|
||
|
// Convert to client coords.
|
||
|
ScreenToClient(hWnd,(LPPOINT)&(rcClient.left));
|
||
|
ScreenToClient(hWnd,(LPPOINT)&(rcClient.right));
|
||
|
|
||
|
if (pt.x >= rcClient.left && pt.y >= rcClient.top && pt.x <= rcClient.right
|
||
|
&& pt.y <= rcClient.bottom) {
|
||
|
/* Dropped in given point of client area. */
|
||
|
fNC = FALSE;
|
||
|
pt.x -= (GetSystemMetrics(SM_CXICON) / 2) + 2;
|
||
|
pt.y -= (GetSystemMetrics(SM_CYICON) / 2) + 2;
|
||
|
lppt = &pt;
|
||
|
}
|
||
|
else {
|
||
|
/* Dropped in nonclient area. */
|
||
|
fNC = TRUE;
|
||
|
lppt = NULL;
|
||
|
}
|
||
|
|
||
|
/* Are we iconic ? */
|
||
|
if (IsIconic(hWnd)) {
|
||
|
// Yep, we'll need to use default positioning.
|
||
|
fNC = TRUE;
|
||
|
lppt = NULL;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// this if statement code if obsolete, it is never called. - johannec 8/11/93
|
||
|
if (lpds->wFmt == DOF_EXECUTABLE || lpds->wFmt == DOF_DOCUMENT) {
|
||
|
|
||
|
BuildDescription(szNameField, szPathName);
|
||
|
|
||
|
return((LONG)(CreateNewItem(hWnd,
|
||
|
szNameField, szPathName, szPathName, TEXT(""),
|
||
|
0, FALSE, 0, 0, NULL, lppt, CI_SET_DOS_FULLSCRN) != NULL));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ((hWnd == pGroup->hwnd) && (bMove)) {
|
||
|
/* Don't drop on our own non-client area. */
|
||
|
if (fNC)
|
||
|
return 0L;
|
||
|
|
||
|
/* We are just moving the item within its own group.
|
||
|
* Hide it first so the icon title is treated correctly.
|
||
|
*/
|
||
|
MoveItem(pGroup,pItem, pt);
|
||
|
if ((bAutoArrange) && (!bAutoArranging))
|
||
|
ArrangeItems(pGroup->hwnd);
|
||
|
else if (!bAutoArranging)
|
||
|
CalcGroupScrolls(pGroup->hwnd);
|
||
|
|
||
|
return(DRAG_SWP);
|
||
|
}
|
||
|
else {
|
||
|
/* Copy the item to the new group... Set the hourglass
|
||
|
* cursor (it will get unset after the message returns),
|
||
|
* select the new group, and add the item at the specified
|
||
|
* point.
|
||
|
*/
|
||
|
fOk = DuplicateItem(pGroup,pItem,
|
||
|
(PGROUP)GetWindowLongPtr(hWnd,GWLP_PGROUP),lppt) != NULL;
|
||
|
|
||
|
/*
|
||
|
* Re-Arrange items within the destination group.
|
||
|
* NB The source will been taken care of by the DeleteItem routine
|
||
|
* called from DragItem.
|
||
|
*/
|
||
|
if ((bAutoArrange) && (!bAutoArranging)) {
|
||
|
/* Destination */
|
||
|
ArrangeItems(hWnd);
|
||
|
}
|
||
|
else if (!bAutoArranging) {
|
||
|
/* Destination */
|
||
|
CalcGroupScrolls(hWnd);
|
||
|
}
|
||
|
|
||
|
/* View the current item. */
|
||
|
BringItemToTop(pGroup,pItem, TRUE);
|
||
|
ViewActiveItem(pGroup);
|
||
|
|
||
|
/* If the dest isn't minimised then move the focus to it. */
|
||
|
if (!IsIconic(hWnd))
|
||
|
SetFocus(hWnd);
|
||
|
return (fOk ? DRAG_COPY : 0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LONG APIENTRY DropFiles(HWND hwnd, HANDLE hDrop)
|
||
|
{
|
||
|
POINT pt;
|
||
|
LPPOINT lppt;
|
||
|
UINT i;
|
||
|
HCURSOR hCursor;
|
||
|
DWORD dwRet;
|
||
|
DWORD dwFlags = CI_ACTIVATE | CI_SET_DOS_FULLSCRN;
|
||
|
|
||
|
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
||
|
ShowCursor(TRUE);
|
||
|
|
||
|
if (!DragQueryPoint(hDrop, &pt) ||
|
||
|
DragQueryFile(hDrop, (UINT)-1, NULL, 0) != 1) {
|
||
|
lppt = NULL;
|
||
|
}
|
||
|
else {
|
||
|
pt.x -= (GetSystemMetrics(SM_CXICON) / 2) + 2;
|
||
|
pt.y -= (GetSystemMetrics(SM_CYICON) / 2) + 2;
|
||
|
lppt = &pt;
|
||
|
}
|
||
|
|
||
|
for (i=0; DragQueryFile(hDrop, i, szPathField, MAXITEMPATHLEN); i++) {
|
||
|
//
|
||
|
// if filename or directory have spaces, put the path
|
||
|
// between quotes.
|
||
|
//
|
||
|
CheckEscapes(szPathField, MAXITEMPATHLEN+1);
|
||
|
|
||
|
/* Verify the file's existance... */
|
||
|
dwRet = ValidatePath(hwndProgman, szPathField, NULL, szIconPath);
|
||
|
if (dwRet == PATH_INVALID) {
|
||
|
continue;
|
||
|
}
|
||
|
else if (dwRet == PATH_INVALID_OK) {
|
||
|
dwFlags |= CI_NO_ASSOCIATION;
|
||
|
}
|
||
|
|
||
|
BuildDescription(szNameField,szPathField);
|
||
|
|
||
|
GetDirectoryFromPath(szPathField, szDirField);
|
||
|
if (!InQuotes(szDirField)) {
|
||
|
CheckEscapes(szDirField, MAXITEMPATHLEN+1);
|
||
|
}
|
||
|
|
||
|
HandleDosApps(szIconPath);
|
||
|
|
||
|
if (!CreateNewItem(hwnd,
|
||
|
szNameField, /* name*/
|
||
|
szPathField, /* command*/
|
||
|
szIconPath , /* icon path*/
|
||
|
szDirField, /* no default dir*/
|
||
|
0,0, /* no hotkey, no min on run*/
|
||
|
0,0,0, /* default icon*/
|
||
|
lppt, /* at this point*/
|
||
|
dwFlags))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DragFinish(hDrop);
|
||
|
|
||
|
ShowCursor(FALSE);
|
||
|
SetCursor(hCursor);
|
||
|
|
||
|
if ((bAutoArrange) && (!bAutoArranging))
|
||
|
ArrangeItems(hwnd);
|
||
|
else if (!bAutoArranging)
|
||
|
CalcGroupScrolls(hwnd);
|
||
|
|
||
|
return 1L;
|
||
|
}
|
||
|
|
||
|
LRESULT APIENTRY GroupWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
POINT pt;
|
||
|
|
||
|
switch (uiMsg) {
|
||
|
|
||
|
case WM_CREATE:
|
||
|
{
|
||
|
LPMDICREATESTRUCT lpmdics;
|
||
|
|
||
|
lpmdics = (LPMDICREATESTRUCT)(((LPCREATESTRUCT)lParam)->lpCreateParams);
|
||
|
SetWindowLongPtr(hwnd, GWLP_PGROUP, lpmdics->lParam);
|
||
|
DragAcceptFiles(hwnd,TRUE);
|
||
|
SetFocus(hwnd);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WM_ERASEBKGND:
|
||
|
if (IsIconic(hwnd)) {
|
||
|
//
|
||
|
// Erase background with the APPWORKSPACE color
|
||
|
//
|
||
|
RECT rc;
|
||
|
|
||
|
if (!hbrWorkspace)
|
||
|
hbrWorkspace = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE));
|
||
|
GetUpdateRect(hwnd, &rc, FALSE);
|
||
|
if (IsRectEmpty(&rc)) {
|
||
|
GetClientRect(hwnd, &rc);
|
||
|
}
|
||
|
FillRect((HDC)wParam, &rc, hbrWorkspace);
|
||
|
}
|
||
|
else {
|
||
|
goto DefProc;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
if (IsIconic(hwnd)) {
|
||
|
DrawGroupIcon(hwnd);
|
||
|
}
|
||
|
else {
|
||
|
PaintGroup(hwnd);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYDRAGICON:
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
HICON hIcon = NULL;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
|
||
|
if (pGroup->fCommon) {
|
||
|
hIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(COMMGROUPICON));
|
||
|
}
|
||
|
else {
|
||
|
hIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PERSGROUPICON));
|
||
|
}
|
||
|
|
||
|
if (hIcon) {
|
||
|
return((LRESULT)hIcon);
|
||
|
}
|
||
|
else {
|
||
|
goto DefProc;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WM_LBUTTONDOWN:
|
||
|
ClickOn(hwnd, MAKEPOINTS(lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_MOUSEMOVE:
|
||
|
if (wParam & MK_LBUTTON) {
|
||
|
pt.x = (int)(MAKEPOINTS(lParam).x);
|
||
|
pt.y = (int)(MAKEPOINTS(lParam).y);
|
||
|
if (!IsRectEmpty(&rcDrag) && !PtInRect(&rcDrag, pt)
|
||
|
&& !fNoFileMenu && (dwEditLevel < 2)) {
|
||
|
SetRect(&rcDrag,0,0,0,0);
|
||
|
DragItem(hwnd);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
SetRect(&rcDrag,0,0,0,0);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONUP:
|
||
|
SetRect(&rcDrag,0,0,0,0);
|
||
|
break;
|
||
|
|
||
|
case WM_NCLBUTTONDBLCLK:
|
||
|
if (IsIconic(hwnd) && (GetKeyState(VK_MENU) < 0)) {
|
||
|
PostMessage(hwndProgman, WM_COMMAND, IDM_PROPS, 0L);
|
||
|
} else {
|
||
|
goto DefProc;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONDBLCLK:
|
||
|
|
||
|
if (ItemHitTest((PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP),
|
||
|
MAKEPOINTS(lParam))) {
|
||
|
if (GetKeyState(VK_MENU) < 0) {
|
||
|
if (!fNoFileMenu)
|
||
|
PostMessage(hwndProgman,WM_COMMAND,IDM_PROPS,0L);
|
||
|
} else {
|
||
|
PostMessage(hwndProgman,WM_COMMAND,IDM_OPEN,0L);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
/*
|
||
|
* Check for Alt-dblclk on nothing to get new item.
|
||
|
*/
|
||
|
if (GetKeyState(VK_MENU) < 0 && !fNoFileMenu &&
|
||
|
(dwEditLevel <= 1) && !(pCurrentGroup->fRO) ) {
|
||
|
MyDialogBox(ITEMDLG, hwndProgman, NewItemDlgProc);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_VSCROLL:
|
||
|
case WM_HSCROLL:
|
||
|
ScrollMessage(hwnd,uiMsg,wParam,lParam);
|
||
|
break;
|
||
|
|
||
|
case WM_CLOSE:
|
||
|
SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0L);
|
||
|
break;
|
||
|
|
||
|
case WM_SYSCOMMAND:
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
LPGROUPDEF lpgd;
|
||
|
TCHAR szCommonGroupSuffix[MAXKEYLEN];
|
||
|
TCHAR szCommonGroupTitle[2*MAXKEYLEN];
|
||
|
|
||
|
if (wParam == SC_MINIMIZE) {
|
||
|
//
|
||
|
// if the group is common remove the common suffix from the group
|
||
|
// window title
|
||
|
//
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
if (pGroup->fCommon) {
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
SetWindowText(hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (wParam == SC_RESTORE) {
|
||
|
if (!LockGroup(hwnd)) {
|
||
|
if (wLockError == LOCK_LOWMEM) {
|
||
|
MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_LOWMEM, NULL, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
/*
|
||
|
* Lock failed for some other reason - hopefully just
|
||
|
* a group change. Stop the icon group from being
|
||
|
* restored.
|
||
|
*/
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
UnlockGroup(hwnd);
|
||
|
}
|
||
|
}
|
||
|
if ((wParam == SC_MAXIMIZE) || (wParam == SC_RESTORE)) {
|
||
|
//
|
||
|
// if the group is common add the common suffix to the group
|
||
|
// window title
|
||
|
//
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
if (pGroup->fCommon) {
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
|
||
|
if (!lpgd)
|
||
|
goto DefProc;
|
||
|
|
||
|
lstrcpy(szCommonGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName));
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
|
||
|
CharSizeOf(szCommonGroupSuffix))) {
|
||
|
lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
|
||
|
}
|
||
|
SetWindowText(pGroup->hwnd, szCommonGroupTitle);
|
||
|
}
|
||
|
InvalidateRect(hwnd, NULL, 0);
|
||
|
}
|
||
|
if (wParam == SC_MAXIMIZE)
|
||
|
SetWindowLong(hwnd, GWL_STYLE,
|
||
|
(GetWindowLong(hwnd,GWL_STYLE) & ~(WS_HSCROLL | WS_VSCROLL)));
|
||
|
goto DefProc;
|
||
|
|
||
|
}
|
||
|
case WM_SYSKEYDOWN:
|
||
|
if (!CheckHotKey(wParam,lParam))
|
||
|
goto DefProc;
|
||
|
break;
|
||
|
|
||
|
case WM_KEYDOWN:
|
||
|
if (!CheckHotKey(wParam,lParam))
|
||
|
KeyWindow(hwnd,(WORD)wParam);
|
||
|
break;
|
||
|
|
||
|
//IME Support
|
||
|
//by yutakas 1992.10.22
|
||
|
// When user input DBCS, go and activate icon which has that
|
||
|
// DBCS charcter in the first of description.
|
||
|
case WM_IME_REPORT:
|
||
|
switch (wParam)
|
||
|
{
|
||
|
case IR_STRING:
|
||
|
IMEStringWindow(hwnd,(HANDLE)lParam);
|
||
|
return TRUE;
|
||
|
default:
|
||
|
goto DefProc;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_CHAR:
|
||
|
CharWindow(hwnd, (WORD) wParam);
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYDROPOBJECT:
|
||
|
{
|
||
|
#define lpds ((LPDROPSTRUCT)lParam)
|
||
|
|
||
|
PGROUP pGroup;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (pGroup->fRO) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (lpds->wFmt == OBJ_ITEM) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
#undef lpds
|
||
|
goto DefProc;
|
||
|
}
|
||
|
|
||
|
case WM_DROPOBJECT:
|
||
|
#define lpds ((LPDROPSTRUCT)lParam)
|
||
|
|
||
|
if (lpds->wFmt == OBJ_ITEM)
|
||
|
return DropObject(hwnd, lpds);
|
||
|
#undef lpds
|
||
|
goto DefProc;
|
||
|
|
||
|
case WM_DROPFILES:
|
||
|
return DropFiles(hwnd,(HANDLE)wParam);
|
||
|
|
||
|
case WM_NCACTIVATE:
|
||
|
{
|
||
|
PGROUP pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (pGroup->pItems != NULL) {
|
||
|
InvalidateRect(hwnd,&pGroup->pItems->rcTitle,TRUE);
|
||
|
}
|
||
|
goto DefProc;
|
||
|
}
|
||
|
|
||
|
case WM_QUERYOPEN:
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
LPGROUPDEF lpgd;
|
||
|
TCHAR szCommonGroupSuffix[MAXKEYLEN];
|
||
|
TCHAR szCommonGroupTitle[2*MAXKEYLEN];
|
||
|
|
||
|
//
|
||
|
// if the group is common add the common suffix to the group
|
||
|
// window title
|
||
|
//
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
if (pGroup->fCommon) {
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
|
||
|
if (!lpgd)
|
||
|
goto DefProc;
|
||
|
|
||
|
lstrcpy(szCommonGroupTitle,(LPTSTR) PTR(lpgd, lpgd->pName));
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
|
||
|
CharSizeOf(szCommonGroupSuffix))) {
|
||
|
lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
|
||
|
}
|
||
|
SetWindowText(pGroup->hwnd, szCommonGroupTitle);
|
||
|
}
|
||
|
goto DefProc;
|
||
|
}
|
||
|
|
||
|
case WM_SIZE:
|
||
|
lParam = DefMDIChildProc(hwnd, uiMsg, wParam, lParam);
|
||
|
if (wParam != SIZEICONIC) {
|
||
|
if ((bAutoArrange) && (!bAutoArranging)) {
|
||
|
ArrangeItems(hwnd);
|
||
|
} else if (!bArranging) {
|
||
|
CalcGroupScrolls(hwnd);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
PGROUP pGroup;
|
||
|
LPGROUPDEF lpgd;
|
||
|
|
||
|
//
|
||
|
// reset window text of common groups
|
||
|
//
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
|
||
|
if (pGroup->fCommon) {
|
||
|
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
|
||
|
SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
|
||
|
GlobalUnlock(pGroup->hGroup);
|
||
|
}
|
||
|
}
|
||
|
return lParam;
|
||
|
|
||
|
case WM_MDIACTIVATE:
|
||
|
if (!pCurrentGroup) {
|
||
|
goto DefProc;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If we are de-activating this window...
|
||
|
*/
|
||
|
if (lParam == 0) {
|
||
|
/*
|
||
|
* We're the last window... punt.
|
||
|
*/
|
||
|
pCurrentGroup = NULL;
|
||
|
|
||
|
} else if (hwnd == (HWND)wParam) {
|
||
|
/*
|
||
|
* We're being deactivated. Update pCurrentGroup
|
||
|
* to the node being activated.
|
||
|
*/
|
||
|
pCurrentGroup = (PGROUP)GetWindowLongPtr((HWND)lParam, GWLP_PGROUP);
|
||
|
|
||
|
} else {
|
||
|
SetFocus(hwnd);
|
||
|
}
|
||
|
|
||
|
goto DefProc;
|
||
|
|
||
|
case WM_MENUSELECT:
|
||
|
//
|
||
|
// to handle F1 on group window system menu
|
||
|
//
|
||
|
|
||
|
if (lParam) { /*make sure menu handle isn't null*/
|
||
|
wMenuID = GET_WM_COMMAND_ID(wParam, lParam); /*get cmd from loword of wParam*/
|
||
|
hSaveMenuHandle = (HANDLE)lParam; /*Save hMenu into one variable*/
|
||
|
wSaveFlags = HIWORD(wParam);/*Save flags into another*/
|
||
|
bFrameSysMenu = FALSE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DefProc:
|
||
|
return DefMDIChildProc(hwnd, uiMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ArrangeItems() - */
|
||
|
/* */
|
||
|
/* Arranges iconic windows within a group. */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID FAR PASCAL ArrangeItems(HWND hwnd)
|
||
|
{
|
||
|
PGROUP pGroup;
|
||
|
register PITEM pItem;
|
||
|
PITEM pItemT;
|
||
|
int xSlots;
|
||
|
register int i;
|
||
|
int j,k;
|
||
|
RECT rc;
|
||
|
LPGROUPDEF lpgd;
|
||
|
PITEM rgpitem[CITEMSMAX];
|
||
|
POINT pt;
|
||
|
int t1, t2;
|
||
|
LONG style;
|
||
|
|
||
|
if (bAutoArranging || IsIconic(hwnd))
|
||
|
return;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
if (!pGroup)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* If the group is RO then don't rearrange the items, just update the
|
||
|
* scroll bars
|
||
|
*/
|
||
|
if (!GroupCheck(pGroup)) {
|
||
|
CalcGroupScrolls(hwnd);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bAutoArranging = TRUE;
|
||
|
SetRectEmpty(&rcArrangeRect);
|
||
|
|
||
|
style = GetWindowLong(hwnd,GWL_STYLE);
|
||
|
GetRealClientRect(hwnd,style&~(WS_VSCROLL|WS_HSCROLL),&rc);
|
||
|
SetWindowLong(hwnd,GWL_STYLE,style);
|
||
|
|
||
|
xSlots = (rc.right - rc.left)/cxArrange;
|
||
|
if (xSlots < 1)
|
||
|
xSlots = 1;
|
||
|
|
||
|
/* sort the items by x location within a row, or by row if the
|
||
|
* rows are different
|
||
|
*/
|
||
|
k = 0;
|
||
|
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
|
||
|
/* find nearest row
|
||
|
*/
|
||
|
t1 = pItem->rcIcon.top + cyArrange/2;
|
||
|
if (t1 >= 0)
|
||
|
t1 -= t1 % cyArrange;
|
||
|
else
|
||
|
t1 += t1 % cyArrange;
|
||
|
|
||
|
for (i = 0; i < k; i++) {
|
||
|
pItemT = rgpitem[i];
|
||
|
|
||
|
t2 = pItemT->rcIcon.top + cyArrange/2;
|
||
|
if (t2 >= 0)
|
||
|
t2 -= t2 % cyArrange;
|
||
|
else
|
||
|
t2 += t2 % cyArrange;
|
||
|
|
||
|
if (t2 > t1)
|
||
|
break;
|
||
|
else if (t2 == t1 && pItemT->rcIcon.left > pItem->rcIcon.left)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (j = k; j > i; j--) {
|
||
|
rgpitem[j] = rgpitem[j-1];
|
||
|
}
|
||
|
|
||
|
rgpitem[i] = pItem;
|
||
|
|
||
|
k++;
|
||
|
}
|
||
|
|
||
|
lpgd = LockGroup(hwnd);
|
||
|
if (!lpgd) {
|
||
|
bAutoArranging = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bNoScrollCalc = TRUE;
|
||
|
for (i = 0; i < k; i++) {
|
||
|
pItem = rgpitem[i];
|
||
|
|
||
|
/* cxOffset necessary to match (buggy???) win 3 USER
|
||
|
*/
|
||
|
pt.x = (i%xSlots)*cxArrange + (cxArrange-cxIconSpace)/2 + cxOffset;
|
||
|
pt.y = (i/xSlots)*cyArrange;
|
||
|
|
||
|
MoveItem(pGroup,pItem,pt);
|
||
|
}
|
||
|
|
||
|
if (!IsRectEmpty(&rcArrangeRect))
|
||
|
InvalidateRect(pGroup->hwnd,&rcArrangeRect,TRUE);
|
||
|
|
||
|
UnlockGroup(hwnd);
|
||
|
bNoScrollCalc = FALSE;
|
||
|
CalcGroupScrolls(hwnd);
|
||
|
|
||
|
bAutoArranging = FALSE;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IMEStringWindow(hwnd,hstr)
|
||
|
*
|
||
|
* Change activate item by the strings come from IME.
|
||
|
* When Get WM_IME_REPORT with IR_STRING,this function is called.
|
||
|
*
|
||
|
* by yutakas 1992.10.22
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL FAR PASCAL IMEStringWindow(HWND hwnd, HANDLE hStr)
|
||
|
{
|
||
|
LPTSTR lpStr;
|
||
|
LPGROUPDEF lpgd;
|
||
|
LPITEMDEF lpid;
|
||
|
PGROUP pGroup;
|
||
|
PITEM pItem = NULL;
|
||
|
PITEM pItemLast,pTItem;
|
||
|
int nCnt = 0;
|
||
|
int nTCnt = 0;
|
||
|
BOOL ret = FALSE;
|
||
|
|
||
|
if (!hStr)
|
||
|
return ret;
|
||
|
|
||
|
if (!(lpStr = GlobalLock(hStr)))
|
||
|
return ret;
|
||
|
|
||
|
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
|
||
|
|
||
|
if (!pGroup->pItems)
|
||
|
return ret;
|
||
|
|
||
|
lpgd = LockGroup(hwnd);
|
||
|
if (!lpgd)
|
||
|
return ret;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
{
|
||
|
TCHAR szDev[80];
|
||
|
OutputDebugString((LPTSTR)TEXT("In IME Winsdow\r\n"));
|
||
|
wsprintf ((LPTSTR)szDev,TEXT("IMEStringWindow: lpStr is %s \r\n"),lpStr);
|
||
|
OutputDebugString((LPSTR)szDev);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Search for item, skip the currently selected one.
|
||
|
for ( pTItem = pGroup->pItems->pNext; pTItem; pTItem=pTItem->pNext)
|
||
|
{
|
||
|
lpid = ITEM(lpgd,pTItem->iItem);
|
||
|
nTCnt = IMEWindowGetCnt(lpStr,(LPTSTR)PTR(lpgd,lpid->pName));
|
||
|
if (nCnt < nTCnt)
|
||
|
{
|
||
|
nCnt = nTCnt;
|
||
|
pItem = pTItem;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lpid = ITEM(lpgd,pGroup->pItems->iItem);
|
||
|
nTCnt = IMEWindowGetCnt(lpStr,(LPTSTR)PTR(lpgd,lpid->pName));
|
||
|
|
||
|
if ((nCnt >= nTCnt) && pItem)
|
||
|
{
|
||
|
pItemLast = MakeFirstItemLast(pGroup);
|
||
|
BringItemToTop(pGroup,pItem, FALSE);
|
||
|
// Handle updates.
|
||
|
InvalidateRect(pGroup->hwnd,&pItem->rcTitle,TRUE);
|
||
|
InvalidateRect(pGroup->hwnd,&pItemLast->rcTitle,TRUE);
|
||
|
ViewActiveItem(pGroup);
|
||
|
ret = TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
GlobalUnlock(hStr);
|
||
|
UnlockGroup(hwnd);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
{
|
||
|
TCHAR szDev[80];
|
||
|
wsprintf ((LPTSTR)szDev,TEXT("IMEStringWindow: ret is %s \r\n"),ret);
|
||
|
OutputDebugString((LPTSTR)szDev);
|
||
|
}
|
||
|
#endif
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IMEWindowGetCnt(LPSTR,LPSTR)
|
||
|
*
|
||
|
* Compare strings from ahead and return the number of same character
|
||
|
*
|
||
|
* by yutakas 1992.10.22
|
||
|
*
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
int FAR PASCAL IMEWindowGetCnt(LPTSTR lp1, LPTSTR lp2)
|
||
|
{
|
||
|
int cnt = 0;
|
||
|
|
||
|
while (*lp1 && *lp2)
|
||
|
{
|
||
|
// ToddB: This typecasting is to prevent lp1 and lp2 from being modified
|
||
|
// by CharUpper'ing one char at a time instead of the whole string
|
||
|
if (CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*lp1) ==
|
||
|
CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*lp2))
|
||
|
{
|
||
|
cnt++;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
|
||
|
lp1++;
|
||
|
lp2++;
|
||
|
}
|
||
|
|
||
|
return (*lp1 ? 0 : cnt);
|
||
|
}
|