|
|
#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); }
|