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.

1671 lines
43 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: navpane.cpp
  5. //
  6. // PURPOSE:
  7. //
  8. #include "pch.hxx"
  9. #include "navpane.h"
  10. #include "treeview.h"
  11. #include "baui.h"
  12. #include "browser.h"
  13. #include "menuutil.h"
  14. #include "inpobj.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Local Stuff
  17. //
  18. const TCHAR c_szNavPaneClass[] = _T("Outlook Express Navigation Pane");
  19. const TCHAR c_szPaneFrameClass[] = _T("Outlook Express Pane Frame");
  20. // Sizing consts
  21. const int c_cxBorder = 1;
  22. const int c_cyBorder = 1;
  23. const int c_cxTextBorder = 4;
  24. const int c_cyTextBorder = 2;
  25. const int c_cyClose = 3;
  26. const int c_cySplit = 4;
  27. const int c_cxSplit = 3;
  28. #define ID_PANE_CLOSE 2000
  29. #define ID_PANE_PIN 2001
  30. #define ID_PANE_TITLE 2002
  31. #define IDT_PANETIMER 100
  32. #define ELAPSE_MOUSEOVERCHECK 250
  33. /////////////////////////////////////////////////////////////////////////////
  34. // CNavPane Implementation
  35. //
  36. CNavPane::CNavPane()
  37. {
  38. m_cRef = 1;
  39. m_fShow = FALSE;
  40. m_fTreeVisible = FALSE;
  41. m_fContactsVisible = FALSE;
  42. m_hwnd = 0;
  43. m_hwndParent = 0;
  44. m_hwndTree = 0;
  45. m_hwndContacts = 0;
  46. m_pSite = NULL;
  47. m_pTreeView = NULL;
  48. m_pContacts = NULL;
  49. m_pContactsFrame = NULL;
  50. m_pContactsTarget = NULL;
  51. m_cxWidth = 200;
  52. m_fResizing = FALSE;
  53. m_fSplitting = FALSE;
  54. m_cySplitPct = 50;
  55. ZeroMemory(&m_rcSplit, sizeof(RECT));
  56. ZeroMemory(&m_rcSizeBorder, sizeof(RECT));
  57. m_cyTitleBar = 32;
  58. }
  59. CNavPane::~CNavPane()
  60. {
  61. SafeRelease(m_pContactsFrame);
  62. }
  63. HRESULT CNavPane::Initialize(CTreeView *pTreeView)
  64. {
  65. // We've got to have this
  66. if (!pTreeView)
  67. return (E_INVALIDARG);
  68. // Keep it
  69. m_pTreeView = pTreeView;
  70. m_pTreeView->AddRef();
  71. // Load some settings
  72. m_cxWidth = DwGetOption(OPT_NAVPANEWIDTH);
  73. if (m_cxWidth < 0)
  74. m_cxWidth = 200;
  75. m_cySplitPct = DwGetOption(OPT_NAVPANESPLIT);
  76. // Do some parameter checking
  77. if (m_cySplitPct > 100 || m_cySplitPct < 2)
  78. m_cySplitPct = 66;
  79. return (S_OK);
  80. }
  81. //
  82. // FUNCTION: CNavPane::QueryInterface()
  83. //
  84. // PURPOSE: Allows caller to retrieve the various interfaces supported by
  85. // this class.
  86. //
  87. HRESULT CNavPane::QueryInterface(REFIID riid, LPVOID *ppvObj)
  88. {
  89. TraceCall("CNavPane::QueryInterface");
  90. *ppvObj = NULL;
  91. if (IsEqualIID(riid, IID_IUnknown))
  92. *ppvObj = (LPVOID) (IDockingWindow *) this;
  93. else if (IsEqualIID(riid, IID_IDockingWindow))
  94. *ppvObj = (LPVOID) (IDockingWindow *) this;
  95. else if (IsEqualIID(riid, IID_IObjectWithSite))
  96. *ppvObj = (LPVOID) (IObjectWithSite *) this;
  97. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  98. *ppvObj = (LPVOID) (IOleCommandTarget *) this;
  99. else if (IsEqualIID(riid, IID_IInputObjectSite))
  100. *ppvObj = (LPVOID) (IInputObjectSite *) this;
  101. else if (IsEqualIID(riid, IID_IInputObject))
  102. *ppvObj = (LPVOID) (IInputObject *) this;
  103. if (*ppvObj)
  104. {
  105. AddRef();
  106. return (S_OK);
  107. }
  108. return (E_NOINTERFACE);
  109. }
  110. //
  111. // FUNCTION: CNavPane::AddRef()
  112. //
  113. // PURPOSE: Adds a reference count to this object.
  114. //
  115. ULONG CNavPane::AddRef(void)
  116. {
  117. TraceCall("CNavPane::AddRef");
  118. return ((ULONG) InterlockedIncrement((LONG *) &m_cRef));
  119. }
  120. //
  121. // FUNCTION: CNavPane::Release()
  122. //
  123. // PURPOSE: Releases a reference on this object.
  124. //
  125. ULONG CNavPane::Release(void)
  126. {
  127. TraceCall("CNavPane::Release");
  128. if (0 == InterlockedDecrement((LONG *) &m_cRef))
  129. {
  130. delete this;
  131. return 0;
  132. }
  133. return (m_cRef);
  134. }
  135. //
  136. // FUNCTION: CNavPane::GetWindow()
  137. //
  138. // PURPOSE: Returns the handle of our outer window
  139. //
  140. // PARAMETERS:
  141. // [out] pHwnd - return value
  142. //
  143. // RETURN VALUE:
  144. // HRESULT
  145. //
  146. HRESULT CNavPane::GetWindow(HWND *pHwnd)
  147. {
  148. TraceCall("CNavPane::GetWindow");
  149. if (!pHwnd)
  150. return (E_INVALIDARG);
  151. if (IsWindow(m_hwnd))
  152. {
  153. *pHwnd = m_hwnd;
  154. return (S_OK);
  155. }
  156. return (E_FAIL);
  157. }
  158. //
  159. // FUNCTION: CNavPane::ContextSensitiveHelp()
  160. //
  161. // PURPOSE: Does anyone _ever_ implement this?
  162. //
  163. HRESULT CNavPane::ContextSensitiveHelp(BOOL fEnterMode)
  164. {
  165. TraceCall("CNavPane::ContextSensitiveHelp");
  166. return (E_NOTIMPL);
  167. }
  168. //
  169. // FUNCTION: CNavPane::ShowDW()
  170. //
  171. // PURPOSE: Show's or hides the Nav pane. If the pane has not yet been
  172. // created it does that too.
  173. //
  174. // PARAMETERS:
  175. // [in] fShow - TRUE to show, FALSE to hide
  176. //
  177. // RETURN VALUE:
  178. // HRESULT
  179. //
  180. HRESULT CNavPane::ShowDW(BOOL fShow)
  181. {
  182. HRESULT hr;
  183. WNDCLASSEX wc;
  184. TraceCall("CNavPane::ShowDW");
  185. // Nothing works without a site pointer
  186. if (!m_pSite)
  187. return (E_UNEXPECTED);
  188. // Check to see if we've been created yet
  189. if (!m_hwnd)
  190. {
  191. // Register the window class if necessary
  192. wc.cbSize = sizeof(WNDCLASSEX);
  193. if (!GetClassInfoEx(g_hInst, c_szNavPaneClass, &wc))
  194. {
  195. wc.style = 0;
  196. wc.lpfnWndProc = _WndProc;
  197. wc.cbClsExtra = 0;
  198. wc.cbWndExtra = 0;
  199. wc.hInstance = g_hInst;
  200. wc.hCursor = LoadCursor(0, IDC_SIZEWE);
  201. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  202. wc.lpszMenuName = NULL;
  203. wc.lpszClassName = c_szNavPaneClass;
  204. wc.hIcon = NULL;
  205. wc.hIconSm = NULL;
  206. RegisterClassEx(&wc);
  207. }
  208. // Get the parent window before we create ours
  209. if (FAILED(m_pSite->GetWindow(&m_hwndParent)))
  210. {
  211. AssertSz(FALSE, "CNavPane::ShowDW() - Failed to get a parent window handle.");
  212. }
  213. // Create the window
  214. m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szNavPaneClass, NULL,
  215. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  216. 0, 0, 10, 10, m_hwndParent, (HMENU) 0, g_hInst, this);
  217. if (!m_hwnd)
  218. {
  219. AssertSz(FALSE, "CNavPane::ShowDW() - Failed to create main window.");
  220. return (E_OUTOFMEMORY);
  221. }
  222. // Create any children
  223. if (FAILED(hr = _CreateChildWindows()))
  224. {
  225. AssertSz(FALSE, "CNavPane::ShowDW() - Failed to create child windows.");
  226. DestroyWindow(m_hwnd);
  227. return (hr);
  228. }
  229. }
  230. // Show or hide the window appropriately
  231. m_fShow = (fShow && (m_fTreeVisible || m_fContactsVisible));
  232. ResizeBorderDW(0, 0, FALSE);
  233. ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
  234. return (S_OK);
  235. }
  236. //
  237. // FUNCTION: CNavPane::ResizeBorderDW()
  238. //
  239. // PURPOSE: Called when it's time for us to re-request space from our
  240. // parent.
  241. //
  242. // PARAMETERS:
  243. // [in] prcBorder - a RECT containing the outer rectangle the object can request space in
  244. // [in] punkSite - pointer to the site that changed
  245. // [in] fReserved - unused.
  246. //
  247. // RETURN VALUE:
  248. // HRESULT
  249. //
  250. HRESULT CNavPane::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkSite, BOOL fReserved)
  251. {
  252. const DWORD c_cxResizeBorder = 3;
  253. HRESULT hr = S_OK;
  254. RECT rcRequest = { 0 };
  255. RECT rcBorder;
  256. TraceCall("CNavPane::ResizeBorderDW");
  257. // If we don't have a site pointer, this ain't gonna work
  258. if (!m_pSite)
  259. return (E_UNEXPECTED);
  260. // If we visible, then calculate our border requirements. If we're not
  261. // visible, the our requirements are zero and we can use the default
  262. // values in rcRequest.
  263. Assert(IsWindow(m_hwnd));
  264. // If the caller didn't provide us with a rect, get one ourselves
  265. if (!prcBorder)
  266. {
  267. m_pSite->GetBorderDW((IDockingWindow *) this, &rcBorder);
  268. prcBorder = &rcBorder;
  269. }
  270. // The space we need is the min of either what we want to be or the
  271. // width of the parent minus some
  272. if (m_fShow)
  273. {
  274. rcRequest.left = min(prcBorder->right - prcBorder->left - 32, m_cxWidth);
  275. }
  276. // Ask for the space we need
  277. if (SUCCEEDED(m_pSite->RequestBorderSpaceDW((IDockingWindow *) this, &rcRequest)))
  278. {
  279. // Tell the site how be we're going to be
  280. if (SUCCEEDED(m_pSite->SetBorderSpaceDW((IDockingWindow *) this, &rcRequest)))
  281. {
  282. // Now once that's all done, resize ourselves if we're visible
  283. if (m_fShow)
  284. {
  285. SetWindowPos(m_hwnd, 0, prcBorder->left, prcBorder->top, rcRequest.left,
  286. prcBorder->bottom - prcBorder->top, SWP_NOZORDER | SWP_NOACTIVATE);
  287. }
  288. }
  289. }
  290. return (S_OK);
  291. }
  292. //
  293. // FUNCTION: CNavPane::CloseDW()
  294. //
  295. // PURPOSE: Called when the parent want's to destroy this window
  296. //
  297. // PARAMETERS:
  298. // [in] dwReserved - unused
  299. //
  300. // RETURN VALUE:
  301. // HRESULT
  302. //
  303. HRESULT CNavPane::CloseDW(DWORD dwReserved)
  304. {
  305. TraceCall("CNavPane::CloseDW");
  306. // Save our settings
  307. SetDwOption(OPT_NAVPANEWIDTH, m_cxWidth, NULL, 0);
  308. SetDwOption(OPT_NAVPANESPLIT, m_cySplitPct, NULL, 0);
  309. if (m_pTreeView)
  310. m_pTreeView->DeInit();
  311. if (m_hwnd)
  312. {
  313. DestroyWindow(m_hwnd);
  314. m_hwnd = NULL;
  315. }
  316. // Destroy our children here
  317. SafeRelease(m_pTreeView);
  318. SafeRelease(m_pContactsTarget);
  319. SafeRelease(m_pContacts);
  320. return (S_OK);
  321. }
  322. //
  323. // FUNCTION: CNavPane::GetSite()
  324. //
  325. // PURPOSE: Called to request an interface to our site
  326. //
  327. // PARAMETERS:
  328. // [in] riid - Requested interface
  329. // [out] ppvSite - Returned interface if available
  330. //
  331. // RETURN VALUE:
  332. // HRESULT
  333. //
  334. HRESULT CNavPane::GetSite(REFIID riid, LPVOID *ppvSite)
  335. {
  336. HRESULT hr;
  337. TraceCall("CNavPane::GetSite");
  338. if (m_pSite)
  339. {
  340. // Ask our site for the requested interface
  341. hr = m_pSite->QueryInterface(riid, ppvSite);
  342. return (hr);
  343. }
  344. return (E_FAIL);
  345. }
  346. //
  347. // FUNCTION: CNavPane::SetSite()
  348. //
  349. // PURPOSE: Called to tell us who our site will be.
  350. //
  351. // PARAMETERS:
  352. // [in] pUnkSite - Pointer to the new site
  353. //
  354. // RETURN VALUE:
  355. // HRESULT
  356. //
  357. HRESULT CNavPane::SetSite(IUnknown *pUnkSite)
  358. {
  359. HRESULT hr = S_OK;
  360. TraceCall("CNavPane::SetSite");
  361. // If we already have a site, release it
  362. if (m_pSite)
  363. {
  364. m_pSite->Release();
  365. m_pSite = 0;
  366. }
  367. // If we were given a new site, keep it
  368. if (pUnkSite)
  369. {
  370. hr = pUnkSite->QueryInterface(IID_IDockingWindowSite, (LPVOID *) &m_pSite);
  371. return (hr);
  372. }
  373. return (hr);
  374. }
  375. //
  376. // FUNCTION: CNavPane::_WndProc()
  377. //
  378. // PURPOSE: External callback.
  379. //
  380. LRESULT CALLBACK CNavPane::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  381. {
  382. CNavPane *pThis;
  383. if (uMsg == WM_NCCREATE)
  384. {
  385. pThis = (CNavPane *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  386. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
  387. }
  388. else
  389. pThis = (CNavPane *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  390. if (pThis)
  391. return (pThis->_NavWndProc(hwnd, uMsg, wParam, lParam));
  392. return (FALSE);
  393. }
  394. //
  395. // FUNCTION: CNavPane::_NavWndProc()
  396. //
  397. // PURPOSE: Left as an exercise for the reader
  398. //
  399. LRESULT CALLBACK CNavPane::_NavWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  400. {
  401. switch (uMsg)
  402. {
  403. HANDLE_MSG(hwnd, WM_SETCURSOR, _OnSetCursor);
  404. HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
  405. HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMove);
  406. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, _OnLButtonDown);
  407. HANDLE_MSG(hwnd, WM_LBUTTONUP, _OnLButtonUp);
  408. case WM_SYSCOLORCHANGE:
  409. case WM_WININICHANGE:
  410. {
  411. // Forward these to all our children
  412. if (IsWindow(m_hwndTree))
  413. SendMessage(m_hwndTree, uMsg, wParam, lParam);
  414. if (IsWindow(m_hwndContacts))
  415. SendMessage(m_hwndContacts, uMsg, wParam, lParam);
  416. // Update any of our own sizes
  417. m_cyTitleBar =(UINT) SendMessage(m_hwndTree, WM_GET_TITLE_BAR_HEIGHT, 0, 0);
  418. return (0);
  419. }
  420. }
  421. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  422. }
  423. //
  424. // FUNCTION: CNavPane::_OnSize()
  425. //
  426. // PURPOSE: When our window get's resized, we need to resize our child
  427. // windows too.
  428. //
  429. void CNavPane::_OnSize(HWND hwnd, UINT state, int cx, int cy)
  430. {
  431. RECT rc;
  432. DWORD cyTree;
  433. DWORD cySplit = c_cySplit;
  434. TraceCall("CNavPane::_OnSize");
  435. // If only the tree is visible
  436. if (m_fTreeVisible && !m_fContactsVisible)
  437. cyTree = cy;
  438. else if (m_fTreeVisible && m_fContactsVisible)
  439. cyTree = (cy * m_cySplitPct) / 100;
  440. else if (!m_fTreeVisible && m_fContactsVisible)
  441. {
  442. cyTree = 0;
  443. cySplit = 0;
  444. }
  445. // Resize the TreeView to fit inside our window
  446. if (m_hwndTree)
  447. SetWindowPos(m_hwndTree, 0, 0, 0, cx - c_cxSplit, cyTree, SWP_NOZORDER | SWP_NOACTIVATE);
  448. if (m_hwndContacts)
  449. SetWindowPos(m_hwndContacts, 0, 0, cyTree + cySplit, cx - 3, cy - cyTree - cySplit, SWP_NOZORDER | SWP_NOACTIVATE);
  450. // Figure out where a few things are, starting with the split bar
  451. SetRect(&rc, c_cxBorder, cyTree, cx - c_cxSplit - c_cxBorder, cyTree + cySplit);
  452. m_rcSplit = rc;
  453. // Figure out where the right side is
  454. SetRect(&rc, cx - c_cxSplit, 0, cx, cy);
  455. m_rcSizeBorder = rc;
  456. }
  457. //
  458. // FUNCTION: CNavPane::_OnLButtonDown()
  459. //
  460. // PURPOSE: When the user clicks down and we get this notification, it
  461. // must be because they want to resize.
  462. //
  463. void CNavPane::_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  464. {
  465. TraceCall("CNavPane::_OnLButtonDown");
  466. if (!m_fResizing)
  467. {
  468. SetCapture(hwnd);
  469. m_fResizing = TRUE;
  470. POINT pt = {x, y};
  471. if (PtInRect(&m_rcSplit, pt))
  472. {
  473. m_fSplitting = TRUE;
  474. }
  475. }
  476. }
  477. //
  478. // FUNCTION: CNavPane::_OnMouseMove()
  479. //
  480. // PURPOSE: If we're resizing, update our position etc.
  481. //
  482. void CNavPane::_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  483. {
  484. POINT pt = {x, y};
  485. RECT rcClient;
  486. TraceCall("CNavPane::_OnMouseMove");
  487. if (m_fResizing)
  488. {
  489. if (m_fSplitting)
  490. {
  491. GetClientRect(m_hwnd, &rcClient);
  492. m_cySplitPct = (int)(((float) pt.y / (float) rcClient.bottom) * 100);
  493. // Make sure we have the min's and max's right
  494. int cy = (rcClient.bottom * m_cySplitPct) / 100;
  495. if (cy < m_cyTitleBar)
  496. {
  497. m_cySplitPct = (int)(((float) m_cyTitleBar / (float) rcClient.bottom) * 100);
  498. }
  499. else if (rcClient.bottom - cy < m_cyTitleBar)
  500. {
  501. m_cySplitPct = (int)(((float) (rcClient.bottom - m_cyTitleBar) / (float) rcClient.bottom) * 100);
  502. }
  503. _OnSize(hwnd, 0, rcClient.right, rcClient.bottom);
  504. }
  505. else
  506. {
  507. if (pt.x > 32)
  508. {
  509. GetClientRect(m_hwndParent, &rcClient);
  510. m_cxWidth = max(0, min(pt.x, rcClient.right - 32));
  511. ResizeBorderDW(0, 0, FALSE);
  512. }
  513. }
  514. }
  515. }
  516. //
  517. // FUNCTION: CNavPane::_OnLButtonUp()
  518. //
  519. // PURPOSE: If the user was resizing, then they're done now and we can
  520. // clean up.
  521. //
  522. void CNavPane::_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  523. {
  524. TraceCall("CNavPane::_OnLButtonUp");
  525. if (m_fResizing)
  526. {
  527. ReleaseCapture();
  528. m_fResizing = FALSE;
  529. m_fSplitting = FALSE;
  530. }
  531. }
  532. //
  533. // FUNCTION: CNavPane::_OnSetCursor()
  534. //
  535. // PURPOSE: Do some jimmying with the cursor
  536. //
  537. BOOL CNavPane::_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
  538. {
  539. POINT pt;
  540. TraceCall("_OnSetCursor");
  541. // Get the cursor position
  542. GetCursorPos(&pt);
  543. ScreenToClient(m_hwnd, &pt);
  544. // If the cursor is within the split bar, update the cursor
  545. if (PtInRect(&m_rcSplit, pt))
  546. {
  547. SetCursor(LoadCursor(NULL, IDC_SIZENS));
  548. return (TRUE);
  549. }
  550. if (PtInRect(&m_rcSizeBorder, pt))
  551. {
  552. SetCursor(LoadCursor(NULL, IDC_SIZEWE));
  553. return (TRUE);
  554. }
  555. return (FALSE);
  556. }
  557. //
  558. // FUNCTION: CNavPane::_OnNCHitTest()
  559. //
  560. // PURPOSE: We monkey around with the non client area to get the correct
  561. // cursors
  562. //
  563. // PARAMETERS:
  564. // [in] hwnd - Window handle the mouse is in
  565. // [in] x, y - Position of the mouse in screen coordinates
  566. //
  567. // RETURN VALUE:
  568. // Our personal opinion of where the mouse is.
  569. //
  570. UINT CNavPane::_OnNCHitTest(HWND hwnd, int x, int y)
  571. {
  572. POINT pt = {x, y};
  573. // If the cursor is in the split bar
  574. if (PtInRect(&m_rcSplit, pt))
  575. return (HTTOP);
  576. if (PtInRect(&m_rcSizeBorder, pt))
  577. return (HTRIGHT);
  578. return (HTCLIENT);
  579. }
  580. //
  581. // FUNCTION: CNavPane::_CreateChildWindows()
  582. //
  583. // PURPOSE: Creates the child windows that will be displayed.
  584. //
  585. // RETURN VALUE:
  586. // HRESULT
  587. //
  588. HRESULT CNavPane::_CreateChildWindows(void)
  589. {
  590. IOleWindow *pWindow = NULL;
  591. IInputObject *pInputObj = NULL;
  592. HRESULT hr;
  593. TraceCall("CNavPane::_CreateChildWindows");
  594. // The treeview is always created by the browser. All we have to do
  595. // is tell it to create it's UI.
  596. m_hwndTree = m_pTreeView->Create(m_hwnd, (IInputObjectSite *) this, TRUE);
  597. Assert(m_hwndTree);
  598. // If the tree is supposed to be visible, show it
  599. if (DwGetOption(OPT_SHOWTREE))
  600. {
  601. ShowWindow(m_hwndTree, SW_SHOW);
  602. m_fTreeVisible = TRUE;
  603. m_cyTitleBar = (UINT) SendMessage(m_hwndTree, WM_GET_TITLE_BAR_HEIGHT, 0, 0);
  604. }
  605. // If we're showing contacts, create it
  606. if (DwGetOption(OPT_SHOWCONTACTS) && (!(g_dwAthenaMode & MODE_OUTLOOKNEWS)))
  607. {
  608. ShowContacts(TRUE);
  609. }
  610. return (S_OK);
  611. }
  612. //
  613. // FUNCTION: CNavPane::ShowFolderList()
  614. //
  615. // PURPOSE: Shows and hides the folder list doodad
  616. //
  617. // PARAMETERS:
  618. // BOOL fShow
  619. //
  620. BOOL CNavPane::ShowFolderList(BOOL fShow)
  621. {
  622. TraceCall("CNavPane::ShowFolderList");
  623. // The folder list _always_ exists. We just toggle the state
  624. ShowWindow(m_hwndTree, fShow ? SW_SHOW : SW_HIDE);
  625. m_fTreeVisible = fShow;
  626. _UpdateVisibleState();
  627. RECT rc;
  628. GetClientRect(m_hwnd, &rc);
  629. _OnSize(m_hwnd, 0, rc.right, rc.bottom);
  630. return (TRUE);
  631. }
  632. //
  633. // FUNCTION: CNavPane::ShowContacts()
  634. //
  635. // PURPOSE:
  636. //
  637. // PARAMETERS:
  638. // BOOL fShow
  639. //
  640. // RETURN VALUE:
  641. // BOOL
  642. //
  643. BOOL CNavPane::ShowContacts(BOOL fShow)
  644. {
  645. CMsgrAb *pMsgrAb;
  646. HWND hwnd;
  647. IAthenaBrowser *pBrowser;
  648. HRESULT hr;
  649. RECT rc = {0};
  650. if (!m_pContacts)
  651. {
  652. hr = CreateMsgrAbCtrl(&m_pContacts);
  653. if (SUCCEEDED(hr))
  654. {
  655. // Initialize the control
  656. m_pContactsFrame = new CPaneFrame();
  657. if (!m_pContactsFrame)
  658. return (0);
  659. m_hwndContacts = m_pContactsFrame->Initialize(m_hwnd, this, idsABBandTitle, IDR_BA_TITLE_POPUP);
  660. pMsgrAb = (CMsgrAb *) m_pContacts;
  661. hwnd = pMsgrAb->CreateControlWindow(m_hwndContacts, rc);
  662. if (hwnd)
  663. {
  664. if (SUCCEEDED(m_pSite->QueryInterface(IID_IAthenaBrowser, (LPVOID *) &pBrowser)))
  665. {
  666. m_pContactsFrame->SetChild(hwnd, DISPID_MSGVIEW_CONTACTS, pBrowser, pMsgrAb, pMsgrAb);
  667. pBrowser->Release();
  668. }
  669. }
  670. // Get the command target
  671. m_pContacts->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pContactsTarget);
  672. }
  673. }
  674. SetWindowPos(m_hwndContacts, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  675. ShowWindow(m_hwndContacts, fShow ? SW_SHOW : SW_HIDE);
  676. m_fContactsVisible = fShow;
  677. _UpdateVisibleState();
  678. GetClientRect(m_hwnd, &rc);
  679. _OnSize(m_hwnd, 0, rc.right, rc.bottom);
  680. return (TRUE);
  681. }
  682. //
  683. // FUNCTION: CNavPane::_UpdateVisibleState()
  684. //
  685. // PURPOSE: Checks to see if we need to show our hide ourselves
  686. //
  687. void CNavPane::_UpdateVisibleState(void)
  688. {
  689. // If this leaves us with nothing visible, then we hide ourselves
  690. if (!m_fTreeVisible && !m_fContactsVisible)
  691. {
  692. ShowWindow(m_hwnd, SW_HIDE);
  693. m_fShow = FALSE;
  694. ResizeBorderDW(0, 0, 0);
  695. }
  696. else if (m_fShow == FALSE && (m_fTreeVisible || m_fContactsVisible))
  697. {
  698. // Show ourselves
  699. m_fShow = TRUE;
  700. ShowWindow(m_hwnd, SW_SHOW);
  701. ResizeBorderDW(0, 0, 0);
  702. }
  703. }
  704. HRESULT CNavPane::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[],
  705. OLECMDTEXT *pCmdText)
  706. {
  707. if (m_pContactsTarget)
  708. {
  709. for (UINT i = 0; i < cCmds; i++)
  710. {
  711. if (prgCmds[i].cmdf == 0 && prgCmds[i].cmdID == ID_CONTACTS_MNEMONIC)
  712. {
  713. prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  714. }
  715. }
  716. }
  717. if (m_pContactsTarget)
  718. return (m_pContactsTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText));
  719. return (S_OK);
  720. }
  721. HRESULT CNavPane::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt,
  722. VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  723. {
  724. if (m_pContactsTarget && nCmdID == ID_CONTACTS_MNEMONIC)
  725. {
  726. m_pContactsFrame->ShowMenu();
  727. return (S_OK);
  728. }
  729. if (m_pContactsTarget)
  730. return (m_pContactsTarget->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut));
  731. return (OLECMDERR_E_NOTSUPPORTED);
  732. }
  733. BOOL CNavPane::IsContactsFocus(void)
  734. {
  735. IInputObject *pInputObject = 0;
  736. HRESULT hr = S_FALSE;
  737. if (m_pContacts)
  738. {
  739. if (SUCCEEDED(m_pContacts->QueryInterface(IID_IInputObject, (LPVOID *) &pInputObject)))
  740. {
  741. hr = pInputObject->HasFocusIO();
  742. pInputObject->Release();
  743. return (S_OK == hr);
  744. }
  745. }
  746. return (S_OK == hr);
  747. }
  748. HRESULT CNavPane::OnFocusChangeIS(IUnknown *punkSrc, BOOL fSetFocus)
  749. {
  750. // Simply call through to our host
  751. UnkOnFocusChangeIS(m_pSite, (IInputObject*) this, fSetFocus);
  752. return (S_OK);
  753. }
  754. HRESULT CNavPane::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  755. {
  756. if (fActivate)
  757. {
  758. UnkOnFocusChangeIS(m_pSite, (IInputObject *) this, TRUE);
  759. SetFocus(m_hwnd);
  760. }
  761. return (S_OK);
  762. }
  763. HRESULT CNavPane::HasFocusIO(void)
  764. {
  765. if (m_hwnd == 0)
  766. return (S_FALSE);
  767. HWND hwndFocus = GetFocus();
  768. return (hwndFocus == m_hwnd || IsChild(m_hwnd, hwndFocus)) ? S_OK : S_FALSE;
  769. }
  770. HRESULT CNavPane::TranslateAcceleratorIO(LPMSG pMsg)
  771. {
  772. if (m_pTreeView && (m_pTreeView->HasFocusIO() == S_OK))
  773. return m_pTreeView->TranslateAcceleratorIO(pMsg);
  774. if (m_pContacts && (UnkHasFocusIO(m_pContacts) == S_OK))
  775. return UnkTranslateAcceleratorIO(m_pContacts, pMsg);
  776. return (S_FALSE);
  777. }
  778. /////////////////////////////////////////////////////////////////////////////
  779. // CPaneFrame
  780. //
  781. CPaneFrame::CPaneFrame()
  782. {
  783. m_cRef = 1;
  784. m_hwnd = 0;
  785. m_hwndChild = 0;
  786. m_hwndParent = 0;
  787. m_szTitle[0] = 0;
  788. m_hFont = 0;
  789. m_hbr3DFace = 0;
  790. m_cyTitleBar = 0;
  791. m_fHighlightIndicator = FALSE;
  792. m_fHighlightPressed = FALSE;
  793. ZeroMemory(&m_rcTitleButton, sizeof(RECT));
  794. m_hwndClose = 0;
  795. m_cButtons = 1;
  796. m_pBrowser = NULL;
  797. m_dwDispId = 0;
  798. m_pTarget = 0;
  799. m_idMenu = 0;
  800. m_fPin = FALSE;
  801. }
  802. CPaneFrame::~CPaneFrame()
  803. {
  804. if (m_hFont != 0)
  805. DeleteObject(m_hFont);
  806. if (m_hbr3DFace != 0)
  807. DeleteObject(m_hbr3DFace);
  808. }
  809. //
  810. // FUNCTION: CPaneFrame::Initialize()
  811. //
  812. // PURPOSE: Initializes the frame by telling the pane what it's title
  813. // should be.
  814. //
  815. // PARAMETERS:
  816. // [in] hwndParent
  817. // [in] idsTitle
  818. //
  819. // RETURN VALUE:
  820. // HWND
  821. //
  822. HWND CPaneFrame::Initialize(HWND hwndParent, IInputObjectSite *pSite, int idsTitle, int idMenu)
  823. {
  824. WNDCLASSEX wc;
  825. TraceCall("CPaneFrame::Initialize");
  826. // This should be NULL
  827. Assert(NULL == m_hwnd);
  828. // Save this for later
  829. m_hwndParent = hwndParent;
  830. m_idMenu = idMenu;
  831. m_pSite = pSite;
  832. // Load the title
  833. AthLoadString(idsTitle, m_szTitle, ARRAYSIZE(m_szTitle));
  834. // Register the window class if necessary
  835. wc.cbSize = sizeof(WNDCLASSEX);
  836. if (!GetClassInfoEx(g_hInst, c_szPaneFrameClass, &wc))
  837. {
  838. wc.style = 0;
  839. wc.lpfnWndProc = _WndProc;
  840. wc.cbClsExtra = 0;
  841. wc.cbWndExtra = 0;
  842. wc.hInstance = g_hInst;
  843. wc.hCursor = LoadCursor(0, IDC_ARROW);
  844. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  845. wc.lpszMenuName = NULL;
  846. wc.lpszClassName = c_szPaneFrameClass;
  847. wc.hIcon = NULL;
  848. wc.hIconSm = NULL;
  849. RegisterClassEx(&wc);
  850. }
  851. // Create the window
  852. m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szPaneFrameClass, m_szTitle,
  853. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  854. 0, 0, 0, 0, hwndParent, 0, g_hInst, this);
  855. if (!m_hwnd)
  856. {
  857. AssertSz(m_hwnd, "CPaneFrame::Initialize() - Failed to create a frame");
  858. return (0);
  859. }
  860. return (m_hwnd);
  861. }
  862. //
  863. // FUNCTION: CPaneFrame::SetChild()
  864. //
  865. // PURPOSE: Allows the owner to tell us what the child window handle is.
  866. //
  867. BOOL CPaneFrame::SetChild(HWND hwndChild, DWORD dwDispId, IAthenaBrowser *pBrowser,
  868. IObjectWithSite *pObject, IOleCommandTarget *pTarget)
  869. {
  870. TraceCall("CPaneFrame::SetChild");
  871. if (IsWindow(hwndChild))
  872. {
  873. m_hwndChild = hwndChild;
  874. if (pBrowser)
  875. {
  876. m_pBrowser = pBrowser;
  877. m_dwDispId = dwDispId;
  878. }
  879. if (pObject)
  880. {
  881. pObject->SetSite((IInputObjectSite *) this);
  882. }
  883. if (pTarget)
  884. {
  885. m_pTarget = pTarget;
  886. }
  887. return (TRUE);
  888. }
  889. return (FALSE);
  890. }
  891. void CPaneFrame::ShowMenu(void)
  892. {
  893. if (m_idMenu)
  894. {
  895. _OnLButtonDown(m_hwnd, 0, m_rcTitleButton.left, m_rcTitleButton.top, 0);
  896. }
  897. }
  898. //
  899. // FUNCTION: CPaneFrame::QueryInterface()
  900. //
  901. // PURPOSE: Allows caller to retrieve the various interfaces supported by
  902. // this class.
  903. //
  904. HRESULT CPaneFrame::QueryInterface(REFIID riid, LPVOID *ppvObj)
  905. {
  906. TraceCall("CPaneFrame::QueryInterface");
  907. *ppvObj = NULL;
  908. if (IsEqualIID(riid, IID_IUnknown))
  909. *ppvObj = (LPVOID) (IInputObjectSite *) this;
  910. else if (IsEqualIID(riid, IID_IInputObjectSite))
  911. *ppvObj = (LPVOID) (IInputObjectSite *) this;
  912. if (*ppvObj)
  913. {
  914. AddRef();
  915. return (S_OK);
  916. }
  917. return (E_NOINTERFACE);
  918. }
  919. //
  920. // FUNCTION: CPaneFrame::AddRef()
  921. //
  922. // PURPOSE: Adds a reference count to this object.
  923. //
  924. ULONG CPaneFrame::AddRef(void)
  925. {
  926. TraceCall("CPaneFrame::AddRef");
  927. return ((ULONG) InterlockedIncrement((LONG *) &m_cRef));
  928. }
  929. //
  930. // FUNCTION: CPaneFrame::Release()
  931. //
  932. // PURPOSE: Releases a reference on this object.
  933. //
  934. ULONG CPaneFrame::Release(void)
  935. {
  936. TraceCall("CPaneFrame::Release");
  937. if (0 == InterlockedDecrement((LONG *) &m_cRef))
  938. {
  939. delete this;
  940. return 0;
  941. }
  942. return (m_cRef);
  943. }
  944. HRESULT CPaneFrame::OnFocusChangeIS(IUnknown *punkSrc, BOOL fSetFocus)
  945. {
  946. // Simply call through to our host
  947. UnkOnFocusChangeIS(m_pSite, (IInputObject*) this, fSetFocus);
  948. return (S_OK);
  949. }
  950. //
  951. // FUNCTION: CPaneFrame::_WndProc()
  952. //
  953. // PURPOSE: External callback.
  954. //
  955. LRESULT CALLBACK CPaneFrame::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  956. {
  957. CPaneFrame *pThis;
  958. if (uMsg == WM_NCCREATE)
  959. {
  960. pThis = (CPaneFrame *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  961. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
  962. }
  963. else
  964. pThis = (CPaneFrame *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  965. if (pThis)
  966. return (pThis->_FrameWndProc(hwnd, uMsg, wParam, lParam));
  967. return (FALSE);
  968. }
  969. //
  970. // FUNCTION: CPaneFrame::_FrameWndProc()
  971. //
  972. // PURPOSE: Left as an exercise for the reader
  973. //
  974. LRESULT CALLBACK CPaneFrame::_FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  975. {
  976. switch (uMsg)
  977. {
  978. HANDLE_MSG(hwnd, WM_CREATE, _OnCreate);
  979. HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
  980. HANDLE_MSG(hwnd, WM_PAINT, _OnPaint);
  981. HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand);
  982. HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMove);
  983. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, _OnLButtonDown);
  984. HANDLE_MSG(hwnd, WM_TIMER, _OnTimer);
  985. case WM_TOGGLE_CLOSE_PIN:
  986. _OnToggleClosePin(hwnd, (BOOL) lParam);
  987. return (0);
  988. case WM_GET_TITLE_BAR_HEIGHT:
  989. return (m_cyTitleBar + (c_cyBorder * 2) + 1);
  990. case WM_SYSCOLORCHANGE:
  991. case WM_WININICHANGE:
  992. {
  993. // Forward these to all our children
  994. if (IsWindow(m_hwndChild))
  995. SendMessage(m_hwndChild, uMsg, wParam, lParam);
  996. _UpdateDrawingInfo();
  997. break;
  998. }
  999. case WM_SETFOCUS:
  1000. {
  1001. if (m_hwndChild && ((HWND)wParam) != m_hwndChild)
  1002. SetFocus(m_hwndChild);
  1003. break;
  1004. }
  1005. }
  1006. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1007. }
  1008. //
  1009. // FUNCTION: CPaneFrame::_OnCreate()
  1010. //
  1011. // PURPOSE: Loads some info that will be handy later
  1012. //
  1013. BOOL CPaneFrame::_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  1014. {
  1015. TraceCall("CPaneFrame::_OnCreate");
  1016. m_hwnd = hwnd;
  1017. _UpdateDrawingInfo();
  1018. _CreateCloseToolbar();
  1019. return (TRUE);
  1020. }
  1021. //
  1022. // FUNCTION: CPaneFrame::_OnSize()
  1023. //
  1024. // PURPOSE: Resizes our child to fit in the right place
  1025. //
  1026. void CPaneFrame::_OnSize(HWND hwnd, UINT state, int cx, int cy)
  1027. {
  1028. TraceCall("CPaneFrame::_OnSize");
  1029. m_rcChild.left = c_cyBorder;
  1030. m_rcChild.top = m_cyTitleBar;
  1031. m_rcChild.right = cx - (2 * c_cyBorder);
  1032. m_rcChild.bottom = cy - m_cyTitleBar - c_cyBorder;
  1033. if (m_hwndChild)
  1034. SetWindowPos(m_hwndChild, 0, m_rcChild.left, m_rcChild.top, m_rcChild.right,
  1035. m_rcChild.bottom, SWP_NOZORDER | SWP_NOACTIVATE);
  1036. POINT pt = {cx, cy};
  1037. _PositionToolbar(&pt);
  1038. // Invalidate the title area
  1039. RECT rc = m_rcChild;
  1040. rc.top = 0;
  1041. rc.bottom = m_rcChild.top;
  1042. InvalidateRect(m_hwnd, &rc, FALSE);
  1043. rc.left = 0;
  1044. rc.right = c_cyBorder;
  1045. rc.bottom = cy;
  1046. InvalidateRect(m_hwnd, &rc, FALSE);
  1047. rc.left = cx - c_cyBorder;
  1048. rc.right = cx;
  1049. InvalidateRect(m_hwnd, &rc, FALSE);
  1050. }
  1051. //
  1052. // FUNCTION: CPaneFrame::_OnPaint()
  1053. //
  1054. // PURPOSE: Called when it's time to paint our borders and title area.
  1055. //
  1056. void CPaneFrame::_OnPaint(HWND hwnd)
  1057. {
  1058. HDC hdc;
  1059. PAINTSTRUCT ps;
  1060. RECT rc;
  1061. RECT rcClient;
  1062. POINT pt[3];
  1063. HBRUSH hBrush,
  1064. hBrushOld;
  1065. HPEN hPen,
  1066. hPenOld;
  1067. // Get our window size
  1068. GetClientRect(m_hwnd, &rcClient);
  1069. rc = rcClient;
  1070. // Start painting
  1071. hdc = BeginPaint(hwnd, &ps);
  1072. // Draw a simple edge around or window
  1073. DrawEdge(hdc, &rc, BDR_SUNKENOUTER, BF_TOPRIGHT | BF_BOTTOMLEFT);
  1074. // Now draw a raised edge around our title bar area
  1075. InflateRect(&rc, -1, -1);
  1076. rc.bottom = m_cyTitleBar;
  1077. DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_TOPRIGHT | BF_BOTTOMLEFT);
  1078. // Paint the background
  1079. InflateRect(&rc, -c_cxBorder, -c_cyBorder);
  1080. FillRect(hdc, &rc, m_hbr3DFace);
  1081. // Now draw some groovy text
  1082. SelectFont(hdc, m_hFont);
  1083. SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
  1084. SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  1085. // Draw the text
  1086. InflateRect(&rc, -c_cxTextBorder, -c_cyTextBorder);
  1087. if (!m_fPin)
  1088. {
  1089. DrawText(hdc, m_szTitle, -1, &rc, DT_CALCRECT | DT_VCENTER | DT_LEFT);
  1090. DrawText(hdc, m_szTitle, -1, &rc, DT_VCENTER | DT_LEFT);
  1091. }
  1092. else
  1093. {
  1094. TCHAR sz[CCHMAX_STRINGRES];
  1095. AthLoadString(idsPushPinInfo, sz, ARRAYSIZE(sz));
  1096. IDrawText(hdc, sz, &rc, DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT,
  1097. rc.bottom - rc.top);
  1098. DrawText(hdc, sz, -1, &rc, DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT);
  1099. }
  1100. // Drop-down indicator
  1101. if (m_idMenu)
  1102. {
  1103. COLORREF crFG = GetSysColor(COLOR_WINDOWTEXT);
  1104. pt[0].x = rc.right + 6;
  1105. pt[0].y = (m_cyTitleBar - 6) / 2 + 2;
  1106. pt[1].x = pt[0].x + 6;
  1107. pt[1].y = pt[0].y;
  1108. pt[2].x = pt[0].x + 3;
  1109. pt[2].y = pt[0].y + 3;
  1110. hPen = CreatePen(PS_SOLID, 1, crFG);
  1111. hBrush = CreateSolidBrush(crFG);
  1112. hPenOld = SelectPen(hdc, hPen);
  1113. hBrushOld = SelectBrush(hdc, hBrush);
  1114. Polygon(hdc, pt, 3);
  1115. SelectPen(hdc, hPenOld);
  1116. SelectBrush(hdc, hBrushOld);
  1117. DeleteObject(hPen);
  1118. DeleteObject(hBrush);
  1119. if (m_fHighlightIndicator)
  1120. {
  1121. rc = m_rcTitleButton;
  1122. DrawEdge(hdc, &rc, m_fHighlightPressed ? BDR_SUNKENOUTER : BDR_RAISEDINNER,
  1123. BF_TOPRIGHT | BF_BOTTOMLEFT);
  1124. }
  1125. }
  1126. EndPaint(hwnd, &ps);
  1127. }
  1128. //
  1129. // FUNCTION: _OnCommand()
  1130. //
  1131. // PURPOSE: We get the occasional command now and again
  1132. //
  1133. void CPaneFrame::_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1134. {
  1135. switch (id)
  1136. {
  1137. case ID_PANE_CLOSE:
  1138. {
  1139. if (m_pBrowser)
  1140. m_pBrowser->SetViewLayout(m_dwDispId, LAYOUT_POS_NA, FALSE, 0, 0);
  1141. return;
  1142. }
  1143. case ID_PANE_PIN:
  1144. {
  1145. SendMessage(m_hwndChild, WMR_CLICKOUTSIDE, CLK_OUT_DEACTIVATE, 0);
  1146. if (m_pBrowser)
  1147. m_pBrowser->SetViewLayout(m_dwDispId, LAYOUT_POS_NA, TRUE, 0, 0);
  1148. return;
  1149. }
  1150. }
  1151. return;
  1152. }
  1153. //
  1154. // FUNCTION: CPaneFrame::_OnToggleClosePin()
  1155. //
  1156. // PURPOSE: Sent to the frame when we should change the close button
  1157. // to a pin button.
  1158. //
  1159. // PARAMETERS:
  1160. // [in] fPin - TRUE to turn the Pin on, FALSE to turn it off.
  1161. //
  1162. void CPaneFrame::_OnToggleClosePin(HWND hwnd, BOOL fPin)
  1163. {
  1164. TraceCall("CPaneFrame::_OnToggleClosePin");
  1165. if (fPin)
  1166. {
  1167. static const TBBUTTON tb[] =
  1168. {
  1169. { 2, ID_PANE_PIN, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
  1170. };
  1171. SendMessage(m_hwndClose, TB_DELETEBUTTON, 0, 0);
  1172. SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
  1173. SendMessage(m_hwndClose, TB_SETHOTITEM, (WPARAM) -1, 0);
  1174. m_fPin = TRUE;
  1175. }
  1176. else
  1177. {
  1178. static const TBBUTTON tb[] =
  1179. {
  1180. { 1, ID_PANE_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
  1181. };
  1182. SendMessage(m_hwndClose, TB_DELETEBUTTON, 0, 0);
  1183. SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
  1184. SendMessage(m_hwndClose, TB_SETHOTITEM, (WPARAM) -1, 0);
  1185. m_fPin = FALSE;
  1186. }
  1187. }
  1188. //
  1189. // FUNCTION: CPaneFrame::_UpdateDrawingInfo()
  1190. //
  1191. // PURPOSE: When we get created or when the user changes their settings,
  1192. // we need to reload our fonts, colors, and sizes.
  1193. //
  1194. void CPaneFrame::_UpdateDrawingInfo(void)
  1195. {
  1196. LOGFONT lf;
  1197. TEXTMETRIC tm;
  1198. HDC hdc;
  1199. TraceCall("CPaneFrame::_UpdateDrawingInfo");
  1200. if (m_hFont)
  1201. DeleteObject(m_hFont);
  1202. // Figure out which font to use
  1203. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
  1204. // Create the font
  1205. m_hFont = CreateFontIndirect(&lf);
  1206. // Get the metrics of this font
  1207. hdc = GetDC(m_hwnd);
  1208. SelectFont(hdc, m_hFont);
  1209. GetTextMetrics(hdc, &tm);
  1210. // Calculate the height
  1211. m_cyTitleBar = tm.tmHeight + (2 * c_cyBorder) + (2 * c_cyTextBorder);
  1212. RECT rc = {2 * c_cxBorder, 2 * c_cyBorder, 0, m_cyTitleBar - c_cyBorder};
  1213. SIZE s;
  1214. GetTextExtentPoint32(hdc, m_szTitle, lstrlen(m_szTitle), &s);
  1215. m_rcTitleButton = rc;
  1216. m_rcTitleButton.right = 14 + (2 * c_cxTextBorder) + s.cx + (2 * c_cxBorder);
  1217. ReleaseDC(m_hwnd, hdc);
  1218. // Get the brush we need
  1219. if (m_hbr3DFace)
  1220. DeleteObject(m_hbr3DFace);
  1221. m_hbr3DFace = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
  1222. }
  1223. //
  1224. // FUNCTION: CPaneFrame::_CreateCloseToolbar()
  1225. //
  1226. // PURPOSE: Creates the toolbar that has our close button
  1227. //
  1228. void CPaneFrame::_CreateCloseToolbar()
  1229. {
  1230. CHAR szTitle[255];
  1231. TraceCall("CPaneFrame::_CreateCloseToolbar");
  1232. AthLoadString(idsHideFolders, szTitle, ARRAYSIZE(szTitle));
  1233. m_hwndClose = CreateWindowEx(0, TOOLBARCLASSNAME, szTitle,
  1234. WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE |
  1235. WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOMOVEY |
  1236. CCS_NOPARENTALIGN | CCS_NORESIZE,
  1237. 0, c_cyClose, 30, 15, m_hwnd, 0, g_hInst, NULL);
  1238. if (m_hwndClose)
  1239. {
  1240. static const TBBUTTON tb[] =
  1241. {
  1242. { 1, ID_PANE_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
  1243. };
  1244. SendMessage(m_hwndClose, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  1245. SendMessage(m_hwndClose, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG(11, 9));
  1246. TBADDBITMAP tbab = { g_hLocRes, idbClosePin };
  1247. SendMessage(m_hwndClose, TB_ADDBITMAP, 4, (LPARAM) &tbab);
  1248. SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
  1249. SendMessage(m_hwndClose, TB_SETINDENT, 0, 0);
  1250. _SizeCloseToolbar();
  1251. }
  1252. }
  1253. //
  1254. // FUNCTION: CPaneFrame::_SizeCloseToolbar()
  1255. //
  1256. // PURPOSE: Set's the size of the toolbar appropriately.
  1257. //
  1258. void CPaneFrame::_SizeCloseToolbar(void)
  1259. {
  1260. TraceCall("CPaneFrame::_SizeCloseToolbar");
  1261. RECT rc;
  1262. LONG lButtonSize;
  1263. GetWindowRect(m_hwndClose, &rc);
  1264. lButtonSize = (LONG) SendMessage(m_hwndClose, TB_GETBUTTONSIZE, 0, 0L);
  1265. SetWindowPos(m_hwndClose, NULL, 0, 0, LOWORD(lButtonSize) * m_cButtons,
  1266. rc.bottom - rc.top, SWP_NOMOVE | SWP_NOACTIVATE);
  1267. _PositionToolbar(NULL);
  1268. }
  1269. //
  1270. // FUNCTION: CPaneFrame::_PositionToolbar()
  1271. //
  1272. // PURPOSE: Does the work of correctly positioning the close button
  1273. // toolbar.
  1274. //
  1275. // PARAMETERS:
  1276. // LPPOINT ppt
  1277. //
  1278. void CPaneFrame::_PositionToolbar(LPPOINT ppt)
  1279. {
  1280. TraceCall("CPaneFrame::_PositionToolbar");
  1281. if (m_hwndClose)
  1282. {
  1283. RECT rc;
  1284. GetClientRect(m_hwnd, &rc);
  1285. if (ppt)
  1286. {
  1287. rc.left = 0;
  1288. rc.right = ppt->x;
  1289. }
  1290. RECT rcTB;
  1291. GetWindowRect(m_hwndClose, &rcTB);
  1292. rc.left = rc.right - (rcTB.right - rcTB.left) - 3;
  1293. DWORD top = max((int) ((m_cyTitleBar - (rcTB.bottom - rcTB.top)) / 2) + 1, 0);
  1294. SetWindowPos(m_hwndClose, HWND_TOP, rc.left, top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  1295. }
  1296. }
  1297. void CPaneFrame::_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  1298. {
  1299. POINT pt = {x, y};
  1300. UINT id;
  1301. if (m_idMenu && PtInRect(&m_rcTitleButton, pt))
  1302. {
  1303. m_fHighlightPressed = TRUE;
  1304. InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
  1305. UpdateWindow(m_hwnd);
  1306. HMENU hMenu = LoadPopupMenu(m_idMenu);
  1307. MenuUtil_EnablePopupMenu(hMenu, m_pTarget);
  1308. if (m_idMenu == IDR_BA_TITLE_POPUP && ((g_dwHideMessenger == BL_HIDE) || (g_dwHideMessenger == BL_DISABLE)))
  1309. {
  1310. DeleteMenu(hMenu, ID_NEW_ONLINE_CONTACT, MF_BYCOMMAND);
  1311. DeleteMenu(hMenu, ID_SET_ONLINE_CONTACT, MF_BYCOMMAND);
  1312. DeleteMenu(hMenu, SEP_MESSENGER, MF_BYCOMMAND);
  1313. DeleteMenu(hMenu, ID_SORT_BY_NAME, MF_BYCOMMAND);
  1314. DeleteMenu(hMenu, ID_SORT_BY_STATUS, MF_BYCOMMAND);
  1315. }
  1316. pt.x = m_rcTitleButton.left;
  1317. pt.y = m_rcTitleButton.bottom;
  1318. ClientToScreen(m_hwnd, &pt);
  1319. id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
  1320. pt.x, pt.y, m_hwnd, NULL);
  1321. if (id)
  1322. {
  1323. m_pTarget->Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  1324. }
  1325. m_fHighlightPressed = m_fHighlightIndicator = FALSE;
  1326. KillTimer(m_hwnd, IDT_PANETIMER);
  1327. InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
  1328. UpdateWindow(m_hwnd);
  1329. if(hMenu)
  1330. {
  1331. //Bug #101329 - (erici) Destroy leaked MENU.
  1332. BOOL bMenuDestroyed = DestroyMenu(hMenu);
  1333. Assert(bMenuDestroyed);
  1334. }
  1335. }
  1336. }
  1337. void CPaneFrame::_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  1338. {
  1339. POINT pt = {x, y};
  1340. if (m_idMenu && (m_fHighlightIndicator != PtInRect(&m_rcTitleButton, pt)))
  1341. {
  1342. m_fHighlightIndicator = !m_fHighlightIndicator;
  1343. InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
  1344. if (m_fHighlightIndicator)
  1345. SetTimer(m_hwnd, IDT_PANETIMER, ELAPSE_MOUSEOVERCHECK, NULL);
  1346. else
  1347. KillTimer(m_hwnd, IDT_PANETIMER);
  1348. }
  1349. }
  1350. void CPaneFrame::_OnTimer(HWND hwnd, UINT id)
  1351. {
  1352. RECT rcClient;
  1353. POINT pt;
  1354. DWORD dw;
  1355. dw = GetMessagePos();
  1356. pt.x = LOWORD(dw);
  1357. pt.y = HIWORD(dw);
  1358. ScreenToClient(m_hwnd, &pt);
  1359. if (id == IDT_PANETIMER)
  1360. {
  1361. GetClientRect(m_hwnd, &rcClient);
  1362. // No need to handle mouse in client area, OnMouseMove will catch this. We
  1363. // only need to catch the mouse moving out of the client area.
  1364. if (!PtInRect(&rcClient, pt) && !m_fHighlightPressed)
  1365. {
  1366. KillTimer(m_hwnd, IDT_PANETIMER);
  1367. m_fHighlightIndicator = FALSE;
  1368. InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
  1369. }
  1370. }
  1371. }