Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2151 lines
58 KiB

  1. #include "progman.h"
  2. #include "ime.h"
  3. BOOL FAR PASCAL IMEStringWindow(HWND,HANDLE);
  4. int FAR PASCAL IMEWindowGetCnt(LPTSTR,LPTSTR);
  5. #define HK_SHIFT 0x0100
  6. #define HK_CONTROL 0x0200
  7. #define HK_ALT 0x0400
  8. #define HK_EXT 0x0800
  9. #define F_EXT 0x01000000L
  10. #define OBJ_ITEM 1
  11. BOOL bNoScrollCalc = FALSE;
  12. RECT rcArrangeRect;
  13. HWND hwndScrolling = NULL;
  14. BOOL APIENTRY InQuotes(LPTSTR sz);
  15. void NEAR PASCAL ViewActiveItem(PGROUP pGroup);
  16. /* Make the first item in a list the last and return a pointer to it.*/
  17. PITEM PASCAL MakeFirstItemLast(PGROUP pGroup)
  18. {
  19. PITEM pItemCur;
  20. /* Just quit if there's no list.*/
  21. if ((pItemCur = pGroup->pItems) == NULL)
  22. return NULL;
  23. /* Find the end of the list.*/
  24. for( ; pItemCur->pNext ; pItemCur = pItemCur->pNext)
  25. ;
  26. /* End of the list.*/
  27. /* This works even if there is only one item in the */
  28. /* list, it's a waste of time though.*/
  29. pItemCur->pNext = pGroup->pItems;
  30. pGroup->pItems = pGroup->pItems->pNext;
  31. pItemCur->pNext->pNext = NULL;
  32. return pItemCur->pNext;
  33. }
  34. VOID PASCAL GetItemText(PGROUP pGroup, PITEM pItem, LPTSTR lpT, int index)
  35. {
  36. LPITEMDEF lpid;
  37. LPGROUPDEF lpgd;
  38. lpid = LockItem(pGroup,pItem);
  39. if (!lpid) {
  40. UnlockGroup(pGroup->hwnd);
  41. *lpT = 0;
  42. return;
  43. }
  44. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  45. switch (index) {
  46. case 0:
  47. lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pName));
  48. break;
  49. case 1:
  50. lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pCommand));
  51. break;
  52. case 2:
  53. lstrcpy(lpT, (LPTSTR) PTR(lpgd, lpid->pIconPath));
  54. break;
  55. default:
  56. *lpT = 0;
  57. break;
  58. }
  59. GlobalUnlock(pGroup->hGroup);
  60. UnlockGroup(pGroup->hwnd);
  61. }
  62. ULONG Color16Palette[] = {
  63. 0x00000000, 0x00800000, 0x00008000, 0x00808000,
  64. 0x00000080, 0x00800080, 0x00008080, 0x00808080,
  65. 0x00c0c0c0, 0x00ff0000, 0x0000ff00, 0x00ffff00,
  66. 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
  67. };
  68. ULONG Color256Palette[] = {
  69. 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
  70. 0x00c0dcc0, 0x00a6caf0, 0x00cccccc, 0x00580800, 0x00600800, 0x00680800, 0x00700800, 0x00780800,
  71. 0x00801000, 0x00881000, 0x00901000, 0x00981000, 0x00a01000, 0x00a81000, 0x00b01000, 0x00b81000,
  72. 0x00c01800, 0x00c81800, 0x00d01800, 0x00d81800, 0x00e01800, 0x00e81800, 0x00f01800, 0x00f81800,
  73. 0x00002000, 0x00082000, 0x00102000, 0x00182000, 0x00202000, 0x00282000, 0x00302000, 0x00382000,
  74. 0x00402800, 0x00482800, 0x00502800, 0x00582800, 0x00602800, 0x00682800, 0x00702800, 0x00782800,
  75. 0x00803000, 0x00883000, 0x00903000, 0x00983000, 0x00a03000, 0x00a83000, 0x00b03000, 0x00b83000,
  76. 0x00c03800, 0x00c83800, 0x00d03800, 0x00d83800, 0x00e03800, 0x00e83800, 0x00f03800, 0x00f83800,
  77. 0x00004010, 0x00084010, 0x00104010, 0x00184010, 0x00204010, 0x00284010, 0x00304010, 0x00384010,
  78. 0x00404810, 0x00484810, 0x00504810, 0x00584810, 0x00604810, 0x00684810, 0x00704810, 0x00784810,
  79. 0x00805010, 0x00885010, 0x00905010, 0x00985010, 0x00a05010, 0x00a85010, 0x00b05010, 0x00b85010,
  80. 0x00c05810, 0x00c85810, 0x00d05810, 0x00d85810, 0x00e05810, 0x00e85810, 0x00f05810, 0x00f85810,
  81. 0x00006010, 0x00086010, 0x00106010, 0x00186010, 0x00206010, 0x00286010, 0x00306010, 0x00386010,
  82. 0x00406810, 0x00486810, 0x00506810, 0x00586810, 0x00606810, 0x00686810, 0x00706810, 0x00786810,
  83. 0x00807010, 0x00887010, 0x00907010, 0x00987010, 0x00a07010, 0x00a87010, 0x00b07010, 0x00b87010,
  84. 0x00c07810, 0x00c87810, 0x00d07810, 0x00d87810, 0x00e07810, 0x00e87810, 0x00f07810, 0x00f87810,
  85. 0x00008020, 0x00088020, 0x00108020, 0x00188020, 0x00208020, 0x00288020, 0x00308020, 0x00388020,
  86. 0x00408820, 0x00488820, 0x00508820, 0x00588820, 0x00608820, 0x00688820, 0x00708820, 0x00788820,
  87. 0x00809020, 0x00889020, 0x00909020, 0x00989020, 0x00a09020, 0x00a89020, 0x00b09020, 0x00b89020,
  88. 0x00c09820, 0x00c89820, 0x00d09820, 0x00d89820, 0x00e09820, 0x00e89820, 0x00f09820, 0x00f89820,
  89. 0x0000a020, 0x0008a020, 0x0010a020, 0x0018a020, 0x0020a020, 0x0028a020, 0x0030a020, 0x0038a020,
  90. 0x0040a820, 0x0048a820, 0x0050a820, 0x0058a820, 0x0060a820, 0x0068a820, 0x0070a820, 0x0078a820,
  91. 0x0080b020, 0x0088b020, 0x0090b020, 0x0098b020, 0x00a0b020, 0x00a8b020, 0x00b0b020, 0x00b8b020,
  92. 0x00c0b820, 0x00b820c8, 0x00b820d0, 0x00b820d8, 0x00b820e0, 0x00b820e8, 0x00b820f0, 0x00b820f8,
  93. 0x0000c030, 0x00c03008, 0x00c03010, 0x00c03018, 0x00c03020, 0x00c03028, 0x00c03030, 0x00c03038,
  94. 0x0040c830, 0x00c83048, 0x00c83050, 0x00c83058, 0x00c83060, 0x00c83068, 0x00c83070, 0x00c83078,
  95. 0x0080d030, 0x00d03088, 0x00d03090, 0x00d03098, 0x00d030a0, 0x00d030a8, 0x00d030b0, 0x00d030b8,
  96. 0x00c0d830, 0x00c8d830, 0x00d0d830, 0x00d8d830, 0x00e0d830, 0x00e8d830, 0x00f0d830, 0x00f8d830,
  97. 0x0000e030, 0x0008e030, 0x0010e030, 0x0018e030, 0x0020e030, 0x0028e030, 0x0030e030, 0x0038e030,
  98. 0x0040e830, 0x0048e830, 0x0050e830, 0x0058e830, 0x0060e830, 0x0068e830, 0x0070e830, 0x0078e830,
  99. 0x0080f030, 0x0088f030, 0x0090f030, 0x0098f030, 0x00a0f030, 0x00a8f030, 0x00fffbf0, 0x00a0a0a4,
  100. 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00, 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
  101. };
  102. HICON APIENTRY GetItemIcon(HWND hwnd, PITEM pitem)
  103. {
  104. LPGROUPDEF lpgd;
  105. LPITEMDEF lpid;
  106. HICON hIcon = NULL;
  107. DWORD dwVer;
  108. HANDLE h;
  109. LPBYTE p;
  110. INT id = 0;
  111. INT cb;
  112. DWORD colors, size;
  113. PBITMAPINFOHEADER pbih, pbihNew;
  114. LPVOID palette;
  115. lpgd = LockGroup(hwnd);
  116. if (!lpgd)
  117. return DuplicateIcon(hAppInstance, hItemIcon);
  118. //return hItemIcon;
  119. lpid = ITEM(lpgd,pitem->iItem);
  120. if ((SHORT)lpid->cbIconRes > 0) {
  121. if (lpid->wIconVer == 2)
  122. dwVer = 0x00020000;
  123. else
  124. dwVer = 0x00030000;
  125. pbihNew = NULL;
  126. pbih = (PBITMAPINFOHEADER)PTR(lpgd, lpid->pIconRes);
  127. size = lpid->cbIconRes;
  128. if (pbih->biClrUsed == -1) {
  129. colors = (1 << (pbih->biPlanes * pbih->biBitCount));
  130. size += colors * sizeof(RGBQUAD);
  131. if (colors == 16) {
  132. palette = Color16Palette;
  133. } else if (colors == 256) {
  134. palette = Color256Palette;
  135. } else {
  136. palette = NULL;
  137. }
  138. if (palette != NULL)
  139. pbihNew = (PBITMAPINFOHEADER)LocalAlloc(LPTR, size);
  140. if (pbihNew != NULL) {
  141. RtlCopyMemory(pbihNew, pbih, sizeof( *pbih ));
  142. pbihNew->biClrUsed = 0;
  143. RtlCopyMemory((pbihNew+1), palette, colors * sizeof(RGBQUAD));
  144. RtlCopyMemory((PCHAR)(pbihNew+1) + (colors * sizeof(RGBQUAD)),
  145. (pbih+1),
  146. lpid->cbIconRes - sizeof(*pbih)
  147. );
  148. pbih = pbihNew;
  149. }
  150. else {
  151. //
  152. // reset size
  153. //
  154. size = lpid->cbIconRes;
  155. }
  156. }
  157. hIcon = CreateIconFromResource((PBYTE)pbih, size, TRUE, dwVer);
  158. if (pbihNew != NULL)
  159. LocalFree(pbihNew);
  160. }
  161. if (!hIcon) {
  162. if (h = FindResource(hAppInstance, (LPTSTR) MAKEINTRESOURCE(ITEMICON), RT_GROUP_ICON)) {
  163. h = LoadResource(hAppInstance, h);
  164. p = LockResource(h);
  165. id = LookupIconIdFromDirectory(p, TRUE);
  166. UnlockResource(h);
  167. FreeResource(h);
  168. }
  169. if (h = FindResource(hAppInstance, (LPTSTR) MAKEINTRESOURCE(id), (LPTSTR) MAKEINTRESOURCE(RT_ICON))) {
  170. cb = SizeofResource(hAppInstance, h);
  171. h = LoadResource(hAppInstance, h);
  172. p = LockResource(h);
  173. hIcon = CreateIconFromResource(p, cb, TRUE, 0x00030000);
  174. UnlockResource(h);
  175. FreeResource(h);
  176. }
  177. }
  178. UnlockGroup(hwnd);
  179. return hIcon;
  180. }
  181. COLORREF PASCAL GetTitleTextColor(VOID)
  182. {
  183. COLORREF color;
  184. color = GetSysColor(COLOR_WINDOW);
  185. if (((WORD)LOBYTE(LOWORD(color)) +
  186. (WORD)HIBYTE(LOWORD(color)) +
  187. (WORD)LOBYTE(HIWORD(color))) >= 3*127)
  188. {
  189. return RGB(0,0,0);
  190. }
  191. else
  192. {
  193. return RGB(255,255,255);
  194. }
  195. }
  196. #define REVERSEPAINT
  197. /*-------------------------------------------------------------------------*/
  198. /*-------------------------------------------------------------------------*/
  199. void NEAR PASCAL ReverseGroupList(PGROUP pGroup)
  200. {
  201. PITEM pitem, p1, p2;
  202. for (p1 = pGroup->pItems, p2 = p1->pNext, p1->pNext = NULL; p2; ) {
  203. pitem = p2->pNext;
  204. p2->pNext = p1;
  205. p1 = p2;
  206. p2 = pitem;
  207. }
  208. pGroup->pItems = p1;
  209. }
  210. VOID PASCAL PaintGroup(HWND hwnd)
  211. {
  212. register HDC hdc;
  213. PGROUP pGroup;
  214. PITEM pitem;
  215. PAINTSTRUCT ps;
  216. LPGROUPDEF lpgd;
  217. LPITEMDEF lpid;
  218. int fontheight;
  219. HBRUSH hbrTitle;
  220. HFONT hFontT;
  221. RECT rcWin;
  222. TEXTMETRIC tm;
  223. HDC hdcMem;
  224. HBITMAP hbmTemp;
  225. HBRUSH hbr, hbrTemp;
  226. INT nMax;
  227. HICON hIcon;
  228. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  229. hdc = BeginPaint(hwnd, &ps);
  230. if (!pGroup->pItems) {
  231. goto Exit;
  232. }
  233. GetClientRect(hwnd, &rcWin);
  234. #ifdef WEIRDBUG
  235. /* DavidPe - 05/15/91
  236. * For some reason RectVisible() will return FALSE in
  237. * situations it shouldn't. Since this is only a
  238. * performance optimization, we can ignore the problem
  239. * for now.
  240. */
  241. if (!RectVisible(hdc, &rcWin))
  242. goto Exit;
  243. #endif
  244. if (!(lpgd = LockGroup(hwnd)))
  245. goto Exit;
  246. hFontT = SelectObject(hdc, hFontTitle);
  247. GetTextMetrics(hdc, &tm);
  248. // ToddB: This seems like a good point, I don't see why tmExternalLeading should ever
  249. // need to be considered. The result of decreasing the FontHeight is that DrawText
  250. // will be used instead of TextOut in some cases, which should be harmless but might
  251. // effect the apearence of some single line icon titles.
  252. //#ifdef JAPAN
  253. // Why we should think about ExternalLeading though we calculate the
  254. // title rectange by DrawText() without DT_EXTERNALLEADING. -YN
  255. fontheight = tm.tmHeight;
  256. //#else
  257. // fontheight = tm.tmHeight + tm.tmExternalLeading;
  258. //#endif
  259. SetBkMode(hdc, TRANSPARENT);
  260. SetTextColor(hdc, GetTitleTextColor());
  261. hbrTitle = NULL;
  262. hdcMem = CreateCompatibleDC(hdc);
  263. if (!hdcMem)
  264. goto BitmapSetupComplete;
  265. if (pGroup->hbm) {
  266. hbmTemp = SelectObject(hdcMem, pGroup->hbm);
  267. if (hbmTemp)
  268. goto BitmapSetupComplete;
  269. else
  270. DeleteObject(pGroup->hbm);
  271. }
  272. for (nMax = 1, pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
  273. if (nMax <= pitem->iItem)
  274. nMax = pitem->iItem + 1;
  275. }
  276. pGroup->hbm = CreateDiscardableBitmap(hdc, cxIcon*lpgd->cItems, cyIcon);
  277. if (!pGroup->hbm)
  278. goto NukeMemDC;
  279. hbmTemp = SelectObject(hdcMem, pGroup->hbm);
  280. if (!hbmTemp)
  281. goto NukeBitmap;
  282. hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  283. if (!hbr)
  284. goto NukeBitmap;
  285. hbrTemp = SelectObject(hdcMem, hbr);
  286. if (!hbrTemp)
  287. goto NukeBrush;
  288. PatBlt(hdcMem, 0, 0, cxIcon * lpgd->cItems, cyIcon, PATCOPY);
  289. SelectObject(hdcMem, hbrTemp);
  290. DeleteObject(hbr);
  291. for (pitem = pGroup->pItems; pitem != NULL; pitem = pitem->pNext) {
  292. if (hIcon = GetItemIcon(hwnd, pitem)) {
  293. DrawIcon(hdcMem, pitem->iItem * cxIcon, 0, hIcon);
  294. DestroyIcon(hIcon);
  295. } else {
  296. goto DeselectAndNukeBitmap;
  297. }
  298. }
  299. goto BitmapSetupComplete;
  300. NukeBrush:
  301. DeleteObject(hbr);
  302. DeselectAndNukeBitmap:
  303. SelectObject(hdcMem, hbmTemp);
  304. NukeBitmap:
  305. DeleteObject(pGroup->hbm);
  306. pGroup->hbm = NULL;
  307. NukeMemDC:
  308. DeleteDC(hdcMem);
  309. hdcMem = NULL;
  310. BitmapSetupComplete:
  311. ReverseGroupList(pGroup); // reverse the icon list
  312. /* Paint the icons */
  313. for (pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
  314. if (!pitem->pNext
  315. && pGroup == pCurrentGroup
  316. && hwndProgman == GetActiveWindow()) {
  317. hbrTitle = (HANDLE)1; // Use it as a flag
  318. }
  319. else
  320. hbrTitle = (HANDLE)0;
  321. lpid = ITEM(lpgd,pitem->iItem);
  322. if (!bMove || !hbrTitle) {
  323. if (hdcMem) {
  324. BitBlt(hdc, pitem->rcIcon.left + cxOffset,
  325. pitem->rcIcon.top + cyOffset,
  326. lpgd->cxIcon, lpgd->cyIcon, hdcMem,
  327. lpgd->cxIcon*pitem->iItem, 0,
  328. SRCCOPY);
  329. }
  330. else {
  331. if (RectVisible(hdc,&pitem->rcIcon)) {
  332. if (hIcon = GetItemIcon(hwnd,pitem)) {
  333. DrawIcon(hdc, pitem->rcIcon.left + cxOffset,
  334. pitem->rcIcon.top + cyOffset, hIcon);
  335. }
  336. else {
  337. PatBlt(hdc,pitem->rcIcon.left + cxOffset,
  338. pitem->rcIcon.top + cyOffset,
  339. cxIcon, cyIcon, BLACKNESS);
  340. }
  341. }
  342. }
  343. }
  344. }
  345. /* Paint the titles. */
  346. for (pitem = pGroup->pItems; pitem; pitem = pitem->pNext) {
  347. /* test for the active icon */
  348. if (!pitem->pNext
  349. && pGroup == pCurrentGroup
  350. && hwndProgman == GetActiveWindow()) {
  351. SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
  352. hbrTitle = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
  353. }
  354. else {
  355. hbrTitle = (HANDLE)0;
  356. }
  357. lpid = ITEM(lpgd,pitem->iItem);
  358. if (!bMove || !hbrTitle) {
  359. if (hbrTitle)
  360. FillRect(hdc, &(pitem->rcTitle), hbrTitle);
  361. /* draw multi line titles like USER does */
  362. if (pitem->rcTitle.bottom - pitem->rcTitle.top < fontheight*2)
  363. TextOut(hdc, pitem->rcTitle.left+cxOffset, pitem->rcTitle.top,
  364. (LPTSTR) PTR(lpgd, lpid->pName), lstrlen((LPTSTR) PTR(lpgd, lpid->pName)));
  365. else {
  366. if (RectVisible(hdc,&pitem->rcTitle)) {
  367. DrawText(hdc,
  368. (LPTSTR)PTR(lpgd, lpid->pName), -1,
  369. &(pitem->rcTitle),
  370. bIconTitleWrap ?
  371. DT_CENTER | DT_WORDBREAK | DT_NOPREFIX :
  372. DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE);
  373. }
  374. }
  375. }
  376. if (hbrTitle) {
  377. SetTextColor(hdc, GetTitleTextColor());
  378. DeleteObject(hbrTitle);
  379. hbrTitle = NULL;
  380. }
  381. }
  382. ReverseGroupList(pGroup); // re-reverse the icon list
  383. if (hFontT) {
  384. SelectObject(hdc, hFontT);
  385. }
  386. if (hdcMem) {
  387. SelectObject(hdcMem, hbmTemp);
  388. DeleteDC(hdcMem);
  389. }
  390. UnlockGroup(hwnd);
  391. Exit:
  392. SetBkMode(hdc, OPAQUE);
  393. EndPaint(hwnd, &ps);
  394. #ifdef DEBUG
  395. ProfStop();
  396. {
  397. TCHAR buf[80];
  398. wsprintf(buf, TEXT("msec to paint group = %ld\r\n"), GetTickCount() - dwStartTime);
  399. OutputDebugString(buf);
  400. }
  401. #endif
  402. }
  403. /*-------------------------------------------------------------------------*/
  404. /* */
  405. /* Draw the group icon. */
  406. /* */
  407. /*-------------------------------------------------------------------------*/
  408. VOID DrawGroupIcon(HWND hwnd)
  409. {
  410. PAINTSTRUCT ps;
  411. HDC hDC;
  412. PGROUP pGroup;
  413. hDC = BeginPaint(hwnd, &ps);
  414. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  415. if (pGroup->fCommon) {
  416. DrawIcon(hDC, cxOffset, cyOffset, hCommonGrpIcon);
  417. }
  418. else {
  419. DrawIcon(hDC, cxOffset, cyOffset, hGroupIcon);
  420. }
  421. EndPaint(hwnd, &ps);
  422. }
  423. PITEM PASCAL ItemHitTest(
  424. PGROUP pGroup,
  425. POINTS pts)
  426. {
  427. PITEM pItem;
  428. POINT pt;
  429. pt.x = (int)pts.x;
  430. pt.y = (int)pts.y;
  431. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  432. if (PtInRect(&pItem->rcIcon, pt) || PtInRect(&pItem->rcTitle, pt)) {
  433. break;
  434. }
  435. }
  436. return pItem;
  437. }
  438. HRGN PASCAL IconExcludedRgn(PGROUP pGroup, PITEM pItem)
  439. {
  440. RECT rc;
  441. PITEM pItemT;
  442. HRGN hrgn, hrgnT;
  443. hrgn = CreateRectRgn(0,0,0,0);
  444. if (!hrgn)
  445. return NULL;
  446. hrgnT = CreateRectRgn(0,0,0,0);
  447. if (!hrgnT)
  448. {
  449. return hrgn;
  450. }
  451. for (pItemT = pGroup->pItems;
  452. pItemT && pItemT != pItem;
  453. pItemT = pItemT->pNext)
  454. {
  455. if (IntersectRect(&rc,&pItem->rcIcon,&pItemT->rcIcon))
  456. {
  457. SetRectRgn(hrgnT,rc.left,rc.top,rc.right,rc.bottom);
  458. CombineRgn(hrgn,hrgn,hrgnT,RGN_OR);
  459. }
  460. if (IntersectRect(&rc,&pItem->rcIcon,&pItemT->rcTitle))
  461. {
  462. SetRectRgn(hrgnT,rc.left,rc.top,rc.right,rc.bottom);
  463. CombineRgn(hrgn,hrgn,hrgnT,RGN_OR);
  464. }
  465. }
  466. DeleteObject(hrgnT);
  467. return hrgn;
  468. }
  469. VOID APIENTRY InvalidateIcon(PGROUP pGroup, PITEM pItem)
  470. {
  471. RECT rc;
  472. if (!pGroup || !pItem)
  473. return;
  474. UnionRect(&rc, &pItem->rcIcon, &pItem->rcTitle);
  475. if (bAutoArranging)
  476. UnionRect(&rcArrangeRect, &rcArrangeRect, &rc);
  477. else
  478. InvalidateRect(pGroup->hwnd,&rc,TRUE);
  479. }
  480. VOID PASCAL BringItemToTop(PGROUP pGroup, PITEM pItem, BOOL fUpdate)
  481. {
  482. PITEM pItemT;
  483. HRGN hrgn;
  484. if (pItem == pGroup->pItems) {
  485. return;
  486. }
  487. if (hrgn = IconExcludedRgn(pGroup, pItem)) {
  488. InvalidateRgn(pGroup->hwnd, hrgn, TRUE);
  489. DeleteObject(hrgn);
  490. }
  491. /*
  492. * At this point we know there is at least two items, and we're not the
  493. * first one...
  494. */
  495. for (pItemT = pGroup->pItems; pItemT->pNext != pItem; pItemT = pItemT->pNext)
  496. ;
  497. pItemT->pNext = pItem->pNext;
  498. pItem->pNext = pGroup->pItems;
  499. pGroup->pItems = pItem;
  500. /*
  501. * Invalidate the whole titles in order to change the color.
  502. */
  503. if (fUpdate) {
  504. InvalidateRect(pGroup->hwnd, &pItem->rcTitle, TRUE);
  505. InvalidateRect(pGroup->hwnd, &pItem->pNext->rcTitle, TRUE);
  506. }
  507. }
  508. VOID PASCAL ClickOn(HWND hwnd, POINTS pts)
  509. {
  510. PGROUP pGroup;
  511. PITEM pItem;
  512. POINT pt;
  513. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  514. pItem = ItemHitTest(pGroup, pts);
  515. if (!pItem) {
  516. return;
  517. }
  518. BringItemToTop(pGroup, pItem, TRUE);
  519. ViewActiveItem(pGroup);
  520. pt.x = (int)pts.x;
  521. pt.y = (int)pts.y;
  522. *(LPPOINT)&rcDrag.left = pt;
  523. *(LPPOINT)&rcDrag.right = pt;
  524. hwndDrag = hwnd;
  525. InflateRect(&rcDrag, GetSystemMetrics(SM_CXDOUBLECLK) / 2,
  526. GetSystemMetrics(SM_CYDOUBLECLK) / 2);
  527. }
  528. VOID PASCAL DragItem(HWND hwnd)
  529. {
  530. PGROUP pGroup;
  531. PITEM pItem;
  532. HICON hIcon;
  533. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  534. pItem = pGroup->pItems;
  535. if (!pItem || hwndDrag != hwnd)
  536. goto ProcExit;
  537. /* If the control key isn't down, do a Move operation. */
  538. bMove = !(GetKeyState(VK_CONTROL) & 0x8000);
  539. /* Don't allow "moves" from RO groups. */
  540. if (pGroup->fRO && bMove == TRUE)
  541. goto ProcExit;
  542. /*
  543. * Redraw the window minus the item we're moving.
  544. * REVIEW - if you just painted the background colour into the
  545. * pItem->rcIcon area then you could remove the bMove code from
  546. * PaintGroup().
  547. */
  548. if (bMove) {
  549. InvalidateIcon(pGroup,pItem);
  550. UpdateWindow(hwnd);
  551. }
  552. hIcon = GetItemIcon(hwnd,pItem);
  553. // BUG BUG MAKELONG(pGroup,pItem) doesn't make sense since all
  554. // pointers all LOMG in WIN32. Will need to change the parameters!
  555. // johannec 08-19-91
  556. if (DragObject(hwndMDIClient, hwnd, (UINT)OBJ_ITEM,
  557. MAKELONG(pGroup,pItem), hIcon) == DRAG_COPY) {
  558. if (bMove)
  559. DeleteItem(pGroup,pItem);
  560. }
  561. else {
  562. /* Drag was SWP or drag failed... just show the item. */
  563. if (bMove) {
  564. bMove = FALSE;
  565. InvalidateIcon(pGroup,pItem);
  566. }
  567. }
  568. DestroyIcon(hIcon);
  569. ProcExit:
  570. bMove = FALSE;
  571. }
  572. void PASCAL GetRealClientRect(
  573. HWND hwnd,
  574. DWORD dwStyle,
  575. LPRECT lprcClient)
  576. {
  577. DWORD Style;
  578. Style = GetWindowLong(hwnd, GWL_STYLE);
  579. /*BUG BUG will GWL_STYLE work???*/
  580. SetWindowLong(hwnd,GWL_STYLE,dwStyle);
  581. GetWindowRect(hwnd,lprcClient);
  582. ScreenToClient(hwnd,(LPPOINT)&lprcClient->left);
  583. ScreenToClient(hwnd,(LPPOINT)&lprcClient->right);
  584. SendMessage(hwnd,WM_NCCALCSIZE,0,(LPARAM)lprcClient);
  585. }
  586. VOID APIENTRY CalcGroupScrolls(HWND hwnd)
  587. {
  588. register PGROUP pGroup;
  589. register PITEM pItem;
  590. RECT rcClient;
  591. RECT rcRange;
  592. RECT rcT;
  593. DWORD dwStyle, dwStyleNew, dwStyleT;
  594. int iMinPos, iMaxPos;
  595. if (bNoScrollCalc || IsIconic(hwnd))
  596. return;
  597. // Stop re-entrance of this routine.
  598. bNoScrollCalc = TRUE;
  599. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  600. if (!pGroup->pItems) {
  601. // No items...
  602. SetRectEmpty(&rcRange);
  603. goto ChangeStyle;
  604. }
  605. hwndScrolling = hwnd;
  606. // If the user has selected auto arranging then make
  607. // the next item in the z-order visable.
  608. if (bAutoArrange)
  609. ViewActiveItem(pGroup);
  610. SetRectEmpty(&rcRange);
  611. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
  612. {
  613. UnionRect(&rcRange,&rcRange,&pItem->rcIcon);
  614. rcT.top = pItem->rcTitle.top; // don't include the
  615. rcT.bottom = pItem->rcTitle.bottom; // title overhang part
  616. rcT.left = pItem->rcIcon.left;
  617. rcT.right = pItem->rcIcon.right;
  618. UnionRect(&rcRange,&rcRange,&rcT);
  619. }
  620. if (rcRange.left != rcRange.right)
  621. {
  622. // Add on a bit for the left border here.
  623. rcRange.left -= ((cxArrange-cxIconSpace)/2)+cxOffset;
  624. // Don't add on a right border so we can cram as many icons in as poss.
  625. // rcRange.right += ((cxArrange-cxIconSpace)/2);
  626. // ADJUST THE RECT SO THAT WE DON'T GET SCROLL BARS IF ONLY THE BORDERS
  627. // OF TEXT ARE NOT VISIBLE ~~~
  628. }
  629. ChangeStyle:
  630. dwStyleNew = dwStyle = GetWindowLong(hwnd,GWL_STYLE);
  631. dwStyleNew &= ~(WS_HSCROLL | WS_VSCROLL);
  632. for (;;)
  633. {
  634. dwStyleT = dwStyleNew;
  635. GetRealClientRect(hwnd, dwStyleNew, &rcClient);
  636. if (rcRange.left < rcClient.left || rcRange.right > rcClient.right)
  637. dwStyleNew |= WS_HSCROLL;
  638. if (rcRange.top < rcClient.top || rcRange.bottom > rcClient.bottom)
  639. dwStyleNew |= WS_VSCROLL;
  640. if (dwStyleNew == dwStyleT)
  641. break;
  642. }
  643. if (dwStyleNew == dwStyle && !(dwStyle & (WS_VSCROLL|WS_HSCROLL)))
  644. {
  645. /* none there and don't need to add 'em!
  646. */
  647. goto ProcExit;
  648. }
  649. UnionRect(&rcRange,&rcClient,&rcRange);
  650. /* union garantees that left==right or top==bottom in case of no
  651. * scrollbar.
  652. */
  653. rcRange.right -= rcClient.right-rcClient.left;
  654. rcRange.bottom -= rcClient.bottom-rcClient.top;
  655. /* if the style changed, don't redraw in sb code, just redraw the
  656. * frame at the end cause the whole ncarea has to be repainted
  657. * if it hasn't changed, just move the thumb
  658. */
  659. if (dwStyleNew==dwStyle)
  660. {
  661. if (dwStyleNew & WS_HSCROLL)
  662. {
  663. if (GetScrollPos(hwnd,SB_HORZ)!=0)
  664. goto SetScrollInfo;
  665. GetScrollRange(hwnd,SB_HORZ,&iMinPos,&iMaxPos);
  666. if ((iMinPos != rcRange.left) || (iMaxPos != rcRange.right))
  667. goto SetScrollInfo;
  668. }
  669. if (dwStyleNew & WS_VSCROLL)
  670. {
  671. if (GetScrollPos(hwnd,SB_VERT)!=0)
  672. goto SetScrollInfo;
  673. GetScrollRange(hwnd,SB_VERT,&iMinPos,&iMaxPos);
  674. if ((iMinPos != rcRange.top) || (iMaxPos != rcRange.bottom))
  675. goto SetScrollInfo;
  676. }
  677. goto ProcExit;
  678. }
  679. SetScrollInfo:
  680. SetScrollPos(hwnd,SB_HORZ,0,FALSE);
  681. SetScrollPos(hwnd,SB_VERT,0,FALSE);
  682. SetScrollRange(hwnd,SB_HORZ,rcRange.left,rcRange.right,FALSE);
  683. SetScrollRange(hwnd,SB_VERT,rcRange.top,rcRange.bottom,FALSE);
  684. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE
  685. | SWP_NOMOVE | SWP_NOACTIVATE
  686. | SWP_DRAWFRAME);
  687. ProcExit:
  688. // Allow other scroll calculations.
  689. bNoScrollCalc = FALSE;
  690. }
  691. VOID PASCAL ScrollGroup(PGROUP pGroup, int xMove, int yMove, BOOL fCalc)
  692. {
  693. register PITEM pItem;
  694. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
  695. {
  696. OffsetRect(&pItem->rcIcon,xMove,yMove);
  697. OffsetRect(&pItem->rcTitle,xMove,yMove);
  698. }
  699. ScrollWindow(pGroup->hwnd,xMove,yMove,NULL,NULL);
  700. UpdateWindow(pGroup->hwnd);
  701. if (fCalc)
  702. CalcGroupScrolls(pGroup->hwnd);
  703. }
  704. VOID APIENTRY ViewActiveItem(PGROUP pGroup)
  705. {
  706. RECT rcClient, rc;
  707. int xMove = 0, yMove = 0;
  708. GetClientRect(pGroup->hwnd,&rcClient);
  709. UnionRect(&rc, &pGroup->pItems->rcIcon, &pGroup->pItems->rcTitle);
  710. // Clip width to that of icon i.e. ignore width of text.
  711. rc.left = pGroup->pItems->rcIcon.left;
  712. rc.right = pGroup->pItems->rcIcon.right;
  713. if (rc.left < rcClient.left)
  714. xMove = rcClient.left - rc.left;
  715. else if (rc.right > rcClient.right)
  716. xMove = rcClient.right - rc.right;
  717. if (rc.top < rcClient.top)
  718. yMove = rcClient.top - rc.top;
  719. else if (rc.bottom > rcClient.bottom)
  720. yMove = rcClient.bottom - rc.bottom;
  721. if (xMove || yMove)
  722. ScrollGroup(pGroup, xMove, yMove,TRUE);
  723. }
  724. BOOL FAR PASCAL CheckHotKey(WPARAM wParam, LPARAM lParam)
  725. {
  726. HWND hwndT;
  727. PGROUP pGroup;
  728. PITEM pItem;
  729. switch (wParam)
  730. {
  731. case VK_SHIFT:
  732. case VK_CONTROL:
  733. case VK_MENU:
  734. case VK_RETURN:
  735. return FALSE;
  736. }
  737. if (GetKeyState(VK_SHIFT) < 0) {
  738. // DBG((" + SHIFT"));
  739. wParam |= HK_SHIFT;
  740. }
  741. if (GetKeyState(VK_CONTROL) < 0) {
  742. // DBG((" + CONTROL"));
  743. wParam |= HK_CONTROL;
  744. }
  745. if (GetKeyState(VK_MENU) < 0) {
  746. // DBG((" + ALT"));
  747. wParam |= HK_ALT;
  748. }
  749. if (lParam & F_EXT) {
  750. // DBG((" EXTENDED"));
  751. wParam |= HK_EXT;
  752. }
  753. // DBG(("... Full code %4.4X...\r\n",wParam));
  754. for (hwndT = GetWindow(hwndMDIClient,GW_CHILD);
  755. hwndT;
  756. hwndT = GetWindow(hwndT,GW_HWNDNEXT)) {
  757. if (GetWindow(hwndT,GW_OWNER))
  758. continue;
  759. pGroup = (PGROUP)GetWindowLongPtr(hwndT,GWLP_PGROUP);
  760. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  761. // DBG(("Checking (%4.4X,%4.4X)...\r\n",pGroup,pItem));
  762. if (GroupFlag(pGroup,pItem,(WORD)ID_HOTKEY) == (WORD)wParam) {
  763. // DBG(("F*O*U*N*D\r\n"));
  764. ExecItem(pGroup,pItem,FALSE,FALSE);
  765. return TRUE;
  766. }
  767. }
  768. }
  769. return FALSE;
  770. }
  771. VOID APIENTRY KeyWindow(HWND hwnd, WORD wDirection)
  772. {
  773. int wT;
  774. int wNext;
  775. RECT rc;
  776. RECT rcT;
  777. POINT ptA;
  778. POINT ptT;
  779. PGROUP pGroup;
  780. PITEM pItem, pItemNext;
  781. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  782. if (!pGroup->pItems)
  783. return;
  784. wNext = 0x7FFF;
  785. pItemNext = NULL;
  786. CopyRect(&rc,&pGroup->pItems->rcIcon);
  787. for (pItem = pGroup->pItems->pNext; pItem; pItem = pItem->pNext) {
  788. CopyRect(&rcT,&pItem->rcIcon);
  789. ptT.x = rcT.left - rc.left;
  790. ptT.y = rcT.top - rc.top;
  791. ptA.x = (ptT.x < 0) ? -ptT.x : ptT.x;
  792. ptA.y = (ptT.y < 0) ? -ptT.y : ptT.y;
  793. switch (wDirection) {
  794. case VK_LEFT:
  795. if ((ptT.x >= 0) || (ptA.x < ptA.y))
  796. continue;
  797. break;
  798. case VK_RIGHT:
  799. if ((ptT.x <= 0) || (ptA.x < ptA.y))
  800. continue;
  801. break;
  802. case VK_DOWN:
  803. if ((ptT.y <= 0) || (ptA.y < ptA.x))
  804. continue;
  805. break;
  806. case VK_UP:
  807. if ((ptT.y >= 0) || (ptA.y < ptA.x))
  808. continue;
  809. break;
  810. default:
  811. /* illegal key
  812. */
  813. return;
  814. }
  815. wT = ptA.y + ptA.x;
  816. if (wT <= wNext) {
  817. wNext = wT;
  818. pItemNext = pItem;
  819. }
  820. }
  821. if (pItemNext) {
  822. BringItemToTop(pGroup,pItemNext, TRUE);
  823. ViewActiveItem(pGroup);
  824. }
  825. }
  826. VOID APIENTRY CharWindow(register HWND hwnd, register WORD wChar)
  827. {
  828. LPGROUPDEF lpgd;
  829. LPITEMDEF lpid;
  830. PGROUP pGroup;
  831. PITEM pItem, pItemLast;
  832. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  833. if (!pGroup->pItems)
  834. return;
  835. lpgd = LockGroup(hwnd);
  836. if (!lpgd)
  837. return;
  838. /* Search for item, skip the currently selected one.*/
  839. for ( pItem = pGroup->pItems->pNext; pItem; pItem=pItem->pNext)
  840. {
  841. lpid = ITEM(lpgd,pItem->iItem);
  842. if (CharUpper((LPTSTR)(DWORD_PTR)wChar)
  843. == CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*PTR(lpgd, lpid->pName)))
  844. {
  845. pItemLast = MakeFirstItemLast(pGroup);
  846. BringItemToTop(pGroup,pItem, FALSE);
  847. /* Handle updates.*/
  848. InvalidateRect(pGroup->hwnd,&pItem->rcTitle,TRUE);
  849. InvalidateRect(pGroup->hwnd,&pItemLast->rcTitle,TRUE);
  850. ViewActiveItem(pGroup);
  851. break;
  852. }
  853. }
  854. UnlockGroup(hwnd);
  855. }
  856. VOID APIENTRY ScrollMessage(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  857. {
  858. int wMin;
  859. int wMax;
  860. int wPos;
  861. int wInc;
  862. int wPage;
  863. int wNewPos;
  864. RECT rcClient;
  865. int yMove;
  866. int xMove;
  867. BOOL fTemp;
  868. GetClientRect(hwnd, &rcClient);
  869. if (uiMsg == WM_HSCROLL) {
  870. GetScrollRange(hwnd, SB_HORZ, &wMin, &wMax);
  871. wPos = GetScrollPos(hwnd, SB_HORZ);
  872. wInc = cxIconSpace + cxArrange / 2;
  873. wPage = rcClient.right-rcClient.left;
  874. }
  875. else {
  876. GetScrollRange(hwnd, SB_VERT, &wMin, &wMax);
  877. wPos = GetScrollPos(hwnd, SB_VERT);
  878. wInc = cyArrange;
  879. wPage = rcClient.bottom-rcClient.top;
  880. }
  881. switch (GET_WM_VSCROLL_CODE(wParam, lParam)) {
  882. case SB_BOTTOM:
  883. wNewPos = wMax;
  884. break;
  885. case SB_TOP:
  886. wNewPos = wMin;
  887. break;
  888. case SB_LINEDOWN:
  889. wNewPos = wPos + wInc;
  890. break;
  891. case SB_LINEUP:
  892. wNewPos = wPos - wInc;
  893. break;
  894. case SB_PAGEDOWN:
  895. wNewPos = wPos + wPage;
  896. break;
  897. case SB_PAGEUP:
  898. wNewPos = wPos - wPage;
  899. break;
  900. case SB_THUMBTRACK:
  901. case SB_THUMBPOSITION:
  902. wNewPos = (INT)(SHORT)GET_WM_VSCROLL_POS(wParam, lParam);
  903. break;
  904. case SB_ENDSCROLL:
  905. // We might suddenly not need the scroll bars anymore so
  906. // check now.
  907. // Stop CGS from moving the view.
  908. fTemp = bAutoArrange;
  909. bAutoArrange = FALSE;
  910. CalcGroupScrolls(hwnd);
  911. bAutoArrange = fTemp;
  912. /*** FALL THRU ***/
  913. default:
  914. return;
  915. }
  916. if (wNewPos < wMin)
  917. wNewPos = wMin;
  918. else if (wNewPos > wMax)
  919. wNewPos = wMax;
  920. if (uiMsg == WM_VSCROLL) {
  921. SetScrollPos(hwnd, SB_VERT, wNewPos, TRUE);
  922. yMove = wPos - wNewPos;
  923. xMove = 0;
  924. }
  925. else {
  926. SetScrollPos(hwnd, SB_HORZ, wNewPos, TRUE);
  927. yMove = 0;
  928. xMove = wPos - wNewPos;
  929. }
  930. ScrollGroup((PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP),xMove,yMove,FALSE);
  931. }
  932. VOID PASCAL OfficialRect(
  933. LPRECT lprc,
  934. int x,
  935. int y,
  936. int xOffset,
  937. int yOffset)
  938. {
  939. // Work out were the icon should go in the icon grid, taking
  940. // note of where the scroll bars are.
  941. lprc->right = (lprc->left = x-xOffset + (cxIconSpace - cxArrange) / 2) +
  942. cxArrange - 1;
  943. lprc->bottom = (lprc->top = y-yOffset) + cyArrange - 1;
  944. }
  945. BOOL PASCAL IconOverlaps(
  946. PGROUP pGroup,
  947. LPRECT lprc,
  948. int xOffset,
  949. int yOffset)
  950. {
  951. PITEM pItem;
  952. RECT rcT;
  953. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  954. // Ignore icons at -1. This is where icon's get put when
  955. // we don't know where to put them and they will get moved
  956. // later.
  957. if (pItem->rcIcon.left == -1) {
  958. continue;
  959. }
  960. OfficialRect(&rcT, pItem->rcIcon.left, pItem->rcIcon.top, xOffset, yOffset);
  961. if (IntersectRect(&rcT, &rcT, lprc)) {
  962. return TRUE;
  963. }
  964. }
  965. return FALSE;
  966. }
  967. /*
  968. * NB This is called for every icon at init time so put anything to do with
  969. * finding icon positions inside the `if' because that's skipped on init.
  970. * If you don't it'll get tres slow.
  971. */
  972. VOID PASCAL ComputeIconPosition(
  973. PGROUP pGroup,
  974. POINT pt,
  975. LPRECT lprcIcon,
  976. LPRECT lprcTitle,
  977. LPTSTR lpText)
  978. {
  979. HDC hdc;
  980. int cch;
  981. RECT rcClient, rcT;
  982. HFONT hFontT;
  983. int xsp, ysp; // Current position of scrollbar.
  984. int vMax, vMin; // Range.
  985. int hMax, hMin; // Range.
  986. int xOffset, yOffset;
  987. DWORD dwStyle;
  988. if (pt.x == -1) {
  989. /*
  990. * Icon is in "find me a default position" mode...
  991. * so search the icon space for it...
  992. */
  993. // Get the current window style.
  994. dwStyle = GetWindowLong(pGroup->hwnd,GWL_STYLE);
  995. if (dwStyle & WS_MINIMIZE) {
  996. // DBG(("PM.CIP: Window Minimised\n\r"));
  997. // We want to use the restored state of the window.
  998. GetInternalWindowPos(pGroup->hwnd, &rcClient, NULL);
  999. // Convert from screen coords to client coords.
  1000. OffsetRect(&rcClient, -rcClient.left, -rcClient.top);
  1001. }
  1002. else {
  1003. // DBG(("PM.CIP: Window normal or maxed.\n\r"));
  1004. // Take into account scroll bars.
  1005. GetClientRect(pGroup->hwnd, &rcClient);
  1006. }
  1007. if (dwStyle & WS_HSCROLL) {
  1008. xsp = GetScrollPos(pGroup->hwnd, SB_HORZ);
  1009. GetScrollRange(pGroup->hwnd, SB_HORZ, &hMin, &hMax);
  1010. xOffset = xsp-hMin; // Offset icon grid to match scroll bar pos.
  1011. }
  1012. else {
  1013. xOffset = 0;
  1014. }
  1015. if (dwStyle & WS_VSCROLL) {
  1016. ysp = GetScrollPos(pGroup->hwnd, SB_VERT);
  1017. GetScrollRange(pGroup->hwnd, SB_VERT, &vMin, &vMax);
  1018. yOffset = ysp-vMin; // Offset icon grid.
  1019. }
  1020. else {
  1021. yOffset = 0;
  1022. }
  1023. pt.x = (cxArrange - cxIconSpace) / 2 + cxOffset - xOffset;
  1024. pt.y = 0 - yOffset;
  1025. /* Set this icon's left to -1 so that it'll be excluded
  1026. * by the IconOverlaps check.
  1027. */
  1028. lprcIcon->left = -1;
  1029. for (;;) {
  1030. OfficialRect(&rcT, pt.x, pt.y, xOffset, yOffset);
  1031. if (!IconOverlaps(pGroup, &rcT, xOffset, yOffset)) {
  1032. break;
  1033. }
  1034. if (rcT.right + cxArrange > rcClient.right) {
  1035. pt.x = (cxArrange-cxIconSpace)/2 + cxOffset - xOffset;
  1036. pt.y += cyArrange;
  1037. }
  1038. else {
  1039. pt.x += cxArrange;
  1040. }
  1041. }
  1042. }
  1043. SetRect(lprcIcon, pt.x, pt.y, pt.x+cxIconSpace, pt.y+cyIconSpace);
  1044. if (IsRectEmpty(lprcTitle)) {
  1045. cch = lstrlen(lpText);
  1046. hdc = GetDC(pGroup->hwnd);
  1047. hFontT = SelectObject(hdc, hFontTitle);
  1048. /*
  1049. * Compute the icon rect using DrawText.
  1050. */
  1051. lprcTitle->right = cxArrange - (2 * cxOffset);
  1052. DrawText(hdc, lpText, -1, lprcTitle, bIconTitleWrap ?
  1053. (WORD)(DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX) :
  1054. (WORD)(DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE));
  1055. if (hFontT) {
  1056. SelectObject(hdc, hFontT);
  1057. }
  1058. ReleaseDC(pGroup->hwnd, hdc);
  1059. lprcTitle->right += cxOffset * 2;
  1060. lprcTitle->bottom += dyBorder * 2;
  1061. }
  1062. else {
  1063. SetRect(lprcTitle, 0, 0, lprcTitle->right - lprcTitle->left,
  1064. lprcTitle->bottom - lprcTitle->top);
  1065. }
  1066. OffsetRect(lprcTitle, pt.x+(cxIconSpace/2)-((lprcTitle->right-lprcTitle->left)/2),
  1067. pt.y + cyIconSpace - dyBorder);
  1068. // REVIEW Very expensive to do this here.
  1069. // if ((bAutoArrange) && (!bAutoArranging))
  1070. // ArrangeItems(pGroup->hwnd);
  1071. }
  1072. VOID APIENTRY MoveItem(PGROUP pGroup, PITEM pItem, POINT pt)
  1073. {
  1074. LPITEMDEF lpid;
  1075. LPGROUPDEF lpgd;
  1076. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1077. /*
  1078. * If the position is the same, ignore
  1079. */
  1080. if ((pt.x == pItem->rcIcon.left) && (pt.y == pItem->rcIcon.top)) {
  1081. GlobalUnlock(pGroup->hGroup);
  1082. return;
  1083. }
  1084. /*
  1085. * Repaint the original position
  1086. */
  1087. InvalidateIcon(pGroup, pItem);
  1088. lpid = LockItem(pGroup,pItem);
  1089. if (!lpid) {
  1090. GlobalUnlock(pGroup->hGroup);
  1091. return;
  1092. }
  1093. ComputeIconPosition(pGroup, pt, &pItem->rcIcon, &pItem->rcTitle,
  1094. (LPTSTR) PTR(lpgd, lpid->pName));
  1095. UnlockGroup(pGroup->hwnd);
  1096. GlobalUnlock(pGroup->hGroup);
  1097. /*
  1098. * Repaint the new position
  1099. */
  1100. InvalidateIcon(pGroup,pItem);
  1101. // CalcGroupScrolls(pGroup->hwnd);
  1102. }
  1103. /*--------------------------------------------------------------------------*/
  1104. /* */
  1105. /* DropObject() - */
  1106. /* */
  1107. /*--------------------------------------------------------------------------*/
  1108. LONG NEAR PASCAL DropObject(HWND hWnd, LPDROPSTRUCT lpds)
  1109. {
  1110. BOOL fNC;
  1111. BOOL fOk;
  1112. POINT pt;
  1113. LPPOINT lppt;
  1114. PGROUP pGroup;
  1115. PITEM pItem;
  1116. RECT rcClient;
  1117. pGroup = pCurrentGroup;
  1118. pItem = pGroup->pItems;
  1119. pt = lpds->ptDrop;
  1120. // A drop anywhere in the window is valid.
  1121. GetWindowRect(hWnd, &rcClient);
  1122. // Convert to client coords.
  1123. ScreenToClient(hWnd,(LPPOINT)&(rcClient.left));
  1124. ScreenToClient(hWnd,(LPPOINT)&(rcClient.right));
  1125. if (pt.x >= rcClient.left && pt.y >= rcClient.top && pt.x <= rcClient.right
  1126. && pt.y <= rcClient.bottom) {
  1127. /* Dropped in given point of client area. */
  1128. fNC = FALSE;
  1129. pt.x -= (GetSystemMetrics(SM_CXICON) / 2) + 2;
  1130. pt.y -= (GetSystemMetrics(SM_CYICON) / 2) + 2;
  1131. lppt = &pt;
  1132. }
  1133. else {
  1134. /* Dropped in nonclient area. */
  1135. fNC = TRUE;
  1136. lppt = NULL;
  1137. }
  1138. /* Are we iconic ? */
  1139. if (IsIconic(hWnd)) {
  1140. // Yep, we'll need to use default positioning.
  1141. fNC = TRUE;
  1142. lppt = NULL;
  1143. }
  1144. #if 0
  1145. // this if statement code if obsolete, it is never called. - johannec 8/11/93
  1146. if (lpds->wFmt == DOF_EXECUTABLE || lpds->wFmt == DOF_DOCUMENT) {
  1147. BuildDescription(szNameField, szPathName);
  1148. return((LONG)(CreateNewItem(hWnd,
  1149. szNameField, szPathName, szPathName, TEXT(""),
  1150. 0, FALSE, 0, 0, NULL, lppt, CI_SET_DOS_FULLSCRN) != NULL));
  1151. }
  1152. #endif
  1153. if ((hWnd == pGroup->hwnd) && (bMove)) {
  1154. /* Don't drop on our own non-client area. */
  1155. if (fNC)
  1156. return 0L;
  1157. /* We are just moving the item within its own group.
  1158. * Hide it first so the icon title is treated correctly.
  1159. */
  1160. MoveItem(pGroup,pItem, pt);
  1161. if ((bAutoArrange) && (!bAutoArranging))
  1162. ArrangeItems(pGroup->hwnd);
  1163. else if (!bAutoArranging)
  1164. CalcGroupScrolls(pGroup->hwnd);
  1165. return(DRAG_SWP);
  1166. }
  1167. else {
  1168. /* Copy the item to the new group... Set the hourglass
  1169. * cursor (it will get unset after the message returns),
  1170. * select the new group, and add the item at the specified
  1171. * point.
  1172. */
  1173. fOk = DuplicateItem(pGroup,pItem,
  1174. (PGROUP)GetWindowLongPtr(hWnd,GWLP_PGROUP),lppt) != NULL;
  1175. /*
  1176. * Re-Arrange items within the destination group.
  1177. * NB The source will been taken care of by the DeleteItem routine
  1178. * called from DragItem.
  1179. */
  1180. if ((bAutoArrange) && (!bAutoArranging)) {
  1181. /* Destination */
  1182. ArrangeItems(hWnd);
  1183. }
  1184. else if (!bAutoArranging) {
  1185. /* Destination */
  1186. CalcGroupScrolls(hWnd);
  1187. }
  1188. /* View the current item. */
  1189. BringItemToTop(pGroup,pItem, TRUE);
  1190. ViewActiveItem(pGroup);
  1191. /* If the dest isn't minimised then move the focus to it. */
  1192. if (!IsIconic(hWnd))
  1193. SetFocus(hWnd);
  1194. return (fOk ? DRAG_COPY : 0L);
  1195. }
  1196. }
  1197. LONG APIENTRY DropFiles(HWND hwnd, HANDLE hDrop)
  1198. {
  1199. POINT pt;
  1200. LPPOINT lppt;
  1201. UINT i;
  1202. HCURSOR hCursor;
  1203. DWORD dwRet;
  1204. DWORD dwFlags = CI_ACTIVATE | CI_SET_DOS_FULLSCRN;
  1205. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1206. ShowCursor(TRUE);
  1207. if (!DragQueryPoint(hDrop, &pt) ||
  1208. DragQueryFile(hDrop, (UINT)-1, NULL, 0) != 1) {
  1209. lppt = NULL;
  1210. }
  1211. else {
  1212. pt.x -= (GetSystemMetrics(SM_CXICON) / 2) + 2;
  1213. pt.y -= (GetSystemMetrics(SM_CYICON) / 2) + 2;
  1214. lppt = &pt;
  1215. }
  1216. for (i=0; DragQueryFile(hDrop, i, szPathField, MAXITEMPATHLEN); i++) {
  1217. //
  1218. // if filename or directory have spaces, put the path
  1219. // between quotes.
  1220. //
  1221. CheckEscapes(szPathField, MAXITEMPATHLEN+1);
  1222. /* Verify the file's existance... */
  1223. dwRet = ValidatePath(hwndProgman, szPathField, NULL, szIconPath);
  1224. if (dwRet == PATH_INVALID) {
  1225. continue;
  1226. }
  1227. else if (dwRet == PATH_INVALID_OK) {
  1228. dwFlags |= CI_NO_ASSOCIATION;
  1229. }
  1230. BuildDescription(szNameField,szPathField);
  1231. GetDirectoryFromPath(szPathField, szDirField);
  1232. if (!InQuotes(szDirField)) {
  1233. CheckEscapes(szDirField, MAXITEMPATHLEN+1);
  1234. }
  1235. HandleDosApps(szIconPath);
  1236. if (!CreateNewItem(hwnd,
  1237. szNameField, /* name*/
  1238. szPathField, /* command*/
  1239. szIconPath , /* icon path*/
  1240. szDirField, /* no default dir*/
  1241. 0,0, /* no hotkey, no min on run*/
  1242. 0,0,0, /* default icon*/
  1243. lppt, /* at this point*/
  1244. dwFlags))
  1245. break;
  1246. }
  1247. DragFinish(hDrop);
  1248. ShowCursor(FALSE);
  1249. SetCursor(hCursor);
  1250. if ((bAutoArrange) && (!bAutoArranging))
  1251. ArrangeItems(hwnd);
  1252. else if (!bAutoArranging)
  1253. CalcGroupScrolls(hwnd);
  1254. return 1L;
  1255. }
  1256. LRESULT APIENTRY GroupWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  1257. {
  1258. POINT pt;
  1259. switch (uiMsg) {
  1260. case WM_CREATE:
  1261. {
  1262. LPMDICREATESTRUCT lpmdics;
  1263. lpmdics = (LPMDICREATESTRUCT)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  1264. SetWindowLongPtr(hwnd, GWLP_PGROUP, lpmdics->lParam);
  1265. DragAcceptFiles(hwnd,TRUE);
  1266. SetFocus(hwnd);
  1267. break;
  1268. }
  1269. case WM_ERASEBKGND:
  1270. if (IsIconic(hwnd)) {
  1271. //
  1272. // Erase background with the APPWORKSPACE color
  1273. //
  1274. RECT rc;
  1275. if (!hbrWorkspace)
  1276. hbrWorkspace = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE));
  1277. GetUpdateRect(hwnd, &rc, FALSE);
  1278. if (IsRectEmpty(&rc)) {
  1279. GetClientRect(hwnd, &rc);
  1280. }
  1281. FillRect((HDC)wParam, &rc, hbrWorkspace);
  1282. }
  1283. else {
  1284. goto DefProc;
  1285. }
  1286. break;
  1287. case WM_PAINT:
  1288. if (IsIconic(hwnd)) {
  1289. DrawGroupIcon(hwnd);
  1290. }
  1291. else {
  1292. PaintGroup(hwnd);
  1293. }
  1294. break;
  1295. case WM_QUERYDRAGICON:
  1296. {
  1297. PGROUP pGroup;
  1298. HICON hIcon = NULL;
  1299. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1300. if (pGroup->fCommon) {
  1301. hIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(COMMGROUPICON));
  1302. }
  1303. else {
  1304. hIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PERSGROUPICON));
  1305. }
  1306. if (hIcon) {
  1307. return((LRESULT)hIcon);
  1308. }
  1309. else {
  1310. goto DefProc;
  1311. }
  1312. break;
  1313. }
  1314. case WM_LBUTTONDOWN:
  1315. ClickOn(hwnd, MAKEPOINTS(lParam));
  1316. break;
  1317. case WM_MOUSEMOVE:
  1318. if (wParam & MK_LBUTTON) {
  1319. pt.x = (int)(MAKEPOINTS(lParam).x);
  1320. pt.y = (int)(MAKEPOINTS(lParam).y);
  1321. if (!IsRectEmpty(&rcDrag) && !PtInRect(&rcDrag, pt)
  1322. && !fNoFileMenu && (dwEditLevel < 2)) {
  1323. SetRect(&rcDrag,0,0,0,0);
  1324. DragItem(hwnd);
  1325. }
  1326. }
  1327. else {
  1328. SetRect(&rcDrag,0,0,0,0);
  1329. }
  1330. break;
  1331. case WM_LBUTTONUP:
  1332. SetRect(&rcDrag,0,0,0,0);
  1333. break;
  1334. case WM_NCLBUTTONDBLCLK:
  1335. if (IsIconic(hwnd) && (GetKeyState(VK_MENU) < 0)) {
  1336. PostMessage(hwndProgman, WM_COMMAND, IDM_PROPS, 0L);
  1337. } else {
  1338. goto DefProc;
  1339. }
  1340. break;
  1341. case WM_LBUTTONDBLCLK:
  1342. if (ItemHitTest((PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP),
  1343. MAKEPOINTS(lParam))) {
  1344. if (GetKeyState(VK_MENU) < 0) {
  1345. if (!fNoFileMenu)
  1346. PostMessage(hwndProgman,WM_COMMAND,IDM_PROPS,0L);
  1347. } else {
  1348. PostMessage(hwndProgman,WM_COMMAND,IDM_OPEN,0L);
  1349. }
  1350. } else {
  1351. /*
  1352. * Check for Alt-dblclk on nothing to get new item.
  1353. */
  1354. if (GetKeyState(VK_MENU) < 0 && !fNoFileMenu &&
  1355. (dwEditLevel <= 1) && !(pCurrentGroup->fRO) ) {
  1356. MyDialogBox(ITEMDLG, hwndProgman, NewItemDlgProc);
  1357. }
  1358. }
  1359. break;
  1360. case WM_VSCROLL:
  1361. case WM_HSCROLL:
  1362. ScrollMessage(hwnd,uiMsg,wParam,lParam);
  1363. break;
  1364. case WM_CLOSE:
  1365. SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0L);
  1366. break;
  1367. case WM_SYSCOMMAND:
  1368. {
  1369. PGROUP pGroup;
  1370. LPGROUPDEF lpgd;
  1371. TCHAR szCommonGroupSuffix[MAXKEYLEN];
  1372. TCHAR szCommonGroupTitle[2*MAXKEYLEN];
  1373. if (wParam == SC_MINIMIZE) {
  1374. //
  1375. // if the group is common remove the common suffix from the group
  1376. // window title
  1377. //
  1378. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1379. if (pGroup->fCommon) {
  1380. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1381. SetWindowText(hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
  1382. GlobalUnlock(pGroup->hGroup);
  1383. }
  1384. }
  1385. if (wParam == SC_RESTORE) {
  1386. if (!LockGroup(hwnd)) {
  1387. if (wLockError == LOCK_LOWMEM) {
  1388. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_LOWMEM, NULL, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1389. break;
  1390. }
  1391. else {
  1392. /*
  1393. * Lock failed for some other reason - hopefully just
  1394. * a group change. Stop the icon group from being
  1395. * restored.
  1396. */
  1397. break;
  1398. }
  1399. }
  1400. else {
  1401. UnlockGroup(hwnd);
  1402. }
  1403. }
  1404. if ((wParam == SC_MAXIMIZE) || (wParam == SC_RESTORE)) {
  1405. //
  1406. // if the group is common add the common suffix to the group
  1407. // window title
  1408. //
  1409. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1410. if (pGroup->fCommon) {
  1411. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1412. if (!lpgd)
  1413. goto DefProc;
  1414. lstrcpy(szCommonGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName));
  1415. GlobalUnlock(pGroup->hGroup);
  1416. if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
  1417. CharSizeOf(szCommonGroupSuffix))) {
  1418. lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
  1419. }
  1420. SetWindowText(pGroup->hwnd, szCommonGroupTitle);
  1421. }
  1422. InvalidateRect(hwnd, NULL, 0);
  1423. }
  1424. if (wParam == SC_MAXIMIZE)
  1425. SetWindowLong(hwnd, GWL_STYLE,
  1426. (GetWindowLong(hwnd,GWL_STYLE) & ~(WS_HSCROLL | WS_VSCROLL)));
  1427. goto DefProc;
  1428. }
  1429. case WM_SYSKEYDOWN:
  1430. if (!CheckHotKey(wParam,lParam))
  1431. goto DefProc;
  1432. break;
  1433. case WM_KEYDOWN:
  1434. if (!CheckHotKey(wParam,lParam))
  1435. KeyWindow(hwnd,(WORD)wParam);
  1436. break;
  1437. //IME Support
  1438. //by yutakas 1992.10.22
  1439. // When user input DBCS, go and activate icon which has that
  1440. // DBCS charcter in the first of description.
  1441. case WM_IME_REPORT:
  1442. switch (wParam)
  1443. {
  1444. case IR_STRING:
  1445. IMEStringWindow(hwnd,(HANDLE)lParam);
  1446. return TRUE;
  1447. default:
  1448. goto DefProc;
  1449. }
  1450. break;
  1451. case WM_CHAR:
  1452. CharWindow(hwnd, (WORD) wParam);
  1453. break;
  1454. case WM_QUERYDROPOBJECT:
  1455. {
  1456. #define lpds ((LPDROPSTRUCT)lParam)
  1457. PGROUP pGroup;
  1458. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  1459. if (pGroup->fRO) {
  1460. return FALSE;
  1461. }
  1462. if (lpds->wFmt == OBJ_ITEM) {
  1463. return TRUE;
  1464. }
  1465. #undef lpds
  1466. goto DefProc;
  1467. }
  1468. case WM_DROPOBJECT:
  1469. #define lpds ((LPDROPSTRUCT)lParam)
  1470. if (lpds->wFmt == OBJ_ITEM)
  1471. return DropObject(hwnd, lpds);
  1472. #undef lpds
  1473. goto DefProc;
  1474. case WM_DROPFILES:
  1475. return DropFiles(hwnd,(HANDLE)wParam);
  1476. case WM_NCACTIVATE:
  1477. {
  1478. PGROUP pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  1479. if (pGroup->pItems != NULL) {
  1480. InvalidateRect(hwnd,&pGroup->pItems->rcTitle,TRUE);
  1481. }
  1482. goto DefProc;
  1483. }
  1484. case WM_QUERYOPEN:
  1485. {
  1486. PGROUP pGroup;
  1487. LPGROUPDEF lpgd;
  1488. TCHAR szCommonGroupSuffix[MAXKEYLEN];
  1489. TCHAR szCommonGroupTitle[2*MAXKEYLEN];
  1490. //
  1491. // if the group is common add the common suffix to the group
  1492. // window title
  1493. //
  1494. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1495. if (pGroup->fCommon) {
  1496. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1497. if (!lpgd)
  1498. goto DefProc;
  1499. lstrcpy(szCommonGroupTitle,(LPTSTR) PTR(lpgd, lpgd->pName));
  1500. GlobalUnlock(pGroup->hGroup);
  1501. if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
  1502. CharSizeOf(szCommonGroupSuffix))) {
  1503. lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
  1504. }
  1505. SetWindowText(pGroup->hwnd, szCommonGroupTitle);
  1506. }
  1507. goto DefProc;
  1508. }
  1509. case WM_SIZE:
  1510. lParam = DefMDIChildProc(hwnd, uiMsg, wParam, lParam);
  1511. if (wParam != SIZEICONIC) {
  1512. if ((bAutoArrange) && (!bAutoArranging)) {
  1513. ArrangeItems(hwnd);
  1514. } else if (!bArranging) {
  1515. CalcGroupScrolls(hwnd);
  1516. }
  1517. }
  1518. else {
  1519. PGROUP pGroup;
  1520. LPGROUPDEF lpgd;
  1521. //
  1522. // reset window text of common groups
  1523. //
  1524. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1525. if (pGroup->fCommon) {
  1526. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1527. SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
  1528. GlobalUnlock(pGroup->hGroup);
  1529. }
  1530. }
  1531. return lParam;
  1532. case WM_MDIACTIVATE:
  1533. if (!pCurrentGroup) {
  1534. goto DefProc;
  1535. }
  1536. /*
  1537. * If we are de-activating this window...
  1538. */
  1539. if (lParam == 0) {
  1540. /*
  1541. * We're the last window... punt.
  1542. */
  1543. pCurrentGroup = NULL;
  1544. } else if (hwnd == (HWND)wParam) {
  1545. /*
  1546. * We're being deactivated. Update pCurrentGroup
  1547. * to the node being activated.
  1548. */
  1549. pCurrentGroup = (PGROUP)GetWindowLongPtr((HWND)lParam, GWLP_PGROUP);
  1550. } else {
  1551. SetFocus(hwnd);
  1552. }
  1553. goto DefProc;
  1554. case WM_MENUSELECT:
  1555. //
  1556. // to handle F1 on group window system menu
  1557. //
  1558. if (lParam) { /*make sure menu handle isn't null*/
  1559. wMenuID = GET_WM_COMMAND_ID(wParam, lParam); /*get cmd from loword of wParam*/
  1560. hSaveMenuHandle = (HANDLE)lParam; /*Save hMenu into one variable*/
  1561. wSaveFlags = HIWORD(wParam);/*Save flags into another*/
  1562. bFrameSysMenu = FALSE;
  1563. }
  1564. break;
  1565. default:
  1566. DefProc:
  1567. return DefMDIChildProc(hwnd, uiMsg, wParam, lParam);
  1568. }
  1569. return 0L;
  1570. }
  1571. /*--------------------------------------------------------------------------*/
  1572. /* */
  1573. /* ArrangeItems() - */
  1574. /* */
  1575. /* Arranges iconic windows within a group. */
  1576. /* */
  1577. /*--------------------------------------------------------------------------*/
  1578. VOID FAR PASCAL ArrangeItems(HWND hwnd)
  1579. {
  1580. PGROUP pGroup;
  1581. register PITEM pItem;
  1582. PITEM pItemT;
  1583. int xSlots;
  1584. register int i;
  1585. int j,k;
  1586. RECT rc;
  1587. LPGROUPDEF lpgd;
  1588. PITEM rgpitem[CITEMSMAX];
  1589. POINT pt;
  1590. int t1, t2;
  1591. LONG style;
  1592. if (bAutoArranging || IsIconic(hwnd))
  1593. return;
  1594. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  1595. if (!pGroup)
  1596. return;
  1597. /*
  1598. * If the group is RO then don't rearrange the items, just update the
  1599. * scroll bars
  1600. */
  1601. if (!GroupCheck(pGroup)) {
  1602. CalcGroupScrolls(hwnd);
  1603. return;
  1604. }
  1605. bAutoArranging = TRUE;
  1606. SetRectEmpty(&rcArrangeRect);
  1607. style = GetWindowLong(hwnd,GWL_STYLE);
  1608. GetRealClientRect(hwnd,style&~(WS_VSCROLL|WS_HSCROLL),&rc);
  1609. SetWindowLong(hwnd,GWL_STYLE,style);
  1610. xSlots = (rc.right - rc.left)/cxArrange;
  1611. if (xSlots < 1)
  1612. xSlots = 1;
  1613. /* sort the items by x location within a row, or by row if the
  1614. * rows are different
  1615. */
  1616. k = 0;
  1617. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  1618. /* find nearest row
  1619. */
  1620. t1 = pItem->rcIcon.top + cyArrange/2;
  1621. if (t1 >= 0)
  1622. t1 -= t1 % cyArrange;
  1623. else
  1624. t1 += t1 % cyArrange;
  1625. for (i = 0; i < k; i++) {
  1626. pItemT = rgpitem[i];
  1627. t2 = pItemT->rcIcon.top + cyArrange/2;
  1628. if (t2 >= 0)
  1629. t2 -= t2 % cyArrange;
  1630. else
  1631. t2 += t2 % cyArrange;
  1632. if (t2 > t1)
  1633. break;
  1634. else if (t2 == t1 && pItemT->rcIcon.left > pItem->rcIcon.left)
  1635. break;
  1636. }
  1637. for (j = k; j > i; j--) {
  1638. rgpitem[j] = rgpitem[j-1];
  1639. }
  1640. rgpitem[i] = pItem;
  1641. k++;
  1642. }
  1643. lpgd = LockGroup(hwnd);
  1644. if (!lpgd) {
  1645. bAutoArranging = FALSE;
  1646. return;
  1647. }
  1648. bNoScrollCalc = TRUE;
  1649. for (i = 0; i < k; i++) {
  1650. pItem = rgpitem[i];
  1651. /* cxOffset necessary to match (buggy???) win 3 USER
  1652. */
  1653. pt.x = (i%xSlots)*cxArrange + (cxArrange-cxIconSpace)/2 + cxOffset;
  1654. pt.y = (i/xSlots)*cyArrange;
  1655. MoveItem(pGroup,pItem,pt);
  1656. }
  1657. if (!IsRectEmpty(&rcArrangeRect))
  1658. InvalidateRect(pGroup->hwnd,&rcArrangeRect,TRUE);
  1659. UnlockGroup(hwnd);
  1660. bNoScrollCalc = FALSE;
  1661. CalcGroupScrolls(hwnd);
  1662. bAutoArranging = FALSE;
  1663. }
  1664. /****************************************************************************
  1665. *
  1666. * IMEStringWindow(hwnd,hstr)
  1667. *
  1668. * Change activate item by the strings come from IME.
  1669. * When Get WM_IME_REPORT with IR_STRING,this function is called.
  1670. *
  1671. * by yutakas 1992.10.22
  1672. *
  1673. ****************************************************************************/
  1674. BOOL FAR PASCAL IMEStringWindow(HWND hwnd, HANDLE hStr)
  1675. {
  1676. LPTSTR lpStr;
  1677. LPGROUPDEF lpgd;
  1678. LPITEMDEF lpid;
  1679. PGROUP pGroup;
  1680. PITEM pItem = NULL;
  1681. PITEM pItemLast,pTItem;
  1682. int nCnt = 0;
  1683. int nTCnt = 0;
  1684. BOOL ret = FALSE;
  1685. if (!hStr)
  1686. return ret;
  1687. if (!(lpStr = GlobalLock(hStr)))
  1688. return ret;
  1689. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  1690. if (!pGroup->pItems)
  1691. return ret;
  1692. lpgd = LockGroup(hwnd);
  1693. if (!lpgd)
  1694. return ret;
  1695. #ifdef _DEBUG
  1696. {
  1697. TCHAR szDev[80];
  1698. OutputDebugString((LPTSTR)TEXT("In IME Winsdow\r\n"));
  1699. wsprintf ((LPTSTR)szDev,TEXT("IMEStringWindow: lpStr is %s \r\n"),lpStr);
  1700. OutputDebugString((LPSTR)szDev);
  1701. }
  1702. #endif
  1703. // Search for item, skip the currently selected one.
  1704. for ( pTItem = pGroup->pItems->pNext; pTItem; pTItem=pTItem->pNext)
  1705. {
  1706. lpid = ITEM(lpgd,pTItem->iItem);
  1707. nTCnt = IMEWindowGetCnt(lpStr,(LPTSTR)PTR(lpgd,lpid->pName));
  1708. if (nCnt < nTCnt)
  1709. {
  1710. nCnt = nTCnt;
  1711. pItem = pTItem;
  1712. }
  1713. }
  1714. lpid = ITEM(lpgd,pGroup->pItems->iItem);
  1715. nTCnt = IMEWindowGetCnt(lpStr,(LPTSTR)PTR(lpgd,lpid->pName));
  1716. if ((nCnt >= nTCnt) && pItem)
  1717. {
  1718. pItemLast = MakeFirstItemLast(pGroup);
  1719. BringItemToTop(pGroup,pItem, FALSE);
  1720. // Handle updates.
  1721. InvalidateRect(pGroup->hwnd,&pItem->rcTitle,TRUE);
  1722. InvalidateRect(pGroup->hwnd,&pItemLast->rcTitle,TRUE);
  1723. ViewActiveItem(pGroup);
  1724. ret = TRUE;
  1725. }
  1726. GlobalUnlock(hStr);
  1727. UnlockGroup(hwnd);
  1728. #ifdef _DEBUG
  1729. {
  1730. TCHAR szDev[80];
  1731. wsprintf ((LPTSTR)szDev,TEXT("IMEStringWindow: ret is %s \r\n"),ret);
  1732. OutputDebugString((LPTSTR)szDev);
  1733. }
  1734. #endif
  1735. return ret;
  1736. }
  1737. /****************************************************************************
  1738. *
  1739. * IMEWindowGetCnt(LPSTR,LPSTR)
  1740. *
  1741. * Compare strings from ahead and return the number of same character
  1742. *
  1743. * by yutakas 1992.10.22
  1744. *
  1745. *
  1746. ****************************************************************************/
  1747. int FAR PASCAL IMEWindowGetCnt(LPTSTR lp1, LPTSTR lp2)
  1748. {
  1749. int cnt = 0;
  1750. while (*lp1 && *lp2)
  1751. {
  1752. // ToddB: This typecasting is to prevent lp1 and lp2 from being modified
  1753. // by CharUpper'ing one char at a time instead of the whole string
  1754. if (CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*lp1) ==
  1755. CharUpper((LPTSTR)(DWORD_PTR)(BYTE)*lp2))
  1756. {
  1757. cnt++;
  1758. }
  1759. else
  1760. break;
  1761. lp1++;
  1762. lp2++;
  1763. }
  1764. return (*lp1 ? 0 : cnt);
  1765. }