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.

1685 lines
48 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: fldbar.cpp
  5. //
  6. // PURPOSE: Implements CFolderBar
  7. //
  8. #include "pch.hxx"
  9. #include <iert.h>
  10. #include "fldbar.h"
  11. #include "resource.h"
  12. #include <shlwapi.h>
  13. #include "treeview.h"
  14. #include "ourguid.h"
  15. #include "goptions.h"
  16. #include "browser.h"
  17. #include "imnglobl.h"
  18. #include "inpobj.h"
  19. #include "storutil.h"
  20. #include <strconst.h>
  21. #include "demand.h"
  22. #include "dragdrop.h"
  23. #include "multiusr.h"
  24. #include "instance.h"
  25. #include "mirror.h"
  26. // Margins
  27. #define CX_MARGIN_CHILDINDICATOR 4 // space between folder text and child indicator
  28. #define CX_MARGIN_TEXT 5 // space between left edge and folder text
  29. #define CX_MARGIN_ICON 4 // 5 space between left edge and icon
  30. #define CX_MARGIN_ICONTEXT 5 // space between icon and view text
  31. #define CY_MARGIN_ICON 4 // border around icon
  32. #define CY_MARGIN_TEXTTOP 2 // space between folder name and top edge of bar
  33. #define CY_MARGIN_TEXTBOTTOM 2 // space between folder name and bottom edge of bar
  34. #define CY_MARGIN 4 // 4? margin below control
  35. #define CX_MARGIN_RIGHTEDGE 2 // margin between the right edge of the bar and the right edge of the window
  36. #define CX_MARGIN_FOLDERVIEWTEXT 5 // space between folder and view text
  37. #define CXY_MARGIN_FLYOUT 4 // 4? margin around flyout scope pane
  38. // Width/Height of child indicator bitmap
  39. #define CX_LARGE_CHILDINDICATOR 8
  40. #define CY_LARGE_CHILDINDICATOR 4
  41. #define CX_SMALL_CHILDINDICATOR 4
  42. #define CY_SMALL_CHILDINDICATOR 2
  43. #define CX_SMALLICON 16
  44. #define CY_SMALLICON 16
  45. #define DY_SMALLLARGE_CUTOFF 12 // folder bar is small when it takes up more than
  46. // DY_SMALLLARGE_CUTOFF percent of the available space
  47. // Fly out constants
  48. #define FLYOUT_INCREMENT 5
  49. // Minimum width of flyout scope pane
  50. #define CX_MINWIDTH_FLYOUT 200
  51. // Mouse-Over timer ID and interval
  52. #define IDT_MOUSEOVERCHECK 456
  53. #define ELAPSE_MOUSEOVERCHECK 250
  54. // Drag/Drop mouse-over dropdown timer ID (interval is defined by OLE)
  55. #define IDT_DROPDOWNCHECK 457
  56. // Drag/Drop mouse leave dropdown removal timer ID and interval
  57. #define IDT_SCOPECLOSECHECK 458
  58. #define ELAPSE_SCOPECLOSECHECK 500
  59. CFolderBar::CFolderBar()
  60. {
  61. m_cRef = 1;
  62. m_fShow = FALSE;
  63. m_fRecalc = TRUE;
  64. m_fHighlightIndicator = FALSE;
  65. m_fHoverTimer = FALSE;
  66. m_idFolder = FOLDERID_INVALID;
  67. m_pSite = NULL;
  68. m_hwnd = NULL;
  69. m_hwndFrame = NULL;
  70. m_hwndParent = NULL;
  71. m_hwndScopeDropDown = NULL;
  72. m_hfFolderName = 0;
  73. m_hfViewText = 0;
  74. m_hIconSmall = 0;
  75. m_pszFolderName = NULL;
  76. m_cchFolderName = 0;
  77. m_pszViewText = NULL;
  78. m_cchViewText = 0;
  79. m_pDataObject = NULL;
  80. m_pDTCur = NULL;
  81. m_dwEffectCur = 0;
  82. m_grfKeyState = 0;
  83. }
  84. CFolderBar::~CFolderBar()
  85. {
  86. Assert(m_cRef == 0);
  87. SafeRelease(m_pSite);
  88. SafeRelease(m_pDataObject);
  89. SafeRelease(m_pDTCur);
  90. SafeMemFree(m_pszFolderName);
  91. SafeMemFree(m_pszViewText);
  92. SafeRelease(m_pBrowser);
  93. if (IsWindow(m_hwndFrame))
  94. DestroyWindow(m_hwndFrame);
  95. if (m_hfFolderName)
  96. DeleteObject(m_hfFolderName);
  97. if (m_hfViewText)
  98. DeleteObject(m_hfViewText);
  99. }
  100. HRESULT CFolderBar::HrInit(IAthenaBrowser *pBrowser)
  101. {
  102. m_pBrowser = pBrowser;
  103. // Don't addref this. It creates a circular ref count with the browser.
  104. // m_pBrowser->AddRef();
  105. BOOL fInfoColumn = FALSE;
  106. if (SUCCEEDED(m_pBrowser->GetViewLayout(DISPID_MSGVIEW_FOLDERLIST, 0, &fInfoColumn, 0, 0)))
  107. m_fDropDownIndicator = !fInfoColumn;
  108. return (S_OK);
  109. }
  110. HRESULT CFolderBar::QueryInterface(REFIID riid, LPVOID *ppvObj)
  111. {
  112. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleWindow) ||
  113. IsEqualIID(riid, IID_IDockingWindow))
  114. {
  115. *ppvObj = (IDockingWindow *) this;
  116. m_cRef++;
  117. return (S_OK);
  118. }
  119. else if (IsEqualIID(riid, IID_IObjectWithSite))
  120. {
  121. *ppvObj = (IObjectWithSite *)this;
  122. m_cRef++;
  123. return (S_OK);
  124. }
  125. else if (IsEqualIID(riid, IID_IDropTarget))
  126. {
  127. *ppvObj = (IDropTarget *) this;
  128. m_cRef++;
  129. return (S_OK);
  130. }
  131. *ppvObj = NULL;
  132. return (E_NOINTERFACE);
  133. }
  134. ULONG CFolderBar::AddRef(void)
  135. {
  136. return (m_cRef++);
  137. }
  138. ULONG CFolderBar::Release(void)
  139. {
  140. m_cRef--;
  141. if (m_cRef > 0)
  142. return (m_cRef);
  143. delete this;
  144. return (0);
  145. }
  146. HRESULT CFolderBar::GetWindow(HWND *pHwnd)
  147. {
  148. if (m_hwnd)
  149. {
  150. *pHwnd = m_hwnd;
  151. return (S_OK);
  152. }
  153. else
  154. {
  155. *pHwnd = NULL;
  156. return (E_FAIL);
  157. }
  158. }
  159. HRESULT CFolderBar::ContextSensitiveHelp(BOOL fEnterMode)
  160. {
  161. return (E_NOTIMPL);
  162. }
  163. //
  164. // FUNCTION: CFolderBar::ShowDW()
  165. //
  166. // PURPOSE: Causes the folder bar to be either shown or hidden.
  167. //
  168. // PARAMETERS:
  169. // <in> fShow - TRUE if the folder bar should be shown, FALSE to hide.
  170. //
  171. // RETURN VALUE:
  172. // HRESULT
  173. //
  174. #define FOLDERBARCLASS TEXT("FolderBar Window")
  175. #define FRAMECLASS TEXT("FolderBar Frame")
  176. HRESULT CFolderBar::ShowDW(BOOL fShow)
  177. {
  178. HRESULT hr = S_OK;
  179. TCHAR szName[CCHMAX_STRINGRES] = {0};
  180. DWORD dwErr;
  181. // If we have a site pointer, but haven't been created yet, create the window
  182. if (!m_hwndFrame && m_pSite)
  183. {
  184. m_hwndParent = NULL;
  185. hr = m_pSite->GetWindow(&m_hwndParent);
  186. if (SUCCEEDED(hr))
  187. {
  188. WNDCLASSEX wc = {0};
  189. // Check to see if we need to register the class first
  190. wc.cbSize = sizeof(WNDCLASSEX);
  191. if (!GetClassInfoEx(g_hInst, FOLDERBARCLASS, &wc))
  192. {
  193. wc.lpfnWndProc = FolderWndProc;
  194. wc.hInstance = g_hInst;
  195. wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  196. wc.lpszClassName = FOLDERBARCLASS;
  197. if (!RegisterClassEx(&wc))
  198. {
  199. dwErr = GetLastError();
  200. }
  201. wc.lpfnWndProc = FrameWndProc;
  202. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  203. wc.lpszClassName = FRAMECLASS;
  204. if (!RegisterClassEx(&wc))
  205. {
  206. dwErr = GetLastError();
  207. }
  208. }
  209. m_hwndFrame = CreateWindow(FRAMECLASS, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  210. 0, 0, 1, 1, m_hwndParent, (HMENU) 0, g_hInst, (LPVOID *) this);
  211. if (!m_hwndFrame)
  212. {
  213. GetLastError();
  214. return (E_OUTOFMEMORY);
  215. }
  216. LoadString(g_hLocRes, idsFolderBar, szName, ARRAYSIZE(szName));
  217. m_hwnd = CreateWindow(FOLDERBARCLASS, szName, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
  218. 0, 0, 0, 0, m_hwndFrame, (HMENU) 0, g_hInst, (LPVOID*) this);
  219. if (!m_hwnd)
  220. {
  221. GetLastError();
  222. return (E_OUTOFMEMORY);
  223. }
  224. RegisterDragDrop(m_hwnd, (IDropTarget *) this);
  225. }
  226. }
  227. // Set our state flags
  228. m_fShow = fShow;
  229. // Resize the folder bar based on its new hidden / visible state
  230. if (m_hwndFrame)
  231. {
  232. ResizeBorderDW(NULL, NULL, FALSE);
  233. ShowWindow(m_hwndFrame, fShow ? SW_SHOW : SW_HIDE);
  234. }
  235. return (hr);
  236. }
  237. //
  238. // FUNCTION: CFolderBar::CloseDW()
  239. //
  240. // PURPOSE: Destroys the folder bar.
  241. //
  242. HRESULT CFolderBar::CloseDW(DWORD dwReserved)
  243. {
  244. if (m_hwndFrame)
  245. {
  246. DestroyWindow(m_hwndFrame);
  247. m_hwndFrame = NULL;
  248. m_hwnd = NULL;
  249. }
  250. return S_OK;
  251. }
  252. //
  253. // FUNCTION: CFolderBar::ResizeBorderDW()
  254. //
  255. // PURPOSE: This is called when the folder bar needs to resize. The bar
  256. // in return figures out how much border space will be required
  257. // from the parent frame and tells the parent to reserve that
  258. // space. The bar then resizes itself to those dimensions.
  259. //
  260. // PARAMETERS:
  261. // <in> prcBorder - Rectangle containing the border space for the
  262. // parent.
  263. // <in> punkToolbarSite - Pointer to the IDockingWindowSite that we are
  264. // part of.
  265. // <in> fReserved - Ignored.
  266. //
  267. // RETURN VALUE:
  268. // HRESULT
  269. //
  270. HRESULT CFolderBar::ResizeBorderDW(LPCRECT prcBorder,
  271. IUnknown* punkToolbarSite,
  272. BOOL fReserved)
  273. {
  274. RECT rcRequest = {0, 0, 0, 0};
  275. BOOL fFontChange;
  276. if (!m_pSite)
  277. return (E_FAIL);
  278. if (m_fShow)
  279. {
  280. RECT rcBorder;
  281. if (!prcBorder)
  282. {
  283. // Find out how big our parent's border space is
  284. m_pSite->GetBorderDW((IDockingWindow *) this, &rcBorder);
  285. prcBorder = &rcBorder;
  286. }
  287. if (m_fRecalc)
  288. {
  289. fFontChange = TRUE;
  290. InvalidateRect(m_hwnd, NULL, TRUE);
  291. }
  292. else
  293. {
  294. fFontChange = FALSE;
  295. InvalidateRect(m_hwnd, NULL, TRUE);
  296. }
  297. // Recalc our internal sizing info
  298. Recalc(NULL, prcBorder, fFontChange);
  299. // Position ourself
  300. rcRequest.top = m_cyControl + CY_MARGIN;
  301. SetWindowPos(m_hwndFrame, NULL, prcBorder->left, prcBorder->top, prcBorder->right - prcBorder->left,
  302. rcRequest.top, SWP_NOACTIVATE | SWP_NOZORDER);
  303. }
  304. m_pSite->SetBorderSpaceDW((IDockingWindow *) this, &rcRequest);
  305. return (S_OK);
  306. }
  307. //
  308. // FUNCTION: CFolderBar::SetSite()
  309. //
  310. // PURPOSE: Allows the owner of the coolbar to tell it what the current
  311. // IDockingWindowSite interface to use is.
  312. //
  313. // PARAMETERS:
  314. // <in> punkSite - Pointer of the IUnknown to query for IDockingWindowSite.
  315. // If this is NULL, we just release our current pointer.
  316. //
  317. // RETURN VALUE:
  318. // S_OK - Everything worked
  319. // E_FAIL - Could not get IDockingWindowSite from the punkSite provided.
  320. //
  321. HRESULT CFolderBar::SetSite(IUnknown* punkSite)
  322. {
  323. // If we had a previous pointer, release it.
  324. if (m_pSite)
  325. {
  326. m_pSite->Release();
  327. m_pSite = NULL;
  328. }
  329. // If a new site was provided, get the IDockingWindowSite interface from it.
  330. if (punkSite)
  331. {
  332. if (FAILED(punkSite->QueryInterface(IID_IDockingWindowSite,
  333. (LPVOID*) &m_pSite)))
  334. {
  335. Assert(m_pSite);
  336. return E_FAIL;
  337. }
  338. }
  339. return (S_OK);
  340. }
  341. HRESULT CFolderBar::GetSite(REFIID riid, LPVOID *ppvSite)
  342. {
  343. return E_NOTIMPL;
  344. }
  345. //
  346. // FUNCTION: CFolderBar::SetCurrentFolder()
  347. //
  348. // PURPOSE: Tells the control to display information for a different folder
  349. //
  350. // PARAMETERS:
  351. // <in> pidl - PIDL for the new folder
  352. //
  353. // RETURN VALUE:
  354. // HRESULT
  355. //
  356. HRESULT CFolderBar::SetCurrentFolder(FOLDERID idFolder)
  357. {
  358. // NOTE - This routine never fails. It will just show everything blank
  359. UINT uIndex = -1;
  360. TCHAR sz[CCHMAX_STRINGRES];
  361. FOLDERINFO Folder;
  362. // Invalidate and let the paint routine know that we're going to need to
  363. // recalc
  364. m_fRecalc = TRUE;
  365. InvalidateRect(m_hwnd, NULL, TRUE);
  366. // Save the Folder Id
  367. m_idFolder = idFolder;
  368. // Get Folder Info
  369. if (FAILED(g_pStore->GetFolderInfo(idFolder, &Folder)))
  370. return (S_OK);
  371. // Set Icon
  372. uIndex = GetFolderIcon(&Folder);
  373. // Clear the view text
  374. SetFolderText(MU_GetCurrentIdentityName());
  375. if ((g_dwAthenaMode & MODE_NEWSONLY) && (Folder.tyFolder == FOLDER_ROOTNODE))
  376. {
  377. //Change the name from OutLookExpress to Outlook News
  378. ZeroMemory(sz, sizeof(TCHAR) * CCHMAX_STRINGRES);
  379. LoadString(g_hLocRes, idsOutlookNewsReader, sz, ARRAYSIZE(sz));
  380. SetFolderName(sz);
  381. }
  382. else
  383. {
  384. // Set the folder name
  385. SetFolderName(Folder.pszName);
  386. }
  387. // Free the previous icons
  388. if (m_hIconSmall)
  389. {
  390. DestroyIcon(m_hIconSmall);
  391. m_hIconSmall = 0;
  392. }
  393. if (-1 != uIndex)
  394. {
  395. // Load the small icon
  396. HIMAGELIST himl = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0,
  397. RGB(255, 0, 255));
  398. if (NULL != himl)
  399. {
  400. m_hIconSmall = ImageList_GetIcon(himl, uIndex, ILD_NORMAL);
  401. ImageList_Destroy(himl);
  402. }
  403. }
  404. // If this folder is moderated or blocked, say so
  405. TCHAR szRes[CCHMAX_STRINGRES];
  406. if (Folder.dwFlags & FOLDER_MODERATED)
  407. {
  408. AthLoadString(idsModerated, szRes, ARRAYSIZE(szRes));
  409. SetFolderText(szRes);
  410. }
  411. else if (Folder.dwFlags & FOLDER_BLOCKED)
  412. {
  413. AthLoadString(idsBlocked, szRes, ARRAYSIZE(szRes));
  414. SetFolderText(szRes);
  415. }
  416. g_pStore->FreeRecord(&Folder);
  417. return (S_OK);
  418. }
  419. void CFolderBar::SetFolderText(LPCTSTR pszText)
  420. {
  421. // Invalidate and let the paint routine know we are going to need to
  422. // recalc
  423. m_fRecalc = TRUE;
  424. InvalidateRect(m_hwnd, NULL, TRUE);
  425. // Free an old text
  426. SafeMemFree(m_pszViewText);
  427. m_cchViewText = 0;
  428. if (pszText && *pszText)
  429. {
  430. m_pszViewText = PszDupA(pszText);
  431. m_cchViewText = lstrlen(pszText);
  432. }
  433. }
  434. void CFolderBar::SetFolderName(LPCTSTR pszFolderName)
  435. {
  436. // Free the old folder name
  437. SafeMemFree(m_pszFolderName);
  438. m_cchFolderName = 0;
  439. // Copy the new one
  440. if (pszFolderName)
  441. {
  442. m_pszFolderName = PszDupA(pszFolderName);
  443. m_cchFolderName = lstrlen(m_pszFolderName);
  444. }
  445. }
  446. // Calculates the rectangle which surrounds the folder name
  447. void CFolderBar::GetFolderNameRect(LPRECT prc)
  448. {
  449. Assert(prc);
  450. GetClientRect(m_hwnd, prc);
  451. prc->right = m_cxFolderNameRight;
  452. }
  453. void CFolderBar::Recalc(HDC hDC, LPCRECT prcAvailableSpace, BOOL fSizeChange)
  454. {
  455. int cyIcon = CY_SMALLICON,
  456. cxIcon = CX_SMALLICON;
  457. BOOL fReleaseDC;
  458. TEXTMETRIC tmFolderName,
  459. tmViewText;
  460. RECT rcClient;
  461. SIZE sFolderName,
  462. sViewText;
  463. HFONT hFontOld;
  464. // Signal that we don't need to recalc again
  465. m_fRecalc = FALSE;
  466. if (prcAvailableSpace)
  467. {
  468. rcClient.left = 0;
  469. rcClient.top = 0;
  470. rcClient.right = prcAvailableSpace->right - prcAvailableSpace->left;
  471. rcClient.bottom = prcAvailableSpace->bottom - prcAvailableSpace->top;
  472. }
  473. else
  474. GetClientRect(m_hwnd, &rcClient);
  475. // Get a device context if we were not given one
  476. if (hDC)
  477. fReleaseDC = FALSE;
  478. else
  479. {
  480. hDC = GetDC(m_hwnd);
  481. fReleaseDC = TRUE;
  482. }
  483. // Create the fonts
  484. if (fSizeChange || !m_hfFolderName || !m_hfViewText)
  485. {
  486. if (m_hfFolderName)
  487. DeleteObject(m_hfFolderName);
  488. if (m_hfViewText)
  489. DeleteObject(m_hfViewText);
  490. // Create the font we are going to use for the folder name
  491. m_hfFolderName = GetFont(idsFontFolderSmall, FW_BOLD);
  492. m_hfViewText = GetFont(idsFontViewTextSmall, FW_BOLD);
  493. // Determine the height of the control, which is whatever is larger of i
  494. // the following two things
  495. // 1) The icon height plus the icon margin
  496. // 2) The text height plus the text margin
  497. hFontOld = SelectFont(hDC, m_hfFolderName);
  498. GetTextMetrics(hDC, &tmFolderName);
  499. SelectFont(hDC, hFontOld);
  500. m_cyControl = max(cyIcon + CY_MARGIN_ICON,
  501. tmFolderName.tmHeight + CY_MARGIN_TEXTTOP + CY_MARGIN_TEXTBOTTOM);
  502. // The top of the folder name text is position so that we have the correct
  503. // amount of border at the bottom of the control
  504. m_dyFolderName = m_cyControl - tmFolderName.tmHeight - CY_MARGIN_TEXTBOTTOM;
  505. // Get the height of the view text
  506. hFontOld = SelectFont(hDC, m_hfViewText);
  507. GetTextMetrics(hDC, &tmViewText);
  508. SelectFont(hDC, hFontOld);
  509. // The view text is positioned such that it's baseline matches the baseline
  510. // of the folder name
  511. m_dyViewText = m_dyFolderName + tmFolderName.tmAscent - tmViewText.tmAscent;
  512. // The child indicator is positioned such that the bottom of the bitmap lines
  513. // up with the baseline of the folder name
  514. m_dyChildIndicator = m_cyControl - CY_MARGIN_TEXTBOTTOM - tmFolderName.tmDescent - GetYChildIndicator();
  515. // The folder icon is centered within the control
  516. m_dyIcon = (m_cyControl - cyIcon) / 2;
  517. // Number must be even to ensure good-looking triangular drop arrow.
  518. Assert(GetXChildIndicator() % 2 == 0);
  519. // Width must be multiple of height for triangle to look smooth.
  520. Assert(GetXChildIndicator() % GetYChildIndicator() == 0);
  521. }
  522. // The view text is right justified within the folder bar
  523. if (m_cchViewText)
  524. {
  525. m_rcViewText.top = m_dyViewText;
  526. m_rcViewText.right = rcClient.right - CX_MARGIN_TEXT;
  527. m_rcViewText.bottom = rcClient.bottom;
  528. m_nFormatViewText = DT_RIGHT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX;
  529. hFontOld = SelectFont(hDC, m_hfViewText);
  530. GetTextExtentPoint32(hDC, m_pszViewText, m_cchViewText, &sViewText);
  531. SelectFont(hDC, hFontOld);
  532. m_rcViewText.left = m_rcViewText.right - sViewText.cx;
  533. }
  534. // The folder name is left justified within the folder bar. It is clipped
  535. // so that it does not overlap the view text
  536. if (m_cchFolderName)
  537. {
  538. m_rcFolderName.left = CX_MARGIN_ICONTEXT + cxIcon + CX_MARGIN_ICON;
  539. m_rcFolderName.top = m_dyFolderName;
  540. if (m_cchViewText)
  541. m_rcFolderName.right = m_rcViewText.left - CX_MARGIN_FOLDERVIEWTEXT;
  542. else
  543. m_rcFolderName.right = rcClient.right;
  544. m_rcFolderName.bottom = rcClient.bottom;
  545. if (FDropDownEnabled())
  546. m_rcFolderName.right -= GetXChildIndicator() + CX_MARGIN_CHILDINDICATOR;
  547. m_nFormatFolderName = DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX;
  548. hFontOld = SelectFont(hDC, m_hfFolderName);
  549. GetTextExtentPoint32(hDC, m_pszFolderName, m_cchFolderName, &sFolderName);
  550. if (sFolderName.cx > (m_rcFolderName.right - m_rcFolderName.left))
  551. {
  552. m_nFormatFolderName |= DT_END_ELLIPSIS;
  553. #ifndef WIN16
  554. DrawTextEx(hDC, m_pszFolderName, m_cchFolderName, &m_rcFolderName,
  555. m_nFormatFolderName | DT_CALCRECT, NULL);
  556. #else
  557. DrawText(hDC, m_pszFolderName, m_cchFolderName, &m_rcFolderName,
  558. m_nFormatFolderName | DT_CALCRECT);
  559. #endif // !WIN16
  560. }
  561. else
  562. {
  563. m_nFormatFolderName |= DT_NOCLIP;
  564. m_rcFolderName.right = m_rcFolderName.left + sFolderName.cx;
  565. }
  566. SelectFont(hDC, hFontOld);
  567. m_cxFolderNameRight = m_rcFolderName.right + CX_MARGIN_TEXT;
  568. if (FDropDownEnabled())
  569. m_cxFolderNameRight += GetXChildIndicator() + CX_MARGIN_CHILDINDICATOR + 2;
  570. }
  571. // When the folder name is clipped it will always display at least one letter
  572. // followed by ellipsis. Make sure not to draw the view text over this.
  573. if (m_cchViewText)
  574. {
  575. if (m_rcViewText.left < m_rcFolderName.right + CX_MARGIN_FOLDERVIEWTEXT)
  576. m_rcViewText.left = m_rcFolderName.right + CX_MARGIN_FOLDERVIEWTEXT;
  577. else
  578. m_nFormatViewText |= DT_NOCLIP;
  579. }
  580. if (fReleaseDC)
  581. ReleaseDC(m_hwnd, hDC);
  582. }
  583. HFONT CFolderBar::GetFont(UINT idsFont, int nWeight)
  584. {
  585. // The font info is stored as a string in the resources so the localizers
  586. // can get to it. The format of the string is "face,size"
  587. TCHAR sz[CCHMAX_STRINGRES];
  588. LPTSTR pszFace, pszTok;
  589. LONG lSize;
  590. // Load the setting
  591. AthLoadString(idsFont, sz, ARRAYSIZE(sz));
  592. // Parse out the face name
  593. pszTok = sz;
  594. pszFace = StrTokEx(&pszTok, g_szComma);
  595. // Parse out the size
  596. lSize = StrToInt(StrTokEx(&pszTok, g_szComma));
  597. return(GetFont(/* pszFace*/ NULL, lSize, nWeight)); // (YST) szFace parametr was always ignored in OE 4.0,
  598. }
  599. HFONT CFolderBar::GetFont(LPTSTR pszFace, LONG lSize, int nWeight)
  600. {
  601. HFONT hf;
  602. HDC hdc = GetDC(m_hwnd);
  603. #ifndef WIN16
  604. ICONMETRICS icm;
  605. #else
  606. LOGFONT lf;
  607. #endif
  608. lSize = -MulDiv(lSize, GetDeviceCaps(hdc, LOGPIXELSY), 720);
  609. #ifndef WIN16
  610. // Get the title bar font from the system
  611. icm.cbSize = sizeof(ICONMETRICS);
  612. SystemParametersInfo(SPI_GETICONMETRICS, sizeof(ICONMETRICS),
  613. (LPVOID) &icm, FALSE);
  614. // Create the font
  615. hf = CreateFont(lSize, 0, 0, 0, nWeight, 0, 0, 0, DEFAULT_CHARSET,
  616. OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
  617. icm.lfFont.lfPitchAndFamily, (pszFace ? pszFace : icm.lfFont.lfFaceName));
  618. #else
  619. // Get the logical font infomation for the current icon-title font.
  620. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
  621. // Create the font
  622. hf = CreateFont(lSize, 0, 0, 0, nWeight /* FW_NORMAL*/, 0, 0, 0, DEFAULT_CHARSET,
  623. OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
  624. lf.lfPitchAndFamily, (pszFace ? pszFace : icm.lfFont.lfFaceName));
  625. #endif // !WIN16
  626. ReleaseDC(m_hwnd, hdc);
  627. return (hf);
  628. }
  629. void CFolderBar::OnPaint(HWND hwnd)
  630. {
  631. HDC hdc;
  632. PAINTSTRUCT ps;
  633. RECT rcClient,
  634. rc;
  635. POINT pt[3];
  636. HBRUSH hBrush,
  637. hBrushOld;
  638. HPEN hPen,
  639. hPenOld;
  640. HFONT hFontOld;
  641. COLORREF crFG = GetSysColor(COLOR_WINDOW);
  642. COLORREF crWindowText = GetSysColor(COLOR_WINDOWTEXT);
  643. #ifndef WIN16
  644. COLORREF crBtnHighlight = GetSysColor(COLOR_BTNHILIGHT);
  645. #else
  646. COLORREF crBtnHighlight = GetSysColor(COLOR_BTNHIGHLIGHT);
  647. #endif // !WIN16
  648. GetClientRect(m_hwnd, &rcClient);
  649. hdc = BeginPaint(m_hwnd, &ps);
  650. // Recalc the text positions
  651. if (m_fRecalc)
  652. Recalc(hdc, NULL, FALSE);
  653. // Paint the background
  654. hBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
  655. hBrushOld = SelectBrush(hdc, hBrush);
  656. PatBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
  657. rcClient.bottom - rcClient.top, PATCOPY);
  658. SelectBrush(hdc, hBrushOld);
  659. DeleteBrush(hBrush);
  660. // Set the foreground and background color
  661. SetBkColor(hdc, GetSysColor(COLOR_3DSHADOW));
  662. SetTextColor(hdc, crFG);
  663. // Folder name
  664. if (m_cchFolderName)
  665. {
  666. hFontOld = SelectFont(hdc, m_hfFolderName);
  667. // Use IDrawText because DrawTextEx() doesn't handle DBCS.
  668. // Note, the "bottom - top" nonsense for the last param is to undo some
  669. // vertical centering that IDrawText is trying to do that we don't want.
  670. IDrawText(hdc, m_pszFolderName, &m_rcFolderName, m_nFormatFolderName & DT_END_ELLIPSIS,
  671. m_rcFolderName.bottom - m_rcFolderName.top);
  672. SelectFont(hdc, hFontOld);
  673. }
  674. // Drop-down indicator
  675. if (FDropDownEnabled())
  676. {
  677. pt[0].x = m_rcFolderName.right + CX_MARGIN_CHILDINDICATOR;
  678. pt[0].y = m_dyChildIndicator;
  679. pt[1].x = pt[0].x + GetXChildIndicator();
  680. pt[1].y = pt[0].y;
  681. pt[2].x = pt[0].x + GetXChildIndicator() / 2;
  682. pt[2].y = pt[0].y + GetYChildIndicator();
  683. hPen = CreatePen(PS_SOLID, 1, crFG);
  684. hBrush = CreateSolidBrush(crFG);
  685. hPenOld = SelectPen(hdc, hPen);
  686. hBrushOld = SelectBrush(hdc, hBrush);
  687. Polygon(hdc, pt, 3);
  688. SelectPen(hdc, hPenOld);
  689. SelectBrush(hdc, hBrushOld);
  690. DeleteObject(hPen);
  691. DeleteObject(hBrush);
  692. }
  693. // Mouse-over highlight
  694. if (m_fHighlightIndicator || m_hwndScopeDropDown)
  695. {
  696. hPen = CreatePen(PS_SOLID, 1, m_hwndScopeDropDown ? crWindowText : crBtnHighlight);
  697. hPenOld = SelectPen(hdc, hPen);
  698. pt[0].x = rcClient.left;
  699. pt[0].y = rcClient.bottom - 1; // - CY_MARGIN;
  700. pt[1].x = rcClient.left;
  701. pt[1].y = rcClient.top;
  702. pt[2].x = m_cxFolderNameRight - 1;
  703. pt[2].y = rcClient.top;
  704. Polyline(hdc, (POINT *)&pt, 3);
  705. SelectPen(hdc, hPenOld);
  706. DeleteObject(hPen);
  707. hPen = CreatePen(PS_SOLID, 1, m_hwndScopeDropDown ? crBtnHighlight : crWindowText);
  708. hPenOld = SelectPen(hdc, hPen);
  709. pt[1].x = m_cxFolderNameRight - 1;
  710. pt[1].y = rcClient.bottom - 1; // - CY_MARGIN;
  711. pt[2].x = pt[1].x;
  712. pt[2].y = rcClient.top - 1;
  713. Polyline(hdc, (POINT *)&pt, 3);
  714. SelectPen(hdc, hPenOld);
  715. DeleteObject(hPen);
  716. }
  717. // View text
  718. if (m_cchViewText)
  719. {
  720. SetTextColor(hdc, crFG);
  721. hFontOld = SelectFont(hdc, m_hfViewText);
  722. ExtTextOut(hdc, m_rcViewText.left, m_rcViewText.top, ETO_OPAQUE | ETO_CLIPPED,
  723. &m_rcViewText, m_pszViewText, m_cchViewText, NULL);
  724. SelectFont(hdc, hFontOld);
  725. }
  726. // Folder Icon
  727. if (m_hIconSmall)
  728. {
  729. int x = rcClient.left + CX_MARGIN_ICON;
  730. int y = m_dyIcon;
  731. DrawIconEx(hdc, x, y, m_hIconSmall, CX_SMALLICON, CY_SMALLICON, 0, NULL, DI_NORMAL);
  732. }
  733. EndPaint(m_hwnd, &ps);
  734. }
  735. BOOL CFolderBar::FDropDownEnabled(void)
  736. {
  737. return (m_fDropDownIndicator);
  738. }
  739. void CFolderBar::InvalidateFolderName(void)
  740. {
  741. RECT rcFolderName;
  742. if (m_fRecalc)
  743. InvalidateRect(m_hwnd, NULL, TRUE);
  744. else
  745. {
  746. GetFolderNameRect(&rcFolderName);
  747. InvalidateRect(m_hwnd, &rcFolderName, TRUE);
  748. }
  749. }
  750. int CFolderBar::GetXChildIndicator()
  751. {
  752. return CX_SMALL_CHILDINDICATOR;
  753. }
  754. int CFolderBar::GetYChildIndicator()
  755. {
  756. return CY_SMALL_CHILDINDICATOR;
  757. }
  758. LRESULT CALLBACK CFolderBar::FolderWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  759. {
  760. CFolderBar *pThis = (CFolderBar *) GetWndThisPtr(hwnd);
  761. switch (uMsg)
  762. {
  763. case WM_NCCREATE:
  764. {
  765. pThis = (CFolderBar *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  766. SetWndThisPtr(hwnd, (LONG_PTR) pThis);
  767. return (TRUE);
  768. }
  769. HANDLE_MSG(hwnd, WM_PAINT, pThis->OnPaint);
  770. HANDLE_MSG(hwnd, WM_MOUSEMOVE, pThis->OnMouseMove);
  771. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, pThis->OnLButtonDown);
  772. HANDLE_MSG(hwnd, WM_TIMER, pThis->OnTimer);
  773. case WM_CREATE:
  774. {
  775. #ifndef WIN16
  776. if (g_pConMan)
  777. g_pConMan->Advise((IConnectionNotify*)pThis);
  778. #endif
  779. break;
  780. }
  781. case WM_DESTROY:
  782. {
  783. #ifndef WIN16
  784. if (g_pConMan)
  785. g_pConMan->Unadvise((IConnectionNotify*)pThis);
  786. #endif
  787. RevokeDragDrop(hwnd);
  788. break;
  789. }
  790. case WM_SYSCOLORCHANGE:
  791. case WM_WININICHANGE:
  792. case WM_FONTCHANGE:
  793. {
  794. pThis->Recalc(NULL, NULL, TRUE);
  795. InvalidateRect(pThis->m_hwnd, NULL, TRUE);
  796. return (0);
  797. }
  798. case WM_PALETTECHANGED:
  799. InvalidateRect(pThis->m_hwnd, NULL, TRUE);
  800. break;
  801. case WM_QUERYNEWPALETTE:
  802. InvalidateRect(pThis->m_hwnd, NULL, TRUE);
  803. return(TRUE);
  804. }
  805. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  806. }
  807. void CFolderBar::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  808. {
  809. POINT pt = {x, y};
  810. #if 0
  811. if (!IsRectEmtpy(&m_rcDragDetect) && !PtInRect(m_rcDragDetect, pt))
  812. {
  813. SetRectEmpty(m_rcDragDetect);
  814. HrBeginDrag();
  815. }
  816. else
  817. #endif
  818. DoMouseOver(&pt, MO_NORMAL);
  819. }
  820. void CFolderBar::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  821. {
  822. POINT pt = {x, y};
  823. DoMouseClick(pt, keyFlags);
  824. }
  825. void CFolderBar::OnTimer(HWND hwnd, UINT id)
  826. {
  827. RECT rcClient;
  828. POINT pt;
  829. DWORD dwMP;
  830. BOOL fHighlightOff = FALSE;
  831. dwMP = GetMessagePos();
  832. pt.x = LOWORD(dwMP);
  833. pt.y = HIWORD(dwMP);
  834. ScreenToClient(m_hwnd, &pt);
  835. if (id == IDT_MOUSEOVERCHECK)
  836. {
  837. GetClientRect(m_hwnd, &rcClient);
  838. // No need to handle mouse in client area, OnMouseMove will catch this. We
  839. // only need to catch the mouse moving out of the client area.
  840. if (!PtInRect(&rcClient, pt))
  841. {
  842. KillTimer(m_hwnd, IDT_MOUSEOVERCHECK);
  843. fHighlightOff = TRUE;
  844. }
  845. }
  846. else if (id == IDT_DROPDOWNCHECK)
  847. {
  848. DoMouseClick(pt, 0);
  849. // ??? DoDeferredCall(DEFERREDCALL_REGISTERTARGET);
  850. fHighlightOff = TRUE;
  851. }
  852. else if (id == IDT_SCOPECLOSECHECK)
  853. {
  854. KillScopeDropDown();
  855. }
  856. #ifdef DEBUG
  857. else
  858. AssertSz(FALSE, "Hey! Who has another timer going here?");
  859. #endif
  860. if (fHighlightOff)
  861. {
  862. m_fHighlightIndicator = FALSE;
  863. InvalidateFolderName();
  864. }
  865. return;
  866. }
  867. void CFolderBar::DoMouseOver(LPPOINT ppt, MOMODE moMode)
  868. {
  869. HWND hwndActive;
  870. RECT rcFolderName;
  871. if (!FDropDownEnabled() || m_hwndScopeDropDown)
  872. return;
  873. if (moMode == MO_NORMAL)
  874. {
  875. // Only do mouse-over if we are the active window and not d&d
  876. hwndActive = GetActiveWindow();
  877. if (!hwndActive || (hwndActive != m_hwndParent && IsChild(m_hwndParent, hwndActive)))
  878. return;
  879. }
  880. GetFolderNameRect(&rcFolderName);
  881. if (moMode == MO_DRAGLEAVE || moMode == MO_DRAGDROP)
  882. ppt->x = rcFolderName.left - 1; // Force point to be outside
  883. if (m_fHighlightIndicator != PtInRect(&rcFolderName, *ppt))
  884. {
  885. m_fHighlightIndicator = !m_fHighlightIndicator;
  886. InvalidateFolderName();
  887. if (moMode == MO_DRAGOVER)
  888. {
  889. if (!m_hwndScopeDropDown && m_fHoverTimer != m_fHighlightIndicator)
  890. {
  891. KillHoverTimer();
  892. if (m_fHighlightIndicator)
  893. m_fHoverTimer = (0 != SetTimer(m_hwnd, IDT_DROPDOWNCHECK, GetDoubleClickTime(), NULL));
  894. }
  895. }
  896. else
  897. {
  898. KillTimer(m_hwnd, IDT_MOUSEOVERCHECK);
  899. if (m_fHighlightIndicator)
  900. SetTimer(m_hwnd, IDT_MOUSEOVERCHECK, ELAPSE_MOUSEOVERCHECK, NULL);
  901. }
  902. }
  903. }
  904. void CFolderBar::KillHoverTimer()
  905. {
  906. if (m_fHoverTimer)
  907. {
  908. KillTimer(m_hwnd, IDT_DROPDOWNCHECK);
  909. m_fHoverTimer = fFalse;
  910. }
  911. }
  912. void CFolderBar::DoMouseClick(POINT pt, DWORD grfKeyState)
  913. {
  914. RECT rcFolderName;
  915. if (!FDropDownEnabled())
  916. return;
  917. GetFolderNameRect(&rcFolderName);
  918. if (PtInRect(&rcFolderName, pt))
  919. {
  920. if (IsWindow(m_hwndScopeDropDown))
  921. KillScopeDropDown();
  922. else
  923. {
  924. KillHoverTimer();
  925. HrShowScopeFlyOut();
  926. }
  927. }
  928. }
  929. void CFolderBar::KillScopeDropDown(void)
  930. {
  931. POINT pt;
  932. // During window destruction hwndScopeDropDown gets set to NULL.
  933. if (IsWindow(m_hwndScopeDropDown))
  934. {
  935. KillScopeCloseTimer();
  936. DestroyWindow(m_hwndScopeDropDown);
  937. m_hwndScopeDropDown = NULL;
  938. pt.x = pt.y = 0;
  939. DoMouseOver(&pt, MO_DRAGLEAVE);
  940. }
  941. }
  942. void CFolderBar::SetScopeCloseTimer(void)
  943. {
  944. KillScopeCloseTimer();
  945. // If we can't set the timer, we just do it immediately.
  946. if (!SetTimer(m_hwnd, IDT_SCOPECLOSECHECK, ELAPSE_SCOPECLOSECHECK, NULL))
  947. SendMessage(m_hwnd, WM_TIMER, (WPARAM) IDT_SCOPECLOSECHECK, NULL);
  948. }
  949. void CFolderBar::KillScopeCloseTimer(void)
  950. {
  951. KillTimer(m_hwnd, IDT_SCOPECLOSECHECK);
  952. }
  953. HRESULT CFolderBar::HrShowScopeFlyOut(void)
  954. {
  955. IAthenaBrowser *pBrowser = NULL;
  956. CFlyOutScope *pFlyOutScope;
  957. m_pSite->QueryInterface(IID_IAthenaBrowser, (LPVOID *) &pBrowser);
  958. Assert(pBrowser);
  959. pFlyOutScope = new CFlyOutScope;
  960. if (pFlyOutScope && pBrowser)
  961. {
  962. pFlyOutScope->HrDisplay(pBrowser, this, m_hwndParent,
  963. &m_hwndScopeDropDown);
  964. InvalidateFolderName();
  965. }
  966. SafeRelease(pBrowser);
  967. return (S_OK);
  968. }
  969. void CFolderBar::Update(BOOL fDisplayNameChanged, BOOL fShowDropDownIndicator)
  970. {
  971. if (fDisplayNameChanged)
  972. {
  973. SetFolderName(NULL);
  974. }
  975. if (fShowDropDownIndicator)
  976. {
  977. BOOL fInfoColumn = FALSE;
  978. if (SUCCEEDED(m_pBrowser->GetViewLayout(DISPID_MSGVIEW_FOLDERLIST, 0, &fInfoColumn, 0, 0)))
  979. m_fDropDownIndicator = !fInfoColumn;
  980. }
  981. if (fDisplayNameChanged || fShowDropDownIndicator)
  982. {
  983. m_fRecalc = TRUE;
  984. InvalidateRect(m_hwnd, NULL, TRUE);
  985. }
  986. }
  987. HRESULT STDMETHODCALLTYPE CFolderBar::DragEnter(IDataObject* pDataObject,
  988. DWORD grfKeyState,
  989. POINTL pt, DWORD* pdwEffect)
  990. {
  991. HRESULT hr = S_OK;
  992. DOUTL(32, _T("CFolderBar::DragEnter() - Starting"));
  993. // Release Current Data Object
  994. SafeRelease(m_pDataObject);
  995. // Initialize our state
  996. SafeRelease(m_pDTCur);
  997. // Let's get a drop target
  998. if (FOLDERID_INVALID == m_idFolder)
  999. return (E_FAIL);
  1000. // Create the a Drop Target
  1001. CDropTarget *pTarget = new CDropTarget();
  1002. if (pTarget)
  1003. {
  1004. if (FAILED(hr = pTarget->Initialize(m_hwnd, m_idFolder)))
  1005. {
  1006. pTarget->Release();
  1007. return (hr);
  1008. }
  1009. }
  1010. m_pDTCur = pTarget;
  1011. // Save the Data Object
  1012. m_pDataObject = pDataObject;
  1013. m_pDataObject->AddRef();
  1014. hr = m_pDTCur->DragEnter(m_pDataObject, grfKeyState, pt, &m_dwEffectCur);
  1015. // Save Key State
  1016. m_grfKeyState = grfKeyState;
  1017. // Set the default return value to be failure
  1018. *pdwEffect = m_dwEffectCur;
  1019. return (S_OK);
  1020. }
  1021. //
  1022. // FUNCTION: CFolderBar::DragOver()
  1023. //
  1024. // PURPOSE: This is called as the user drags an object over our target.
  1025. // If we allow this object to be dropped on us, then we will have
  1026. // a pointer in m_pDataObject.
  1027. //
  1028. // PARAMETERS:
  1029. // <in> grfKeyState - Pointer to the current key states
  1030. // <in> pt - Point in screen coordinates of the mouse
  1031. // <out> pdwEffect - Where we return whether this is a valid place for
  1032. // pDataObject to be dropped and if so what type of
  1033. // drop.
  1034. //
  1035. // RETURN VALUE:
  1036. // S_OK - The function succeeded.
  1037. //
  1038. HRESULT STDMETHODCALLTYPE CFolderBar::DragOver(DWORD grfKeyState, POINTL pt,
  1039. DWORD* pdwEffect)
  1040. {
  1041. HRESULT hr = E_FAIL;
  1042. // If we don't have a stored data object from DragEnter()
  1043. if (m_pDataObject && NULL != m_pDTCur)
  1044. {
  1045. // If the keys changed, we need to re-query the drop target
  1046. if ((m_grfKeyState != grfKeyState) && m_pDTCur)
  1047. {
  1048. m_dwEffectCur = *pdwEffect;
  1049. hr = m_pDTCur->DragOver(grfKeyState, pt, &m_dwEffectCur);
  1050. }
  1051. else
  1052. {
  1053. hr = S_OK;
  1054. }
  1055. *pdwEffect = m_dwEffectCur;
  1056. m_grfKeyState = grfKeyState;
  1057. }
  1058. ScreenToClient(m_hwnd, (LPPOINT) &pt);
  1059. DoMouseOver((LPPOINT) &pt, MO_DRAGOVER);
  1060. return (hr);
  1061. }
  1062. //
  1063. // FUNCTION: CFolderBar::DragLeave()
  1064. //
  1065. // PURPOSE: Allows us to release any stored data we have from a successful
  1066. // DragEnter()
  1067. //
  1068. // RETURN VALUE:
  1069. // S_OK - Everything is groovy
  1070. //
  1071. HRESULT STDMETHODCALLTYPE CFolderBar::DragLeave(void)
  1072. {
  1073. POINT pt = {0, 0};
  1074. DOUTL(32, _T("CFolderBarView::DragLeave()"));
  1075. KillHoverTimer();
  1076. DoMouseOver(&pt, MO_DRAGLEAVE);
  1077. // SetScopeCloseTimer();
  1078. SafeRelease(m_pDTCur);
  1079. SafeRelease(m_pDataObject);
  1080. return (S_OK);
  1081. }
  1082. //
  1083. // FUNCTION: CFolderBar::Drop()
  1084. //
  1085. // PURPOSE: The user has let go of the object over our target. If we
  1086. // can accept this object we will already have the pDataObject
  1087. // stored in m_pDataObject. If this is a copy or move, then
  1088. // we go ahead and update the store. Otherwise, we bring up
  1089. // a send note with the object attached.
  1090. //
  1091. // PARAMETERS:
  1092. // <in> pDataObject - Pointer to the data object being dragged
  1093. // <in> grfKeyState - Pointer to the current key states
  1094. // <in> pt - Point in screen coordinates of the mouse
  1095. // <out> pdwEffect - Where we return whether this is a valid place for
  1096. // pDataObject to be dropped and if so what type of
  1097. // drop.
  1098. //
  1099. // RETURN VALUE:
  1100. // S_OK - Everything worked OK
  1101. //
  1102. HRESULT STDMETHODCALLTYPE CFolderBar::Drop(IDataObject* pDataObject,
  1103. DWORD grfKeyState, POINTL pt,
  1104. DWORD* pdwEffect)
  1105. {
  1106. HRESULT hr;
  1107. Assert(m_pDataObject == pDataObject);
  1108. if (m_pDTCur)
  1109. {
  1110. hr = m_pDTCur->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  1111. }
  1112. else
  1113. {
  1114. *pdwEffect = 0;
  1115. hr = S_OK;
  1116. }
  1117. KillHoverTimer();
  1118. ScreenToClient(m_hwnd, (LPPOINT) &pt);
  1119. DoMouseOver((LPPOINT) &pt, MO_DRAGDROP);
  1120. SafeRelease(m_pDataObject);
  1121. SafeRelease(m_pDTCur);
  1122. return (hr);
  1123. }
  1124. LRESULT CALLBACK CFolderBar::FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1125. LPARAM lParam)
  1126. {
  1127. CFolderBar *pThis = (CFolderBar *) GetWndThisPtr(hwnd);
  1128. switch (uMsg)
  1129. {
  1130. case WM_NCCREATE:
  1131. {
  1132. pThis = (CFolderBar *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  1133. SetWndThisPtr(hwnd, (LONG_PTR) pThis);
  1134. pThis->m_hwnd = hwnd;
  1135. return (TRUE);
  1136. }
  1137. case WM_SIZE:
  1138. {
  1139. SetWindowPos(pThis->m_hwnd, NULL, 0, 0, LOWORD(lParam) - CX_MARGIN_RIGHTEDGE,
  1140. HIWORD(lParam) - CY_MARGIN, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1141. return (TRUE);
  1142. }
  1143. }
  1144. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1145. }
  1146. #define FLYOUTSCOPECLASS _T("FlyOutScope")
  1147. HRESULT CFlyOutScope::HrDisplay(IAthenaBrowser *pBrowser, CFolderBar *pFolderBar,
  1148. HWND hwndParent, HWND *phwndScope)
  1149. {
  1150. HRESULT hr = S_OK;
  1151. RECT rc,
  1152. rcFrame,
  1153. rcView;
  1154. int cx,
  1155. cy,
  1156. cyMax,
  1157. increments,
  1158. dyOffset;
  1159. const cmsAvail = 250;
  1160. DWORD cmsUsed,
  1161. cmsLeft,
  1162. cmsThreshold,
  1163. cmsStart,
  1164. cmsNow;
  1165. Assert(pBrowser);
  1166. Assert(pFolderBar);
  1167. m_pBrowser = pBrowser;
  1168. m_pBrowser->AddRef();
  1169. m_pFolderBar = pFolderBar;
  1170. m_fResetParent = FALSE;
  1171. m_hwndParent = hwndParent;
  1172. m_pFolderBar->GetWindow(&m_hwndFolderBar);
  1173. m_hwndFocus = GetFocus();
  1174. // Create the control
  1175. WNDCLASSEX wc = {0};
  1176. // Check to see if we need to register the class first
  1177. wc.cbSize = sizeof(WNDCLASSEX);
  1178. if (!GetClassInfoEx(g_hInst, FLYOUTSCOPECLASS, &wc))
  1179. {
  1180. wc.style = 0;
  1181. wc.lpfnWndProc = FlyWndProc;
  1182. wc.cbClsExtra = 0;
  1183. wc.cbWndExtra = 0;
  1184. wc.hInstance = g_hInst;
  1185. wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  1186. wc.hbrBackground = NULL;
  1187. wc.hIcon = NULL;
  1188. IF_WIN32( wc.hIconSm = NULL; )
  1189. wc.lpszClassName = FLYOUTSCOPECLASS;
  1190. SideAssert(RegisterClassEx(&wc));
  1191. }
  1192. m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, FLYOUTSCOPECLASS, NULL,
  1193. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 0, 0,
  1194. m_hwndParent, 0, g_hInst, (LPVOID) this);
  1195. if (!m_hwnd)
  1196. {
  1197. GetLastError();
  1198. return (E_OUTOFMEMORY);
  1199. }
  1200. // Get the scope pane from the browser
  1201. m_pBrowser->GetTreeView(&m_pTreeView);
  1202. m_pTreeView->GetWindow(&m_hwndTree);
  1203. m_hwndTreeParent = GetParent(m_hwndTree);
  1204. // Turn on the pin button
  1205. SendMessage(m_hwndTree, WM_TOGGLE_CLOSE_PIN, 0, TRUE);
  1206. // Set the focus before changing the parent. In some cases, setting the
  1207. // focus, causes a selection change notification to come through. This
  1208. // makes the explorer split pane think the user has made their selection
  1209. // and shuts down the drop down scope pane before it is even shown!
  1210. HWND hwndT = GetWindow(m_hwndTree, GW_CHILD);
  1211. SetFocus(m_hwndTree);
  1212. SetParent(m_hwndTree, m_hwnd);
  1213. m_fResetParent = TRUE;
  1214. SetWindowPos(m_hwndTree, NULL, CXY_MARGIN_FLYOUT, CXY_MARGIN_FLYOUT, 0, 0,
  1215. SWP_NOSIZE | SWP_NOZORDER);
  1216. ShowWindow(m_hwndTree, SW_SHOW);
  1217. m_pTreeView->RegisterFlyOut(m_pFolderBar);
  1218. // Clear the parent for better redraw
  1219. SetParent(m_hwnd, NULL);
  1220. // Set up for the slide, the final position for the flyout will match the
  1221. // left/top/bottom edges of the view. The width of the scope pane is either
  1222. // 1/3 of the width of the view or CX_MINWIDTH_FLYOUT, whichever is larger.
  1223. // Get the position & size of the view window
  1224. m_pBrowser->GetViewRect(&rcView);
  1225. MapWindowPoints(m_hwndParent, GetDesktopWindow(), (LPPOINT) &rcView, 2);
  1226. // Determine the width of the fly-out
  1227. cx = max(CX_MINWIDTH_FLYOUT, ((rcView.right - rcView.left) / 3) + 2 * CXY_MARGIN_FLYOUT);
  1228. // Calculate the fly-out increments
  1229. cyMax = cy = (rcView.bottom - rcView.top) + (CXY_MARGIN_FLYOUT * 2);
  1230. increments = cy / FLYOUT_INCREMENT;
  1231. cy -= increments * FLYOUT_INCREMENT;
  1232. // Scope pane is positioned at it's final size so that it's size does not
  1233. // change as we drop the flyout down. This gives better redraw than resizing
  1234. // as the window drops
  1235. SetWindowPos(m_hwndTree, NULL, 0, 0, cx - CXY_MARGIN_FLYOUT * 2, cyMax - CXY_MARGIN_FLYOUT * 2,
  1236. SWP_NOMOVE | SWP_NOZORDER);
  1237. // Move the window to its initial position
  1238. GetWindowRect(m_hwndFolderBar, &rc);
  1239. MoveWindow(m_hwnd, IS_WINDOW_RTL_MIRRORED(m_hwndParent) ? (rc.right + CXY_MARGIN_FLYOUT - cx) : (rc.left - CXY_MARGIN_FLYOUT), rcView.top - CXY_MARGIN_FLYOUT,
  1240. cx, cy, FALSE);
  1241. ShowWindow(m_hwnd, SW_SHOW);
  1242. SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  1243. #ifndef WIN16
  1244. if (GetSystemMetrics(SM_SLOWMACHINE))
  1245. {
  1246. // On a slow machine, just show the thing
  1247. SetWindowPos(m_hwnd, NULL, 0, 0, cx, cyMax, SWP_NOMOVE | SWP_NOZORDER);
  1248. }
  1249. else
  1250. #endif // !WIN16
  1251. {
  1252. // Whoosh down to the bottom of the frame. We want to do this in ~250ms on any
  1253. // CPU. In order to make this work on differing machine speeds, we double
  1254. // the slide speed everytime the remaining time is halved. If the remaining time
  1255. // is negative, it will finish the slide in one step.
  1256. dyOffset = FLYOUT_INCREMENT;
  1257. cmsStart = ::GetTickCount();
  1258. cmsThreshold = cmsAvail;
  1259. while (cy <= cyMax)
  1260. {
  1261. // Slide the window down
  1262. cy += dyOffset;
  1263. SetWindowPos(m_hwnd, NULL, 0, 0, cx, min(cy, cyMax), SWP_NOMOVE | SWP_NOZORDER);
  1264. UpdateWindow(m_hwnd);
  1265. UpdateWindow(m_hwndTree);
  1266. // Determine the next increment based on time remaining
  1267. cmsNow = GetTickCount();
  1268. cmsUsed = cmsNow - cmsStart;
  1269. if (cmsUsed > cmsAvail && cy < cyMax)
  1270. {
  1271. // Finish it in one step
  1272. cy = cyMax;
  1273. }
  1274. else
  1275. {
  1276. // Double scroll step if time remaining is halved since the
  1277. // last time we double the scroll step
  1278. cmsLeft = cmsAvail - cmsUsed;
  1279. if (cmsLeft < cmsThreshold)
  1280. {
  1281. dyOffset *= 2;
  1282. cmsThreshold /= 2;
  1283. }
  1284. }
  1285. }
  1286. }
  1287. *phwndScope = m_hwnd;
  1288. return (hr);
  1289. }
  1290. LRESULT CALLBACK CFlyOutScope::FlyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1291. {
  1292. CFlyOutScope *pThis = (CFlyOutScope *) GetWndThisPtr(hwnd);
  1293. switch (uMsg)
  1294. {
  1295. case WM_NCCREATE:
  1296. {
  1297. pThis = (CFlyOutScope *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  1298. SetWndThisPtr(hwnd, (LONG_PTR) pThis);
  1299. pThis->m_hwnd = hwnd;
  1300. return (TRUE);
  1301. }
  1302. HANDLE_MSG(hwnd, WM_PAINT, pThis->OnPaint);
  1303. HANDLE_MSG(hwnd, WM_NOTIFY, pThis->OnNotify);
  1304. HANDLE_MSG(hwnd, WM_DESTROY, pThis->OnDestroy);
  1305. HANDLE_MSG(hwnd, WM_SIZE, pThis->OnSize);
  1306. case WM_NCDESTROY:
  1307. {
  1308. pThis->Release();
  1309. break;
  1310. }
  1311. }
  1312. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1313. }
  1314. BOOL CFlyOutScope::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
  1315. {
  1316. return (0);
  1317. }
  1318. void CFlyOutScope::OnPaint(HWND hwnd)
  1319. {
  1320. HDC hdc;
  1321. RECT rcClient;
  1322. PAINTSTRUCT ps;
  1323. GetClientRect(hwnd, &rcClient);
  1324. // Paint the background
  1325. hdc = BeginPaint(hwnd, &ps);
  1326. SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
  1327. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, NULL, 0, NULL);
  1328. // Draw the 3D edge
  1329. DrawEdge(hdc, &rcClient, EDGE_RAISED, BF_RECT);
  1330. EndPaint(hwnd, &ps);
  1331. }
  1332. void CFlyOutScope::OnSize(HWND hwnd, UINT state, int cx, int cy)
  1333. {
  1334. RECT rc;
  1335. GetClientRect(hwnd, &rc);
  1336. InvalidateRect(hwnd, &rc, FALSE);
  1337. InflateRect(&rc, -CXY_MARGIN_FLYOUT, -CXY_MARGIN_FLYOUT);
  1338. ValidateRect(hwnd, &rc);
  1339. }
  1340. void CFlyOutScope::OnDestroy(HWND hwnd)
  1341. {
  1342. // Make sure to kill any bogus timers still lying around
  1343. m_pFolderBar->KillScopeCloseTimer();
  1344. m_pFolderBar->ScopePaneDied();
  1345. // Reset the parent of the scope pane back to the browser
  1346. if (m_fResetParent)
  1347. {
  1348. ShowWindow(m_hwndTree, SW_HIDE);
  1349. SendMessage(m_hwndTree, WM_TOGGLE_CLOSE_PIN, 0, FALSE);
  1350. SetParent(m_hwndTree, m_hwndTreeParent);
  1351. m_pTreeView->RevokeFlyOut();
  1352. }
  1353. // Set the parent of the drop down pane itself back
  1354. SetParent(m_hwnd, m_hwndFolderBar);
  1355. // $TODO - Review where the focus is supposed to go
  1356. HWND hwndBrowser;
  1357. if (m_pBrowser)
  1358. {
  1359. m_pBrowser->GetWindow(&hwndBrowser);
  1360. PostMessage(hwndBrowser, WM_OESETFOCUS, (WPARAM) m_hwndFocus, 0);
  1361. }
  1362. }
  1363. CFlyOutScope::CFlyOutScope()
  1364. {
  1365. m_cRef = 1;
  1366. m_pBrowser = 0;
  1367. m_pFolderBar = 0;
  1368. m_fResetParent = 0;
  1369. m_pTreeView = NULL;
  1370. m_hwnd = NULL;
  1371. m_hwndParent = NULL;
  1372. m_hwndTree = NULL;
  1373. m_hwndFolderBar = NULL;
  1374. }
  1375. CFlyOutScope::~CFlyOutScope()
  1376. {
  1377. SafeRelease(m_pBrowser);
  1378. SafeRelease(m_pTreeView);
  1379. }
  1380. ULONG CFlyOutScope::AddRef(void)
  1381. {
  1382. return (++m_cRef);
  1383. }
  1384. ULONG CFlyOutScope::Release(void)
  1385. {
  1386. ULONG cRefT = --m_cRef;
  1387. if (m_cRef == 0)
  1388. delete this;
  1389. return (cRefT);
  1390. }
  1391. HRESULT CFolderBar::OnConnectionNotify(CONNNOTIFY nCode, LPVOID pvData, CConnectionManager *pConMan)
  1392. {
  1393. m_fRecalc = TRUE;
  1394. InvalidateRect(m_hwnd, NULL, TRUE);
  1395. return S_OK;
  1396. }