Leaked source code of windows server 2003
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.

1043 lines
27 KiB

  1. //
  2. // PSDLG.CPP
  3. // Page Sorter Dialog
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. static const DWORD s_helpIds[] =
  10. {
  11. IDC_PS_THUMBNAILS, IDH_CONF_PAGESORT_MAIN,
  12. IDC_PS_GOTO, IDH_CONF_PAGESORT_GOTO,
  13. IDC_PS_DELETE, IDH_CONF_PAGESORT_DEL,
  14. IDC_PS_INSERT_BEFORE, IDH_CONF_PAGESORT_BEFORE,
  15. IDC_PS_INSERT_AFTER, IDH_CONF_PAGESORT_AFTER,
  16. 0,0
  17. };
  18. //
  19. // PageSortDlgProc()
  20. // Dialog message handler for the page sort dialog. We have to set the
  21. // real LRESULT return value in some cases.
  22. //
  23. INT_PTR PageSortDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  24. {
  25. BOOL fHandled = FALSE;
  26. PAGESORT * pps = (PAGESORT *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  27. switch (message)
  28. {
  29. case WM_DROPFILES:
  30. g_pMain->OnDropFiles((HDROP)wParam);
  31. fHandled = TRUE;
  32. break;
  33. case WM_INITDIALOG:
  34. OnInitDialog(hwnd, (PAGESORT *)lParam);
  35. fHandled = TRUE;
  36. break;
  37. case WM_MEASUREITEM:
  38. OnMeasureItem(hwnd, (UINT)wParam, (LPMEASUREITEMSTRUCT)lParam);
  39. fHandled = TRUE;
  40. break;
  41. case WM_DRAWITEM:
  42. OnDrawItem(hwnd, (UINT)wParam, (LPDRAWITEMSTRUCT)lParam);
  43. fHandled = TRUE;
  44. break;
  45. case WM_DELETEITEM:
  46. OnDeleteItem(hwnd, (UINT)wParam, (LPDELETEITEMSTRUCT)lParam);
  47. fHandled = TRUE;
  48. break;
  49. case WM_LBTRACKPOINT:
  50. // This gets sent to us from the listbox; see if the user is dragging
  51. OnStartDragDrop(pps, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  52. fHandled = TRUE;
  53. break;
  54. case WM_MOUSEMOVE:
  55. WhileDragging(pps, LOWORD(lParam), HIWORD(lParam));
  56. fHandled = TRUE;
  57. break;
  58. case WM_LBUTTONUP:
  59. case WM_CAPTURECHANGED:
  60. // If we're dragging, complete the drag/drop
  61. OnEndDragDrop(pps, (message == WM_LBUTTONUP),
  62. (short)LOWORD(lParam), (short)HIWORD(lParam));
  63. fHandled = TRUE;
  64. break;
  65. case WM_PALETTECHANGED:
  66. // Repaint the thumbnail list
  67. ::InvalidateRect(::GetDlgItem(hwnd, IDC_PS_THUMBNAILS), NULL, TRUE);
  68. fHandled = TRUE;
  69. break;
  70. case WM_COMMAND:
  71. OnCommand(pps, GET_WM_COMMAND_ID(wParam, lParam),
  72. GET_WM_COMMAND_CMD(wParam, lParam), GET_WM_COMMAND_HWND(wParam, lParam));
  73. fHandled = TRUE;
  74. break;
  75. case WM_SETCURSOR:
  76. fHandled = OnSetCursor(pps, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  77. break;
  78. case WM_CONTEXTMENU:
  79. DoHelpWhatsThis(wParam, s_helpIds);
  80. fHandled = TRUE;
  81. break;
  82. case WM_HELP:
  83. DoHelp(lParam, s_helpIds);
  84. fHandled = TRUE;
  85. break;
  86. //
  87. // Private PageSortDlg messages
  88. //
  89. case WM_PS_ENABLEPAGEOPS:
  90. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  91. pps->fPageOpsAllowed = (wParam != 0);
  92. EnableButtons(pps);
  93. fHandled = TRUE;
  94. break;
  95. case WM_PS_LOCKCHANGE:
  96. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  97. EnableButtons(pps);
  98. fHandled = TRUE;
  99. break;
  100. case WM_PS_PAGECLEARIND:
  101. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  102. OnPageClearInd(pps, (WB_PAGE_HANDLE)wParam);
  103. fHandled = TRUE;
  104. break;
  105. case WM_PS_PAGEDELIND:
  106. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  107. OnPageDeleteInd(pps, (WB_PAGE_HANDLE)wParam);
  108. fHandled = TRUE;
  109. break;
  110. case WM_PS_PAGEORDERUPD:
  111. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  112. OnPageOrderUpdated(pps);
  113. fHandled = TRUE;
  114. break;
  115. }
  116. return(fHandled);
  117. }
  118. //
  119. // OnInitDialog()
  120. // WM_INITDIALOG handler
  121. //
  122. void OnInitDialog(HWND hwnd, PAGESORT * pps)
  123. {
  124. int nCount;
  125. RECT rc;
  126. RECT rcWindow;
  127. HWND hwndList;
  128. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnInitDialog");
  129. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  130. // Save this away
  131. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pps);
  132. // Get our listbox
  133. pps->hwnd = hwnd;
  134. // Also put our HWND in WbMainWindow
  135. ASSERT(g_pMain);
  136. g_pMain->m_hwndPageSortDlg = hwnd;
  137. //
  138. // Get the drag/drop cursors we use
  139. //
  140. pps->hCursorDrag = ::LoadCursor(g_hInstance, MAKEINTRESOURCE(DRAGPAGECURSOR));
  141. pps->hCursorNoDrop = ::LoadCursor(NULL, IDC_NO);
  142. pps->hCursorNormal = ::LoadCursor(NULL, IDC_ARROW);
  143. pps->hCursorCurrent = pps->hCursorNormal;
  144. // Convert the cur page to a page number
  145. pps->iCurPageNo = (int) g_pwbCore->WBP_PageNumberFromHandle((WB_PAGE_HANDLE)pps->hCurPage);
  146. //
  147. // Insert items, with empty data (we render thumbnail bitmap the first
  148. // time we draw ite).
  149. //
  150. hwndList = ::GetDlgItem(hwnd, IDC_PS_THUMBNAILS);
  151. nCount = g_pwbCore->WBP_ContentsCountPages();
  152. // LB_SETCOUNT doesn't work on NT 4.0; must use add string
  153. while (nCount > 0)
  154. {
  155. ::SendMessage(hwndList, LB_ADDSTRING, 0, 0);
  156. nCount--;
  157. }
  158. ASSERT(::SendMessage(hwndList, LB_GETCOUNT, 0, 0) == (LRESULT)g_pwbCore->WBP_ContentsCountPages());
  159. // Select the current page
  160. ::SendMessage(hwndList, LB_SETCURSEL, pps->iCurPageNo - 1, 0);
  161. //
  162. // Set the original button page op state
  163. //
  164. EnableButtons(pps);
  165. //
  166. // We can receive dropped files
  167. //
  168. DragAcceptFiles(hwnd, TRUE);
  169. }
  170. //
  171. // OnMeasureItem()
  172. //
  173. void OnMeasureItem(HWND hwnd, UINT id, LPMEASUREITEMSTRUCT lpmis)
  174. {
  175. RECT rcClient;
  176. ASSERT(id == IDC_PS_THUMBNAILS);
  177. ASSERT(!IsBadReadPtr(lpmis, sizeof(MEASUREITEMSTRUCT)));
  178. //
  179. // We want the slots to be square, although the page is wider than it
  180. // is high.
  181. //
  182. ::GetClientRect(::GetDlgItem(hwnd, id), &rcClient);
  183. rcClient.bottom -= rcClient.top;
  184. lpmis->itemWidth = rcClient.bottom;
  185. lpmis->itemHeight = rcClient.bottom;
  186. }
  187. //
  188. // OnDeleteItem()
  189. // We need to delete the bitmap for the item, if there is one
  190. //
  191. void OnDeleteItem(HWND hwnd, UINT id, LPDELETEITEMSTRUCT lpdis)
  192. {
  193. HBITMAP hbmp;
  194. ASSERT(id == IDC_PS_THUMBNAILS);
  195. ASSERT(!IsBadReadPtr(lpdis, sizeof(DELETEITEMSTRUCT)));
  196. hbmp = (HBITMAP)lpdis->itemData;
  197. if (hbmp != NULL)
  198. {
  199. ASSERT(GetObjectType(hbmp) == OBJ_BITMAP);
  200. ::DeleteBitmap(hbmp);
  201. }
  202. }
  203. //
  204. // OnDrawItem()
  205. // Draws the thumbnail. If there isn't a cached bitmap, we create one for
  206. // the page. The page number is the same as the item index + 1.
  207. //
  208. void OnDrawItem(HWND hwnd, UINT id, LPDRAWITEMSTRUCT lpdi)
  209. {
  210. HWND hwndList;
  211. WB_PAGE_HANDLE hPage;
  212. HPALETTE hPalette;
  213. HPALETTE hOldPalette1 = NULL;
  214. HPALETTE hOldPalette2 = NULL;
  215. HBITMAP hBitmap = NULL;
  216. HBITMAP hOldBitmap = NULL;
  217. HDC hdcMem = NULL;
  218. HBRUSH hbr;
  219. HPEN hpen;
  220. TCHAR szPageNum[8];
  221. COLORREF clrOld;
  222. int nMode;
  223. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnDrawItem");
  224. ASSERT(id == IDC_PS_THUMBNAILS);
  225. ASSERT(!IsBadReadPtr(lpdi, sizeof(DRAWITEMSTRUCT)));
  226. hwndList = ::GetDlgItem(hwnd, id);
  227. //
  228. // Is this within the proper range?
  229. //
  230. if (lpdi->itemID == -1)
  231. {
  232. WARNING_OUT(("OnDrawItem: bogus item id"));
  233. goto Done;
  234. }
  235. if (g_pwbCore->WBP_PageHandleFromNumber(lpdi->itemID+1, &hPage) != 0)
  236. {
  237. ERROR_OUT(("OnDrawItem: can't get page handle"));
  238. goto Done;
  239. }
  240. //
  241. // Account for the horizontal scroll bar; to get around whacky listbox
  242. // sizing bugs, we needed to fake the height out by including the scroll
  243. // bar in the item height.
  244. //
  245. lpdi->rcItem.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
  246. hdcMem = ::CreateCompatibleDC(lpdi->hDC);
  247. if (!hdcMem)
  248. {
  249. ERROR_OUT(("OnDrawItem: can't create compatible dc"));
  250. goto Done;
  251. }
  252. //
  253. // Realize our palette into the DC
  254. //
  255. hPalette = PG_GetPalette();
  256. if (hPalette != NULL)
  257. {
  258. hOldPalette1 = ::SelectPalette(lpdi->hDC, hPalette, FALSE);
  259. ::RealizePalette(lpdi->hDC);
  260. hOldPalette2 = ::SelectPalette(hdcMem, hPalette, FALSE);
  261. }
  262. //
  263. // Do we have the image for this page created yet? If not, create it
  264. // now.
  265. //
  266. hBitmap = (HBITMAP)lpdi->itemData;
  267. if (hBitmap == NULL)
  268. {
  269. hBitmap = ::CreateCompatibleBitmap(lpdi->hDC,
  270. RENDERED_WIDTH+2, RENDERED_HEIGHT+2);
  271. if (!hBitmap)
  272. {
  273. ERROR_OUT(("OnDrawItem: can't create compatible bitmap"));
  274. goto Done;
  275. }
  276. }
  277. hOldBitmap = SelectBitmap(hdcMem, hBitmap);
  278. if ((HBITMAP)lpdi->itemData == NULL)
  279. {
  280. //
  281. // Fill the bitmap with the background color, framed so it looks
  282. // like a page.
  283. //
  284. hbr = SelectBrush(hdcMem, ::GetSysColorBrush(COLOR_WINDOW));
  285. ::Rectangle(hdcMem, 0, 0, RENDERED_WIDTH+2, RENDERED_HEIGHT+2);
  286. SelectBrush(hdcMem, hbr);
  287. //
  288. // Render the page
  289. //
  290. ::SaveDC(hdcMem);
  291. // Set the attributes to compress the whole page into a
  292. // thumbnail at the relevant position for the cache index.
  293. ::SetMapMode(hdcMem, MM_ANISOTROPIC);
  294. ::SetWindowExtEx(hdcMem, DRAW_WIDTH, DRAW_HEIGHT, NULL);
  295. ::SetViewportOrgEx(hdcMem, 1, 1, NULL);
  296. ::SetViewportExtEx(hdcMem, RENDERED_WIDTH, RENDERED_HEIGHT, NULL);
  297. // Draw the page into the cache bitmap
  298. ::SetStretchBltMode(hdcMem, STRETCH_DELETESCANS);
  299. PG_Draw(hPage, hdcMem, TRUE);
  300. // Restore the DC atrributes
  301. ::RestoreDC(hdcMem, -1);
  302. // Set the item data
  303. ::SendMessage(hwndList, LB_SETITEMDATA, lpdi->itemID, (LPARAM)hBitmap);
  304. }
  305. //
  306. // Fill the background with the selection or window color depending
  307. // on the state.
  308. //
  309. if (lpdi->itemState & ODS_SELECTED)
  310. ::FillRect(lpdi->hDC, &lpdi->rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT));
  311. else
  312. ::FillRect(lpdi->hDC, &lpdi->rcItem, ::GetSysColorBrush(COLOR_WINDOW));
  313. if (lpdi->itemState & ODS_FOCUS)
  314. ::DrawFocusRect(lpdi->hDC, &lpdi->rcItem);
  315. //
  316. // Blt the page bitmap to the listbox item, centering it horizontally
  317. // and vertically.
  318. //
  319. ::BitBlt(lpdi->hDC,
  320. (lpdi->rcItem.left + lpdi->rcItem.right - (RENDERED_WIDTH + 2)) / 2,
  321. (lpdi->rcItem.top + lpdi->rcItem.bottom - (RENDERED_HEIGHT + 2)) / 2,
  322. RENDERED_WIDTH + 2, RENDERED_HEIGHT + 2,
  323. hdcMem, 0, 0, SRCCOPY);
  324. //
  325. // Draw number of page centered
  326. //
  327. wsprintf(szPageNum, "%d", lpdi->itemID+1);
  328. clrOld = ::SetTextColor(lpdi->hDC, ::GetSysColor(COLOR_GRAYTEXT));
  329. nMode = ::SetBkMode(lpdi->hDC, TRANSPARENT);
  330. ::DrawText(lpdi->hDC, szPageNum, lstrlen(szPageNum), &lpdi->rcItem,
  331. DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  332. ::SetBkMode(lpdi->hDC, nMode);
  333. ::SetTextColor(lpdi->hDC, clrOld);
  334. Done:
  335. if (hOldBitmap)
  336. {
  337. SelectBitmap(hdcMem, hOldBitmap);
  338. }
  339. if (hOldPalette2)
  340. {
  341. ::SelectPalette(hdcMem, hOldPalette2, FALSE);
  342. }
  343. if (hOldPalette1)
  344. {
  345. ::SelectPalette(lpdi->hDC, hOldPalette1, FALSE);
  346. }
  347. if (hdcMem)
  348. {
  349. ::DeleteDC(hdcMem);
  350. }
  351. }
  352. //
  353. // OnSetCursor
  354. // If the set is for us, handles the WM_SETCURSOR message and returns TRUE
  355. // that we handled it, and TRUE via the window LRESULT.
  356. //
  357. BOOL OnSetCursor(PAGESORT * pps, HWND hwnd, UINT uiHit, UINT msg)
  358. {
  359. // Check that this message is for the main window
  360. if (hwnd == pps->hwnd)
  361. {
  362. // If the cursor is now in the client area, set the cursor
  363. if (uiHit == HTCLIENT)
  364. {
  365. ::SetCursor(pps->hCursorCurrent);
  366. }
  367. else
  368. {
  369. // Restore the cursor to the standard arrow
  370. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  371. }
  372. ::SetWindowLongPtr(pps->hwnd, DWLP_MSGRESULT, TRUE);
  373. return(TRUE);
  374. }
  375. else
  376. {
  377. return(FALSE);
  378. }
  379. }
  380. //
  381. // OnCommand()
  382. //
  383. void OnCommand(PAGESORT * pps, UINT id, UINT cmd, HWND hwndCtl)
  384. {
  385. switch (id)
  386. {
  387. case IDC_PS_INSERT_BEFORE:
  388. if (cmd == BN_CLICKED)
  389. {
  390. InsertPage(pps, INSERT_BEFORE);
  391. }
  392. break;
  393. case IDC_PS_INSERT_AFTER:
  394. if (cmd == BN_CLICKED)
  395. {
  396. InsertPage(pps, INSERT_AFTER);
  397. }
  398. break;
  399. case IDC_PS_GOTO:
  400. if (cmd == BN_CLICKED)
  401. {
  402. pps->iCurPageNo = (int)::SendDlgItemMessage(pps->hwnd,
  403. IDC_PS_THUMBNAILS, LB_GETCURSEL, 0, 0) + 1;
  404. OnCommand(pps, IDOK, BN_CLICKED, NULL);
  405. }
  406. break;
  407. case IDC_PS_DELETE:
  408. if (cmd == BN_CLICKED)
  409. {
  410. OnDelete(pps);
  411. }
  412. break;
  413. case IDC_PS_THUMBNAILS:
  414. switch (cmd)
  415. {
  416. case LBN_DBLCLK:
  417. OnCommand(pps, IDC_PS_GOTO, BN_CLICKED, NULL);
  418. break;
  419. }
  420. break;
  421. case IDOK:
  422. case IDCANCEL:
  423. if (cmd == BN_CLICKED)
  424. {
  425. // Clear out WbMainWindow
  426. ASSERT(g_pMain);
  427. g_pMain->m_hwndPageSortDlg = NULL;
  428. // Get the current page
  429. pps->hCurPage = PG_GetPageNumber(pps->iCurPageNo);
  430. ::EndDialog(pps->hwnd, id);
  431. }
  432. break;
  433. }
  434. }
  435. //
  436. // EnableButtons
  437. // Enable (or disable) the dialog buttons appropriately
  438. //
  439. //
  440. void EnableButtons(PAGESORT * pps)
  441. {
  442. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::EnableButtons");
  443. ASSERT(!IsBadWritePtr(pps, sizeof(PAGESORT)));
  444. // If another user currently has a lock on the contents, disable the
  445. // delete and insert buttons.
  446. BOOL bLocked = WB_Locked();
  447. UINT uiCountPages = (UINT)::SendDlgItemMessage(pps->hwnd, IDC_PS_THUMBNAILS,
  448. LB_GETCOUNT, 0, 0);
  449. ::EnableWindow(::GetDlgItem(pps->hwnd, IDC_PS_DELETE), (!bLocked &&
  450. (uiCountPages > 1) &&
  451. pps->fPageOpsAllowed));
  452. ::EnableWindow(::GetDlgItem(pps->hwnd, IDC_PS_INSERT_BEFORE), (!bLocked &&
  453. (uiCountPages < WB_MAX_PAGES) &&
  454. pps->fPageOpsAllowed));
  455. ::EnableWindow(::GetDlgItem(pps->hwnd, IDC_PS_INSERT_AFTER), (!bLocked &&
  456. (uiCountPages < WB_MAX_PAGES) &&
  457. pps->fPageOpsAllowed));
  458. }
  459. //
  460. // OnDelete
  461. // The user has clicked the Delete button
  462. //
  463. //
  464. void OnDelete(PAGESORT * pps)
  465. {
  466. int iResult;
  467. BOOL bWasPosted;
  468. HWND hwndList;
  469. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnDelete");
  470. if (!pps->fPageOpsAllowed)
  471. return;
  472. // Display a message box with the relevant question
  473. if (g_pMain->UsersMightLoseData( &bWasPosted, pps->hwnd ) ) // bug NM4db:418
  474. return;
  475. hwndList = ::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS);
  476. if( bWasPosted )
  477. iResult = IDYES;
  478. else
  479. iResult = ::Message(pps->hwnd, IDS_DELETE_PAGE, IDS_DELETE_PAGE_MESSAGE, MB_YESNO | MB_ICONQUESTION );
  480. // If the user wants to continue with the delete
  481. if (iResult == IDYES)
  482. {
  483. UINT uiRet;
  484. int iSel = (int)::SendMessage(hwndList, LB_GETCURSEL, 0, 0);
  485. // Get a pointer to the current page
  486. WB_PAGE_HANDLE hPage = PG_GetPageNumber(iSel + 1);
  487. ASSERT(::SendMessage(hwndList, LB_GETCOUNT, 0, 0) > 1);
  488. // Ensure that we have the Page Order lock.
  489. if (!g_pMain->GetLock(WB_LOCK_TYPE_CONTENTS, SW_HIDE))
  490. {
  491. DefaultExceptionHandler(WBFE_RC_WB, WB_RC_LOCKED);
  492. return;
  493. }
  494. // Delete the page. We do not update the thumbnails yet - this
  495. // is done when the page deleted event is received.
  496. uiRet = g_pwbCore->WBP_PageDelete(hPage);
  497. if (uiRet != 0)
  498. {
  499. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  500. return;
  501. }
  502. // Show that the pages have been manipulated
  503. pps->fChanged = TRUE;
  504. }
  505. }
  506. //
  507. //
  508. // InsertPage
  509. // Insert a new (blank) page into the Whiteboard
  510. //
  511. //
  512. void InsertPage(PAGESORT * pps, UINT uiBeforeAfter)
  513. {
  514. int iSel;
  515. MLZ_EntryOut(ZONE_FUNCTION, "InsertPage");
  516. if (!pps->fPageOpsAllowed)
  517. return;
  518. // Ensure that we have the Page Order lock.
  519. if (!g_pMain->GetLock(WB_LOCK_TYPE_CONTENTS, SW_HIDE))
  520. return;
  521. iSel = (int)::SendDlgItemMessage(pps->hwnd, IDC_PS_THUMBNAILS, LB_GETCURSEL, 0, 0);
  522. // Add the new page to the list (throws an exception on failure)
  523. WB_PAGE_HANDLE hRefPage = PG_GetPageNumber(iSel + 1);
  524. UINT uiRet;
  525. WB_PAGE_HANDLE hPage;
  526. if (uiBeforeAfter == INSERT_BEFORE)
  527. {
  528. uiRet = g_pwbCore->WBP_PageAddBefore(hRefPage, &hPage);
  529. }
  530. else
  531. {
  532. uiRet = g_pwbCore->WBP_PageAddAfter(hRefPage, &hPage);
  533. }
  534. if (uiRet != 0)
  535. {
  536. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  537. return;
  538. }
  539. // Show that the contents have been changed by the dialog
  540. pps->fChanged = TRUE;
  541. // We'll get notified in a bit when the page order has changed.
  542. }
  543. //
  544. // OnPageClearInd()
  545. // Notification passed on AFTER page has been cleared
  546. //
  547. void OnPageClearInd(PAGESORT * pps, WB_PAGE_HANDLE hPage)
  548. {
  549. HWND hwndList;
  550. int iPageNo;
  551. RECT rcItem;
  552. HBITMAP hbmp;
  553. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnPageClearInd");
  554. hwndList = ::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS);
  555. iPageNo = g_pwbCore->WBP_PageNumberFromHandle(hPage) - 1;
  556. // Is it in the right range?
  557. if ((iPageNo < 0) || (iPageNo >= ::SendMessage(hwndList, LB_GETCOUNT,
  558. 0, 0)))
  559. {
  560. ERROR_OUT(("Bogus page number %d", iPageNo));
  561. return;
  562. }
  563. // Clear the item's data
  564. hbmp = (HBITMAP)::SendMessage(hwndList, LB_SETITEMDATA, iPageNo, 0);
  565. if (hbmp)
  566. ::DeleteBitmap(hbmp);
  567. // Repaint the rect
  568. if (::SendMessage(hwndList, LB_GETITEMRECT, iPageNo, (LPARAM)&rcItem))
  569. {
  570. ::InvalidateRect(hwndList, &rcItem, TRUE);
  571. ::UpdateWindow(hwndList);
  572. }
  573. }
  574. //
  575. // OnPageDeleteInd()
  576. // Notification passed on BEFORE page has been deleted
  577. //
  578. void OnPageDeleteInd(PAGESORT * pps, WB_PAGE_HANDLE hPage)
  579. {
  580. HWND hwndList;
  581. int iPageNo;
  582. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnPageDeleteInd");
  583. hwndList = ::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS);
  584. iPageNo = g_pwbCore->WBP_PageNumberFromHandle(hPage) - 1;
  585. //
  586. // If this isn't in the range we know about, we don't care
  587. //
  588. if ((iPageNo < 0) || (iPageNo >= ::SendMessage(hwndList, LB_GETCOUNT, 0, 0)))
  589. {
  590. ERROR_OUT(("Bogus page number %d", iPageNo));
  591. return;
  592. }
  593. //
  594. // Delete this item from the list
  595. //
  596. ::SendMessage(hwndList, LB_DELETESTRING, iPageNo, 0);
  597. EnableButtons(pps);
  598. }
  599. //
  600. // OnPageOrderUpdated()
  601. //
  602. void OnPageOrderUpdated(PAGESORT * pps)
  603. {
  604. HWND hwndList;
  605. int nCount;
  606. int iCurSel;
  607. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::OnPageOrderUpdated");
  608. hwndList = ::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS);
  609. // Remember the old selection
  610. iCurSel = (int)::SendMessage(hwndList, LB_GETCURSEL, 0, 0);
  611. // This is too complicated. We're just going to wipe out all the items
  612. // and their bitmaps
  613. ::SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  614. ::SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
  615. nCount = g_pwbCore->WBP_ContentsCountPages();
  616. //
  617. // Adjust the current, and selected indeces
  618. //
  619. if (pps->iCurPageNo > nCount)
  620. {
  621. pps->iCurPageNo = nCount;
  622. }
  623. // Put back the same selected item
  624. if (iCurSel >= nCount)
  625. {
  626. iCurSel = nCount - 1;
  627. }
  628. // LB_SETCOUNT doesn't work on NT 4.0; must use add string
  629. while (nCount > 0)
  630. {
  631. ::SendMessage(hwndList, LB_ADDSTRING, 0, 0);
  632. nCount--;
  633. }
  634. ASSERT(::SendMessage(hwndList, LB_GETCOUNT, 0, 0) == (LRESULT)g_pwbCore->WBP_ContentsCountPages());
  635. ::SendMessage(hwndList, LB_SETCURSEL, iCurSel, 0);
  636. ::SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  637. ::InvalidateRect(hwndList, NULL, TRUE);
  638. ::UpdateWindow(hwndList);
  639. EnableButtons(pps);
  640. }
  641. //
  642. // OnStartDragDrop()
  643. // This checks if the user is trying to drag & drop pages around to
  644. // change the order via direct manipulation. We get a WM_LBTRACKPOINT
  645. // message when someone clicks in the listbox. We then see if they are
  646. // dragging; if so, we tell the listbox to ignore the mouse click, and we
  647. // ourselves capture the mouse moves.
  648. //
  649. void OnStartDragDrop(PAGESORT * pps, UINT iItem, int x, int y)
  650. {
  651. POINT pt;
  652. //
  653. // If no page order stuff is currently allowed, return
  654. //
  655. if (!pps->fPageOpsAllowed || WB_Locked())
  656. {
  657. WARNING_OUT(("No direct manipulation of page order allowed"));
  658. return;
  659. }
  660. pt.x = x;
  661. pt.y = y;
  662. if (!DragDetect(pps->hwnd, pt))
  663. {
  664. // If the mouse is no longer down, fake a button up to the listbox
  665. // because DragDetect() just swallowed it
  666. if (::GetKeyState(VK_LBUTTON) >= 0)
  667. {
  668. ::PostMessage(::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS),
  669. WM_LBUTTONUP, MK_LBUTTON, MAKELONG(x, y));
  670. }
  671. return;
  672. }
  673. // We are dragging
  674. pps->fDragging = TRUE;
  675. pps->iPageDragging = iItem + 1;
  676. pps->hCursorCurrent = pps->hCursorDrag;
  677. ::SetCursor(pps->hCursorCurrent);
  678. ::SetCapture(pps->hwnd);
  679. // Tell the listbox to ignore the mouse-we're handling it
  680. // and blow off a double-click.
  681. ::SetWindowLongPtr(pps->hwnd, DWLP_MSGRESULT, 2);
  682. }
  683. //
  684. // WhileDragging()
  685. //
  686. void WhileDragging(PAGESORT * pps, int x, int y)
  687. {
  688. POINT pt;
  689. RECT rc;
  690. if (!pps->fDragging)
  691. return;
  692. pps->hCursorCurrent = pps->hCursorNoDrop;
  693. if (pps->fPageOpsAllowed && !WB_Locked())
  694. {
  695. //
  696. // Is this over the listbox client?
  697. //
  698. ::GetClientRect(::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS), &rc);
  699. ::MapWindowPoints(::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS),
  700. pps->hwnd, (LPPOINT)&rc, 2);
  701. pt.x = x;
  702. pt.y = y;
  703. if (::PtInRect(&rc, pt))
  704. {
  705. pps->hCursorCurrent = pps->hCursorDrag;
  706. }
  707. }
  708. ::SetCursor(pps->hCursorCurrent);
  709. }
  710. //
  711. // OnEndDragDrop
  712. //
  713. void OnEndDragDrop(PAGESORT * pps, BOOL fComplete, int x, int y)
  714. {
  715. POINT pt;
  716. RECT rc;
  717. int iItem;
  718. if (!pps->fDragging)
  719. return;
  720. //
  721. // Do this first; releasing capture will send a WM_CAPTURECHANGED
  722. // message.
  723. //
  724. pps->fDragging = FALSE;
  725. pps->hCursorCurrent = pps->hCursorNormal;
  726. ::SetCursor(pps->hCursorCurrent);
  727. // Release capture
  728. if (::GetCapture() == pps->hwnd)
  729. {
  730. ::ReleaseCapture();
  731. }
  732. if (fComplete && pps->fPageOpsAllowed && !WB_Locked())
  733. {
  734. HWND hwndList;
  735. //
  736. // Is this over the listbox client?
  737. //
  738. hwndList = ::GetDlgItem(pps->hwnd, IDC_PS_THUMBNAILS);
  739. ::GetClientRect(hwndList, &rc);
  740. ::MapWindowPoints(hwndList, pps->hwnd, (LPPOINT)&rc, 2);
  741. pt.x = x;
  742. pt.y = y;
  743. if (::PtInRect(&rc, pt))
  744. {
  745. //
  746. // If there is no item at this point, use the last one
  747. //
  748. ::MapWindowPoints(pps->hwnd, hwndList, &pt, 1);
  749. iItem = (int)::SendMessage(hwndList, LB_ITEMFROMPOINT, 0,
  750. MAKELONG(pt.x, pt.y));
  751. if (iItem == -1)
  752. iItem = (int)::SendMessage(hwndList, LB_GETCOUNT, 0, 0) - 1;
  753. if (g_pMain->GetLock(WB_LOCK_TYPE_CONTENTS, SW_HIDE))
  754. {
  755. // Move the page
  756. MovePage(pps, pps->iPageDragging, iItem+1);
  757. }
  758. }
  759. }
  760. pps->iPageDragging = 0;
  761. }
  762. //
  763. //
  764. // Function: MovePage
  765. //
  766. // Purpose: Move a page in the core
  767. //
  768. //
  769. void MovePage(PAGESORT * pps, int iOldPageNo, int iNewPageNo)
  770. {
  771. int iCountPages;
  772. MLZ_EntryOut(ZONE_FUNCTION, "PageSortDlgProc::MovePage");
  773. ASSERT(iNewPageNo > 0);
  774. ASSERT(iOldPageNo > 0);
  775. if (!pps->fPageOpsAllowed)
  776. return;
  777. // If the new page number is bigger than the number of pages, assume
  778. // that the last page is meant.
  779. iCountPages = (int)::SendDlgItemMessage(pps->hwnd, IDC_PS_THUMBNAILS, LB_GETCOUNT, 0, 0);
  780. if (iNewPageNo > iCountPages)
  781. {
  782. iNewPageNo = iCountPages;
  783. }
  784. // If no change will result, do nothing
  785. if ( (iNewPageNo != iOldPageNo)
  786. && (iNewPageNo != (iOldPageNo + 1)))
  787. {
  788. // If we are moving a page up the list we use move after to allow
  789. // the moving of a page to be the last page. If we are moving a page
  790. // down the list we use move before so that we can move a page to
  791. // be the first page.
  792. // it down. We check here which is meant.
  793. // Assume that we want to move the page up the list
  794. BOOL bMoveAfter = FALSE;
  795. if (iOldPageNo < iNewPageNo)
  796. {
  797. bMoveAfter = TRUE;
  798. iNewPageNo -= 1;
  799. }
  800. // Only do the move if we have requested to move the page to a new place
  801. if (iOldPageNo != iNewPageNo)
  802. {
  803. // get lock
  804. if (!g_pMain->GetLock(WB_LOCK_TYPE_CONTENTS, SW_HIDE))
  805. return;
  806. UINT uiRet;
  807. WB_PAGE_HANDLE hOldPage = PG_GetPageNumber((UINT) iOldPageNo);
  808. WB_PAGE_HANDLE hNewPage = PG_GetPageNumber((UINT) iNewPageNo);
  809. // Move the page
  810. if (bMoveAfter)
  811. {
  812. uiRet = g_pwbCore->WBP_PageMove(hNewPage, hOldPage, PAGE_AFTER);
  813. }
  814. else
  815. {
  816. uiRet = g_pwbCore->WBP_PageMove(hNewPage, hOldPage, PAGE_BEFORE);
  817. }
  818. if (uiRet != 0)
  819. {
  820. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  821. return;
  822. }
  823. // Show that the pages have been manipulated
  824. pps->fChanged = TRUE;
  825. }
  826. }
  827. }