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

599 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: docksite.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // DockSite.cpp : implementation file
  11. //
  12. #include "stdafx.h"
  13. #include "amc.h"
  14. #include "DockSite.h"
  15. #include "MainFrm.h"
  16. #include "ChildFrm.h"
  17. #include "commctrl.h"
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CDockSite
  20. CDockSite::CDockSite() : m_rect(0, 0, 0, 0)
  21. {
  22. m_pManagedWindows = NULL;
  23. m_style = DSS_TOP;
  24. m_bVisible = FALSE;
  25. }
  26. BOOL CDockSite::Create(DSS_STYLE style)
  27. {
  28. // Not supported
  29. ASSERT(style != DSS_LEFT && style != DSS__RIGHT);
  30. m_pManagedWindows = new CList<CDockWindow*, CDockWindow*>;
  31. m_style = style;
  32. return TRUE;
  33. }
  34. CDockSite::~CDockSite()
  35. {
  36. delete m_pManagedWindows;
  37. }
  38. /////////////////////////////////////////////////////////////////////////////
  39. // Operations
  40. BOOL CDockSite::Attach(CDockWindow* pWnd)
  41. {
  42. ASSERT(pWnd != NULL);
  43. m_pManagedWindows->AddTail(pWnd);
  44. return TRUE;
  45. }
  46. BOOL CDockSite::Detach(CDockWindow* pWnd)
  47. {
  48. ASSERT(pWnd != NULL);
  49. return TRUE;
  50. }
  51. void CDockSite::Show(BOOL bState)
  52. {
  53. // insure its 0 or 1
  54. BOOL b = (bState & 0x1);
  55. ASSERT(m_pManagedWindows != NULL);
  56. if (b == m_bVisible || m_pManagedWindows == NULL)
  57. return ;
  58. m_bVisible = b;
  59. POSITION pos;
  60. CDockWindow* pWindow;
  61. pos = m_pManagedWindows->GetHeadPosition();
  62. while(pos)
  63. {
  64. pWindow = m_pManagedWindows->GetNext(pos);
  65. if (pWindow != NULL)
  66. pWindow->Show(b);
  67. }
  68. }
  69. void CDockSite::RenderLayout(HDWP& hdwp, CRect& clientRect, CPoint& xyLocation)
  70. {
  71. // No support for other styles
  72. ASSERT(m_style == DSS_TOP || m_style == DSS_BOTTOM);
  73. ASSERT(hdwp != 0);
  74. CRect siteRect(0,0,0,0);
  75. CRect controlRect(0,0,0,0);
  76. CDockWindow* pWindow;
  77. if (m_bVisible == TRUE)
  78. {
  79. POSITION pos;
  80. pos = m_pManagedWindows->GetHeadPosition();
  81. // Default point for the DSS_TOP
  82. int x = 0, y = xyLocation.y;
  83. while (pos)
  84. {
  85. pWindow = m_pManagedWindows->GetNext(pos);
  86. if ((pWindow != NULL) && pWindow->IsVisible ())
  87. {
  88. // Compute the size of the dockwindow rect
  89. controlRect = pWindow->CalculateSize(clientRect);
  90. siteRect += controlRect;
  91. if (m_style == DSS_BOTTOM)
  92. y = xyLocation.y - siteRect.Height();
  93. DeferWindowPos(hdwp, pWindow->m_hWnd, NULL , x, y,
  94. clientRect.Width(), controlRect.Height(),
  95. SWP_NOZORDER|SWP_NOACTIVATE);
  96. if (m_style == DSS_TOP)
  97. y += siteRect.Height();
  98. }
  99. }
  100. }
  101. clientRect.bottom -= siteRect.Height();
  102. }
  103. /////////////////////////////////////////////////////////////////////////////
  104. // CDockWindow
  105. IMPLEMENT_DYNAMIC(CDockWindow, CWnd)
  106. CDockWindow::CDockWindow()
  107. {
  108. m_bVisible = FALSE;
  109. }
  110. CDockWindow::~CDockWindow()
  111. {
  112. }
  113. void CDockWindow::Show(BOOL bState)
  114. {
  115. bool state = (bState != FALSE);
  116. if (state != IsVisible())
  117. {
  118. SetVisible(state);
  119. ShowWindow(state ? SW_SHOWNORMAL : SW_HIDE);
  120. }
  121. }
  122. BEGIN_MESSAGE_MAP(CDockWindow, CWnd)
  123. //{{AFX_MSG_MAP(CDockWindow)
  124. ON_WM_SHOWWINDOW()
  125. //}}AFX_MSG_MAP
  126. END_MESSAGE_MAP()
  127. LRESULT CDockWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  128. {
  129. ASSERT_VALID(this);
  130. LRESULT lResult;
  131. switch (message)
  132. {
  133. case WM_NOTIFY:
  134. case WM_DRAWITEM:
  135. case WM_MEASUREITEM:
  136. case WM_DELETEITEM:
  137. case WM_COMPAREITEM:
  138. case WM_VKEYTOITEM:
  139. case WM_CHARTOITEM:
  140. // send these messages to the owner if not handled
  141. if (OnWndMsg(message, wParam, lParam, &lResult))
  142. return lResult;
  143. else
  144. return GetOwner()->SendMessage(message, wParam, lParam);
  145. break;
  146. case WM_COMMAND:
  147. if (OnWndMsg(message, wParam, lParam, &lResult))
  148. return lResult;
  149. else
  150. {
  151. CRebarDockWindow* pRebar = dynamic_cast<CRebarDockWindow*>(this);
  152. ASSERT(NULL != pRebar);
  153. if (pRebar)
  154. {
  155. // In case of tool-button click, send this message to
  156. // the owner (the toolbar).
  157. return pRebar->GetRebar()->SendMessage(message, wParam, lParam);
  158. }
  159. else
  160. {
  161. // We want to know when this code is hit. Below is a
  162. // benign assert for this purpose.
  163. ASSERT(FALSE);
  164. // send these messages to the owner if there is no rebar.
  165. return GetOwner()->SendMessage(message, wParam, lParam);
  166. }
  167. }
  168. break;
  169. }
  170. // otherwise, just handle in default way
  171. lResult = CWnd::WindowProc(message, wParam, lParam);
  172. return lResult;
  173. }
  174. /////////////////////////////////////////////////////////////////////////////
  175. // CDockWindow message handlers
  176. void CDockWindow::OnShowWindow(BOOL bShow, UINT nStatus)
  177. {
  178. CWnd::OnShowWindow(bShow, nStatus);
  179. // keep our visibility flag in sync with the true visibility state of the window
  180. m_bVisible = bShow;
  181. }
  182. /////////////////////////////////////////////////////////////////////////////
  183. // CStatBar
  184. IMPLEMENT_DYNAMIC(CStatBar, CDockWindow)
  185. CStatBar::CStatBar()
  186. {
  187. m_nCount = 10;
  188. m_pPaneInfo = new STATUSBARPANE[10] ;
  189. }
  190. CStatBar::~CStatBar()
  191. {
  192. delete [] m_pPaneInfo;
  193. }
  194. #define USE_CCS_NORESIZE 0
  195. CRect CStatBar::CalculateSize(CRect maxRect)
  196. {
  197. // default rect is 0,0 for hidden windows
  198. CRect rect(0,0,0,0);
  199. if (IsVisible())
  200. {
  201. #if USE_CCS_NORESIZE
  202. CClientDC dc(this);
  203. CFont* pOldFont = dc.SelectObject(GetFont());
  204. TEXTMETRIC tm;
  205. // Compute the height for the status bar based on the font it is using
  206. // Note: tm.tmInternalLeading is added for spacing
  207. dc.GetTextMetrics(&tm);
  208. //rect.SetRect(0, 0,maxRect.Width(), tm.tmHeight+tm.tmInternalLeading);
  209. rect.SetRect(0, 0,50, tm.tmHeight+tm.tmInternalLeading);
  210. dc.SelectFont (pOldFont);
  211. #else
  212. /*
  213. * Bug 188319: if we let the status bar handle its own sizing
  214. * (~CCS_NORESIZE), we can just use the client rect here
  215. */
  216. GetClientRect (rect);
  217. #endif
  218. }
  219. return rect;
  220. };
  221. void CStatBar::GetItemRect(int nIndex, LPRECT lpRect)
  222. {
  223. SendMessage(SB_GETRECT, (WPARAM)nIndex, (LPARAM)lpRect);
  224. }
  225. void CStatBar::SetPaneStyle(int nIndex, UINT nStyle)
  226. {
  227. ASSERT(nIndex >=0 && nIndex < m_nCount);
  228. ASSERT(m_pPaneInfo != NULL);
  229. m_pPaneInfo[nIndex].m_style = nStyle;
  230. SendMessage(SB_SETTEXT, (WPARAM)(nIndex | nStyle), (LPARAM)((LPCTSTR)m_pPaneInfo[nIndex].m_paneText));
  231. }
  232. void CStatBar::SetPaneText(int nIndex, LPCTSTR lpszText, BOOL bUpdate)
  233. {
  234. m_pPaneInfo[nIndex].m_paneText = lpszText;
  235. SetPaneStyle(nIndex, m_pPaneInfo[nIndex].m_style);
  236. if (bUpdate == TRUE)
  237. {
  238. CRect rect;
  239. GetItemRect(nIndex, &rect);
  240. InvalidateRect(rect, TRUE);
  241. }
  242. }
  243. BEGIN_MESSAGE_MAP(CStatBar, CDockWindow)
  244. //{{AFX_MSG_MAP(CStatBar)
  245. ON_WM_SIZE()
  246. //}}AFX_MSG_MAP
  247. END_MESSAGE_MAP()
  248. BOOL CStatBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  249. {
  250. ASSERT_VALID(pParentWnd); // must have a parent
  251. /*
  252. * Bug 188319: let the status bar handle its own sizing (~CCS_NORESIZE)
  253. */
  254. dwStyle |= WS_CLIPSIBLINGS
  255. | CCS_NOPARENTALIGN
  256. | CCS_NOMOVEY
  257. #if USE_CCS_NORESIZE
  258. | CCS_NORESIZE
  259. #endif
  260. | CCS_NODIVIDER;
  261. // create status window
  262. CRect rect(0,0,0,0);
  263. CWnd::Create(STATUSCLASSNAME, _T("Ready"), dwStyle, rect, pParentWnd, nID);
  264. return TRUE;
  265. }
  266. BOOL CStatBar::CreatePanes(UINT* pIndicatorArray, int nCount)
  267. {
  268. ASSERT(nCount <= 10); // Note: No realloc implemented. If needed, do it.
  269. UINT array[10] = {0};
  270. int nTotal = 0;
  271. CClientDC dc(this);
  272. // Default to 1 pane the full width of the status bar
  273. if (pIndicatorArray == NULL)
  274. m_nCount = 1;
  275. m_nCount = nCount;
  276. for (int i = 0; i < m_nCount; i++)
  277. {
  278. // Load the string from the resource and determine its width
  279. CString s;
  280. CSize sz;
  281. if (pIndicatorArray[i] != ID_SEPARATOR)
  282. {
  283. LoadString(s, pIndicatorArray[i]);
  284. GetTextExtentPoint32(dc.m_hDC, (LPCTSTR)s, s.GetLength(), &sz);
  285. m_pPaneInfo[i].m_width = sz.cx+3;
  286. array[i] = m_pPaneInfo[i].m_width;
  287. nTotal += array[i];
  288. }
  289. // Reset values in-case LoadString fails
  290. sz.cx = 0;
  291. s = _T("");
  292. }
  293. return SendMessage(SB_SETPARTS, (WPARAM) m_nCount,
  294. (LPARAM)array);
  295. }
  296. /*
  297. UpdateAllPanes - Assumes the first pane is the one that is stretchy
  298. This means only m_pPaneInfo[nCount].m_width == -1 and the rest have
  299. a 0 or greater width.
  300. */
  301. void CStatBar::UpdateAllPanes(int clientWidth)
  302. {
  303. enum
  304. {
  305. eBorder_cyHorzBorder,
  306. eBorder_cxVertBorder,
  307. eBorder_cxGutter,
  308. eBorder_Count
  309. };
  310. int anBorders[eBorder_Count];
  311. int anPartWidths[10] = {0};
  312. ASSERT(m_nCount <= countof(anPartWidths));
  313. ASSERT(m_nCount > 0);
  314. // Get the border widths. anBorders[2] is the border width between rectangles
  315. SendMessage(SB_GETBORDERS, 0, (LPARAM)anBorders);
  316. // Starting from right to left
  317. // The right-most pane is ends at the client width
  318. int nCount = m_nCount - 1;
  319. clientWidth -= anBorders[eBorder_cxVertBorder]; // substract vertical border from right side
  320. anPartWidths[nCount] = clientWidth;
  321. clientWidth -= m_pPaneInfo[nCount].m_width;
  322. clientWidth -= anBorders[eBorder_cxGutter]; // substract between pane border
  323. --nCount;
  324. for (int i = nCount; i >= 0; i--)
  325. {
  326. if (clientWidth >= 0)
  327. anPartWidths[i] = clientWidth;
  328. //TRACE(_T("Pane#:%d currentWidth: %d"));
  329. clientWidth -= m_pPaneInfo[i].m_width;
  330. clientWidth -= anBorders[eBorder_cxGutter]; // substract between pane border
  331. }
  332. SendMessage (SB_SETPARTS, m_nCount, (LPARAM)anPartWidths);
  333. }
  334. /////////////////////////////////////////////////////////////////////////////
  335. // CStatBar message handlers
  336. void CStatBar::OnSize(UINT nType, int cx, int cy)
  337. {
  338. if (cx > 0)
  339. UpdateAllPanes(cx);
  340. CDockWindow::OnSize(nType, cx, cy);
  341. }
  342. /////////////////////////////////////////////////////////////////////////////
  343. // CRebarDockWindow
  344. BEGIN_MESSAGE_MAP(CRebarDockWindow, CDockWindow)
  345. //{{AFX_MSG_MAP(CRebarDockWindow)
  346. ON_WM_CREATE()
  347. ON_WM_LBUTTONDOWN()
  348. ON_WM_LBUTTONUP()
  349. ON_WM_MOUSEMOVE()
  350. ON_WM_SIZE()
  351. //}}AFX_MSG_MAP
  352. END_MESSAGE_MAP()
  353. CRebarDockWindow::CRebarDockWindow()
  354. {
  355. m_bTracking = false;
  356. }
  357. CRebarDockWindow::~CRebarDockWindow()
  358. {
  359. }
  360. BOOL CRebarDockWindow::PreCreateWindow(CREATESTRUCT& cs)
  361. {
  362. BOOL bSuccess=FALSE;
  363. // Let default implementation fill in most of the details
  364. CWnd::PreCreateWindow(cs);
  365. WNDCLASS wc;
  366. if (::GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wc))
  367. {
  368. // Clear the H and V REDRAW flags
  369. wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
  370. wc.lpszClassName = SIZEABLEREBAR_WINDOW;
  371. wc.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  372. wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  373. // Register this new style;
  374. bSuccess=AfxRegisterClass(&wc);
  375. }
  376. // Use the new child frame window class
  377. cs.lpszClass = SIZEABLEREBAR_WINDOW;
  378. return bSuccess;
  379. }
  380. BOOL CRebarDockWindow::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  381. {
  382. ASSERT_VALID(pParentWnd); // must have a parent
  383. return CWnd::Create(NULL,NULL,dwStyle, g_rectEmpty, pParentWnd, nID);
  384. }
  385. CRect CRebarDockWindow::CalculateSize(CRect maxRect)
  386. {
  387. CRect rect(0,0,0,0);
  388. if (IsVisible())
  389. {
  390. rect = m_wndRebar.CalculateSize(maxRect);
  391. rect.bottom += SIZEABLEREBAR_GUTTER;
  392. }
  393. return rect;
  394. }
  395. /////////////////////////////////////////////////////////////////////////////
  396. // CRebarDockWindow message handlers
  397. int CRebarDockWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
  398. {
  399. if (CDockWindow::OnCreate(lpCreateStruct) == -1)
  400. return -1;
  401. if (!m_wndRebar.Create (NULL, WS_VISIBLE | WS_CHILD | RBS_AUTOSIZE,
  402. g_rectEmpty, this, ID_REBAR))
  403. return (-1);
  404. return 0;
  405. }
  406. void CRebarDockWindow::UpdateWindowSize(void)
  407. {
  408. CFrameWnd* pFrame = GetParentFrame();
  409. if (pFrame->IsKindOf (RUNTIME_CLASS (CChildFrame)))
  410. static_cast<CChildFrame*>(pFrame)->RenderDockSites();
  411. else if (pFrame->IsKindOf (RUNTIME_CLASS (CMainFrame)))
  412. static_cast<CMainFrame*>(pFrame)->RenderDockSites();
  413. }
  414. void CRebarDockWindow::OnLButtonDown(UINT nFlags, CPoint point)
  415. {
  416. // set the tracking flag on
  417. m_bTracking=TRUE;
  418. // capture the mouse
  419. SetCapture();
  420. }
  421. void CRebarDockWindow::OnLButtonUp(UINT nFlags, CPoint point)
  422. {
  423. // set the tracking flag off
  424. m_bTracking=FALSE;
  425. // release mouse capture
  426. ReleaseCapture();
  427. }
  428. void CRebarDockWindow::OnMouseMove(UINT nFlags, CPoint point)
  429. {
  430. // Reposition Bands
  431. if (m_bTracking)
  432. UpdateWindowSize();
  433. else
  434. CDockWindow::OnMouseMove(nFlags, point);
  435. }
  436. BOOL CRebarDockWindow::InsertBand(LPREBARBANDINFO lprbbi)
  437. {
  438. ASSERT(lprbbi!=NULL);
  439. BOOL bReturn=FALSE;
  440. if (IsWindow(m_wndRebar.m_hWnd))
  441. bReturn = m_wndRebar.InsertBand(lprbbi);
  442. return bReturn;
  443. }
  444. LRESULT CRebarDockWindow::SetBandInfo(UINT uBand, LPREBARBANDINFO lprbbi)
  445. {
  446. ASSERT(lprbbi!=NULL);
  447. BOOL bReturn=FALSE;
  448. if (IsWindow(m_wndRebar.m_hWnd))
  449. bReturn = m_wndRebar.SetBandInfo(uBand, lprbbi);
  450. return bReturn;
  451. }
  452. void CRebarDockWindow::OnSize(UINT nType, int cx, int cy)
  453. {
  454. CDockWindow::OnSize(nType, cx, cy);
  455. m_wndRebar.MoveWindow (0, 0, cx, cy - SIZEABLEREBAR_GUTTER);
  456. }