home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / BARCORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  26.9 KB  |  1,098 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <malloc.h>
  13. #ifdef _MAC
  14. #include <macname1.h>
  15. #include <Types.h>
  16. #include <QuickDraw.h>
  17. #include <Fonts.h>
  18. #include <macos\Windows.h>
  19. #include <GestaltEqu.h>
  20. #include <Script.h>
  21. #include <macname2.h>
  22. #endif
  23.  
  24. #ifdef AFX_CORE3_SEG
  25. #pragma code_seg(AFX_CORE3_SEG)
  26. #endif
  27.  
  28. #ifdef _DEBUG
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32.  
  33. #define new DEBUG_NEW
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CControlBar
  37.  
  38. // IMPLEMENT_DYNAMIC for CControlBar is in wincore.cpp for .OBJ granularity reasons
  39.  
  40. BEGIN_MESSAGE_MAP(CControlBar, CWnd)
  41.     //{{AFX_MSG_MAP(CControlBar)
  42.     ON_WM_TIMER()
  43.     ON_WM_PAINT()
  44.     ON_WM_CTLCOLOR()
  45.     ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  46.     ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
  47.     ON_WM_WINDOWPOSCHANGING()
  48.     ON_WM_SHOWWINDOW()
  49.     ON_WM_LBUTTONDOWN()
  50.     ON_WM_LBUTTONDBLCLK()
  51.     ON_WM_MOUSEACTIVATE()
  52.     ON_WM_CANCELMODE()
  53.     ON_WM_CREATE()
  54.     ON_WM_DESTROY()
  55.     ON_MESSAGE_VOID(WM_INITIALUPDATE, OnInitialUpdate)
  56.     ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
  57.     ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
  58.     ON_WM_ERASEBKGND()
  59.     //}}AFX_MSG_MAP
  60. #ifdef _MAC
  61.     ON_WM_SIZE()
  62.     ON_WM_SYSCOLORCHANGE()
  63.     ON_WM_MOVE()
  64.     ON_MESSAGE(WM_MACINTOSH, OnMacintosh)
  65. #endif
  66. END_MESSAGE_MAP()
  67.  
  68. #ifdef AFX_INIT_SEG
  69. #pragma code_seg(AFX_INIT_SEG)
  70. #endif
  71.  
  72. CControlBar::CControlBar()
  73. {
  74.     // no elements contained in the control bar yet
  75.     m_nCount = 0;
  76.     m_pData = NULL;
  77.  
  78.     // set up some default border spacings
  79.     m_cxLeftBorder = m_cxRightBorder = 6;
  80.     m_cxDefaultGap = 2;
  81.     m_cyTopBorder = m_cyBottomBorder = 1;
  82.     m_bAutoDelete = FALSE;
  83.     m_hWndOwner = NULL;
  84.     m_nStateFlags = 0;
  85.     m_pDockSite = NULL;
  86.     m_pDockBar = NULL;
  87.     m_pDockContext = NULL;
  88.     m_dwStyle = 0;
  89.     m_dwDockStyle = 0;
  90.     m_nMRUWidth = 32767;
  91.  
  92. #ifdef _MAC
  93.     m_bMonochrome = FALSE;      // will be set correctly by OnSize()
  94. #endif
  95. }
  96.  
  97. BOOL CControlBar::PreCreateWindow(CREATESTRUCT& cs)
  98. {
  99.     if (!CWnd::PreCreateWindow(cs))
  100.         return FALSE;
  101.  
  102.     // force clipsliblings (otherwise will cause repaint problems)
  103.     cs.style |= WS_CLIPSIBLINGS;
  104.  
  105.     // default border style translation for Win4
  106.     //  (you can turn off this translation by setting CBRS_BORDER_3D)
  107.     if (afxData.bWin4 && (m_dwStyle & CBRS_BORDER_3D) == 0)
  108.     {
  109.         DWORD dwNewStyle = 0;
  110.         switch (m_dwStyle & (CBRS_BORDER_ANY|CBRS_ALIGN_ANY))
  111.         {
  112.         case CBRS_LEFT:
  113.             dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
  114.             break;
  115.         case CBRS_TOP:
  116.             dwNewStyle = CBRS_BORDER_TOP;
  117.             break;
  118.         case CBRS_RIGHT:
  119.             dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
  120.             break;
  121.         case CBRS_BOTTOM:
  122.             dwNewStyle = CBRS_BORDER_BOTTOM;
  123.             break;
  124.         }
  125.  
  126.         // set new style if it matched one of the predefined border types
  127.         if (dwNewStyle != 0)
  128.         {
  129.             m_dwStyle &= ~(CBRS_BORDER_ANY);
  130.             m_dwStyle |= (dwNewStyle | CBRS_BORDER_3D);
  131.         }
  132.     }
  133.  
  134.     return TRUE;
  135. }
  136.  
  137. void CControlBar::SetBarStyle(DWORD dwStyle)
  138. {
  139.     EnableToolTips(dwStyle & CBRS_TOOLTIPS);
  140.  
  141.     if (m_dwStyle != dwStyle)
  142.     {
  143.         DWORD dwOldStyle = m_dwStyle;
  144.         m_dwStyle = dwStyle;
  145.         OnBarStyleChange(dwOldStyle, dwStyle);
  146.     }
  147. }
  148.  
  149. void CControlBar::OnBarStyleChange(DWORD, DWORD)
  150. {
  151.     // can be overridden in derived classes
  152. }
  153.  
  154. BOOL CControlBar::AllocElements(int nElements, int cbElement)
  155. {
  156.     ASSERT_VALID(this);
  157.     ASSERT(nElements >= 0 && cbElement >= 0);
  158.     ASSERT(m_pData != NULL || m_nCount == 0);
  159.  
  160.     // allocate new data if necessary
  161.     void* pData = NULL;
  162.     if (nElements > 0)
  163.     {
  164.         ASSERT(cbElement > 0);
  165.         if ((pData = calloc(nElements, cbElement)) == NULL)
  166.             return FALSE;
  167.     }
  168.     free(m_pData);      // free old data
  169.  
  170.     // set new data and elements
  171.     m_pData = pData;
  172.     m_nCount = nElements;
  173.  
  174.     return TRUE;
  175. }
  176.  
  177. #ifdef AFX_CORE3_SEG
  178. #pragma code_seg(AFX_CORE3_SEG)
  179. #endif
  180.  
  181. CControlBar::~CControlBar()
  182. {
  183.     ASSERT_VALID(this);
  184.  
  185.     DestroyWindow();    // avoid PostNcDestroy problems
  186.  
  187.     // also done in OnDestroy, but done here just in case
  188.     if (m_pDockSite != NULL)
  189.         m_pDockSite->RemoveControlBar(this);
  190.  
  191.     // free docking context
  192.     CDockContext* pDockContext = m_pDockContext;
  193.     m_pDockContext = NULL;
  194.     delete pDockContext;
  195.  
  196.     // free array
  197.     if (m_pData != NULL)
  198.     {
  199.         ASSERT(m_nCount != 0);
  200.         free(m_pData);
  201.     }
  202.  
  203.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  204.     if (pThreadState->m_pLastStatus == this)
  205.     {
  206.         pThreadState->m_pLastStatus = NULL;
  207.         pThreadState->m_nLastStatus = -1;
  208.     }
  209. }
  210.  
  211. void CControlBar::PostNcDestroy()
  212. {
  213.     if (m_bAutoDelete)      // Automatic cleanup?
  214.         delete this;
  215. }
  216.  
  217. /////////////////////////////////////////////////////////////////////////////
  218. // Attributes
  219.  
  220. CSize CControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  221. {
  222.     CSize size;
  223.     size.cx = (bStretch && bHorz ? 32767 : 0);
  224.     size.cy = (bStretch && !bHorz ? 32767 : 0);
  225.     return size;
  226. }
  227.  
  228. CSize CControlBar::CalcDynamicLayout(int, DWORD nMode)
  229. {
  230.     return CalcFixedLayout(nMode & LM_STRETCH, nMode & LM_HORZ);
  231. }
  232.  
  233. BOOL CControlBar::IsDockBar() const
  234. {
  235.     return FALSE;
  236. }
  237.  
  238. /////////////////////////////////////////////////////////////////////////////
  239. // Fly-by status bar help
  240.  
  241. #define ID_TIMER_WAIT   0xE000  // timer while waiting to show status
  242. #define ID_TIMER_CHECK  0xE001  // timer to check for removal of status
  243.  
  244. void CControlBar::ResetTimer(UINT nEvent, UINT nTime)
  245. {
  246.     KillTimer(ID_TIMER_WAIT);
  247.     KillTimer(ID_TIMER_CHECK);
  248.     VERIFY(SetTimer(nEvent, nTime, NULL));
  249. }
  250.  
  251. void CControlBar::OnTimer(UINT nIDEvent)
  252. {
  253.     if (GetKeyState(VK_LBUTTON) < 0)
  254.         return;
  255.  
  256.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  257.  
  258.     // get current mouse position for hit test
  259.     CPoint point; GetCursorPos(&point);
  260.     ScreenToClient(&point);
  261.     int nHit = OnToolHitTest(point, NULL);
  262.     if (nHit >= 0)
  263.     {
  264.         // determine if status bar help should go away
  265.         CWnd* pParent = GetTopLevelParent();
  266.         if (!IsTopParentActive() || !pParent->IsWindowEnabled())
  267.             nHit = -1;
  268.  
  269.         // remove status help if capture is set
  270.         HWND hWndTip = pThreadState->m_pToolTip->GetSafeHwnd();
  271.         CWnd* pCapture = GetCapture();
  272.         if (pCapture != this && pCapture->GetSafeHwnd() != hWndTip &&
  273.             pCapture->GetTopLevelParent() == pParent)
  274.         {
  275.             nHit = -1;
  276.         }
  277.     }
  278.     else
  279.     {
  280.         pThreadState->m_nLastStatus = -1;
  281.     }
  282.  
  283.     // make sure it isn't over some other app's window
  284.     if (nHit >= 0)
  285.     {
  286.         ClientToScreen(&point);
  287.         HWND hWnd = ::WindowFromPoint(point);
  288.         if (hWnd == NULL || (hWnd != m_hWnd && !::IsChild(m_hWnd, hWnd) &&
  289.             pThreadState->m_pToolTip->GetSafeHwnd() != hWnd))
  290.         {
  291.             nHit = -1;
  292.             pThreadState->m_nLastStatus = -1;
  293.         }
  294.     }
  295.  
  296.     // handle the result
  297.     if (nHit < 0)
  298.     {
  299.         if (pThreadState->m_nLastStatus == -1)
  300.             KillTimer(ID_TIMER_CHECK);
  301.         SetStatusText(-1);
  302.     }
  303.  
  304.     // set status text after initial timeout
  305.     if (nIDEvent == ID_TIMER_WAIT)
  306.     {
  307.         KillTimer(ID_TIMER_WAIT);
  308.         if (nHit >= 0)
  309.             SetStatusText(nHit);
  310.     }
  311. }
  312.  
  313. BOOL CControlBar::SetStatusText(int nHit)
  314. {
  315.     CWnd* pOwner = GetOwner();
  316.  
  317.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  318.     if (nHit == -1)
  319.     {
  320.         // handle reset case
  321.         pThreadState->m_pLastStatus = NULL;
  322.         if (m_nStateFlags & statusSet)
  323.         {
  324.             pOwner->SendMessage(WM_POPMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  325.             m_nStateFlags &= ~statusSet;
  326.             return TRUE;
  327.         }
  328.         KillTimer(ID_TIMER_WAIT);
  329.     }
  330.     else
  331.     {
  332.         // handle setnew case
  333.         if (!(m_nStateFlags & statusSet) || pThreadState->m_nLastStatus != nHit)
  334.         {
  335.             pThreadState->m_pLastStatus = this;
  336.             pOwner->SendMessage(WM_SETMESSAGESTRING, nHit);
  337.             m_nStateFlags |= statusSet;
  338.             ResetTimer(ID_TIMER_CHECK, 200);
  339.             return TRUE;
  340.         }
  341.     }
  342.     return FALSE;
  343. }
  344.  
  345. /////////////////////////////////////////////////////////////////////////////
  346. // Default control bar processing
  347.  
  348. BOOL CControlBar::PreTranslateMessage(MSG* pMsg)
  349. {
  350.     ASSERT_VALID(this);
  351.     ASSERT(m_hWnd != NULL);
  352.  
  353.     // allow tooltip messages to be filtered
  354.     if (CWnd::PreTranslateMessage(pMsg))
  355.         return TRUE;
  356.  
  357.     UINT message = pMsg->message;
  358.     CWnd* pOwner = GetOwner();
  359.  
  360.     // handle CBRS_FLYBY style (status bar flyby help)
  361.     if (((m_dwStyle & CBRS_FLYBY) ||
  362.         message == WM_LBUTTONDOWN || message == WM_LBUTTONUP) &&
  363.         ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) ||
  364.          (message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST)))
  365.     {
  366.         _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  367.  
  368.         // gather information about current mouse position
  369.         CPoint point = pMsg->pt;
  370.         ScreenToClient(&point);
  371.         TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
  372.         ti.cbSize = sizeof(TOOLINFO);
  373.         int nHit = OnToolHitTest(point, &ti);
  374.         if (ti.lpszText != LPSTR_TEXTCALLBACK)
  375.             free(ti.lpszText);
  376.         BOOL bNotButton =
  377.             message == WM_LBUTTONDOWN && (ti.uFlags & TTF_NOTBUTTON);
  378.         if (message != WM_LBUTTONDOWN && GetKeyState(VK_LBUTTON) < 0)
  379.             nHit = pThreadState->m_nLastStatus;
  380.  
  381.         // update state of status bar
  382.         if (nHit < 0 || bNotButton)
  383.         {
  384.             if (GetKeyState(VK_LBUTTON) >= 0 || bNotButton)
  385.             {
  386.                 SetStatusText(-1);
  387.                 KillTimer(ID_TIMER_CHECK);
  388.             }
  389.         }
  390.         else
  391.         {
  392.             if (message == WM_LBUTTONUP)
  393.             {
  394.                 SetStatusText(-1);
  395.                 ResetTimer(ID_TIMER_CHECK, 200);
  396.             }
  397.             else
  398.             {
  399.                 if ((m_nStateFlags & statusSet) || GetKeyState(VK_LBUTTON) < 0)
  400.                     SetStatusText(nHit);
  401.                 else if (nHit != pThreadState->m_nLastStatus)
  402.                     ResetTimer(ID_TIMER_WAIT, 300);
  403.             }
  404.         }
  405.         pThreadState->m_nLastStatus = nHit;
  406.     }
  407.  
  408.     // don't translate dialog messages when in Shift+F1 help mode
  409.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  410.     if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
  411.         return FALSE;
  412.  
  413.     // since 'IsDialogMessage' will eat frame window accelerators,
  414.     //   we call all frame windows' PreTranslateMessage first
  415.     while (pOwner != NULL)
  416.     {
  417.         // allow owner & frames to translate before IsDialogMessage does
  418.         if (pOwner->PreTranslateMessage(pMsg))
  419.             return TRUE;
  420.  
  421.         // try parent frames until there are no parent frames
  422.         pOwner = pOwner->GetParentFrame();
  423.     }
  424.  
  425.     // filter both messages to dialog and from children
  426.     return PreTranslateInput(pMsg);
  427. }
  428.  
  429. LRESULT CControlBar::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  430. {
  431.     ASSERT_VALID(this);
  432.  
  433.     LRESULT lResult;
  434.     switch (nMsg)
  435.     {
  436.     case WM_NOTIFY:
  437.     case WM_COMMAND:
  438.     case WM_DRAWITEM:
  439.     case WM_MEASUREITEM:
  440.     case WM_DELETEITEM:
  441.     case WM_COMPAREITEM:
  442.     case WM_VKEYTOITEM:
  443.     case WM_CHARTOITEM:
  444.         // send these messages to the owner if not handled
  445.         if (OnWndMsg(nMsg, wParam, lParam, &lResult))
  446.             return lResult;
  447.         else
  448.             return GetOwner()->SendMessage(nMsg, wParam, lParam);
  449.     }
  450.  
  451.     // otherwise, just handle in default way
  452.     lResult = CWnd::WindowProc(nMsg, wParam, lParam);
  453.     return lResult;
  454. }
  455.  
  456. LRESULT CControlBar::OnHelpHitTest(WPARAM, LPARAM lParam)
  457. {
  458.     ASSERT_VALID(this);
  459.  
  460.     int nID = OnToolHitTest((DWORD)lParam, NULL);
  461.     if (nID != -1)
  462.         return HID_BASE_COMMAND+nID;
  463.  
  464.     nID = _AfxGetDlgCtrlID(m_hWnd);
  465.     return nID != 0 ? HID_BASE_CONTROL+nID : 0;
  466. }
  467.  
  468. void CControlBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
  469. {
  470.     CWnd::OnWindowPosChanging(lpWndPos);
  471.  
  472.     if (lpWndPos->flags & SWP_NOSIZE)
  473.         return;
  474.  
  475.     // invalidate borders on the right
  476.     CRect rect;
  477.     GetWindowRect(&rect);
  478.     CSize sizePrev = rect.Size();
  479.     int cx = lpWndPos->cx;
  480.     int cy = lpWndPos->cy;
  481.     if (cx != sizePrev.cx && (m_dwStyle & CBRS_BORDER_RIGHT))
  482.     {
  483.         rect.SetRect(cx-afxData.cxBorder2, 0, cx, cy);
  484.         InvalidateRect(&rect);
  485.         rect.SetRect(sizePrev.cx-afxData.cxBorder2, 0, sizePrev.cx, cy);
  486.         InvalidateRect(&rect);
  487.     }
  488.  
  489.     // invalidate borders on the bottom
  490.     if (cy != sizePrev.cy && (m_dwStyle & CBRS_BORDER_BOTTOM))
  491.     {
  492.         rect.SetRect(0, cy-afxData.cyBorder2, cx, cy);
  493.         InvalidateRect(&rect);
  494.         rect.SetRect(0, sizePrev.cy-afxData.cyBorder2, cx, sizePrev.cy);
  495.         InvalidateRect(&rect);
  496.     }
  497. }
  498.  
  499. int CControlBar::OnCreate(LPCREATESTRUCT lpcs)
  500. {
  501.     if (CWnd::OnCreate(lpcs) == -1)
  502.         return -1;
  503.  
  504.     if (m_dwStyle & CBRS_TOOLTIPS)
  505.         EnableToolTips();
  506.  
  507.     CFrameWnd *pFrameWnd = (CFrameWnd*)GetParent();
  508.     if (pFrameWnd->IsFrameWnd())
  509.     {
  510.         m_pDockSite = pFrameWnd;
  511.         m_pDockSite->AddControlBar(this);
  512.     }
  513.     return 0;
  514. }
  515.  
  516. void CControlBar::OnDestroy()
  517. {
  518.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  519.     if (pThreadState->m_pLastStatus == this)
  520.     {
  521.         SetStatusText(-1);
  522.         ASSERT(pThreadState->m_pLastStatus == NULL);
  523.     }
  524.  
  525.     if (m_pDockSite != NULL)
  526.     {
  527.         m_pDockSite->RemoveControlBar(this);
  528.         m_pDockSite = NULL;
  529.     }
  530.  
  531.     CWnd::OnDestroy();
  532. }
  533.  
  534. BOOL CControlBar::DestroyWindow()
  535. {
  536.     if (m_hWnd != NULL && IsFloating())
  537.         return GetDockingFrame()->DestroyWindow();
  538.     else
  539.         return CWnd::DestroyWindow();
  540. }
  541.  
  542. int CControlBar::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT nMsg)
  543. {
  544.     // call default when toolbar is not floating
  545.     if (!IsFloating())
  546.         return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, nMsg);
  547.  
  548.     // special behavior when floating
  549.     ActivateTopParent();
  550.  
  551.     return MA_NOACTIVATE;   // activation already done
  552. }
  553.  
  554. void CControlBar::OnPaint()
  555. {
  556.     // background is already filled in grey
  557.     CPaintDC dc(this);
  558.  
  559.     // erase background now
  560.     if (IsVisible())
  561.         DoPaint(&dc);       // delegate to paint helper
  562. }
  563.  
  564. void CControlBar::EraseNonClient()
  565. {
  566.     // get window DC that is clipped to the non-client area
  567.     CWindowDC dc(this);
  568.     CRect rectClient;
  569.     GetClientRect(rectClient);
  570.     CRect rectWindow;
  571.     GetWindowRect(rectWindow);
  572.     ScreenToClient(rectWindow);
  573.     rectClient.OffsetRect(-rectWindow.left, -rectWindow.top);
  574.     dc.ExcludeClipRect(rectClient);
  575.  
  576.     // draw borders in non-client area
  577.     rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);
  578.     DrawBorders(&dc, rectWindow);
  579.  
  580.     // erase parts not drawn
  581.     dc.IntersectClipRect(rectWindow);
  582.     SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC);
  583. }
  584.  
  585. HBRUSH CControlBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  586. {
  587.     LRESULT lResult;
  588.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  589.         return (HBRUSH)lResult;     // eat it
  590.  
  591.     // force black text on grey background all the time
  592.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  593.        afxData.hbrBtnFace, afxData.clrBtnText))
  594.         return (HBRUSH)Default();
  595.     return afxData.hbrBtnFace;
  596. }
  597.  
  598. void CControlBar::OnLButtonDown(UINT nFlags, CPoint pt)
  599. {
  600.     // only start dragging if clicked in "void" space
  601.     if (m_pDockBar != NULL && OnToolHitTest(pt, NULL) == -1)
  602.     {
  603.         // start the drag
  604.         ASSERT(m_pDockContext != NULL);
  605.         ClientToScreen(&pt);
  606.         m_pDockContext->StartDrag(pt);
  607.     }
  608.     else
  609.     {
  610.         CWnd::OnLButtonDown(nFlags, pt);
  611.     }
  612. }
  613.  
  614. void CControlBar::OnLButtonDblClk(UINT nFlags, CPoint pt)
  615. {
  616.     // only toggle docking if clicked in "void" space
  617.     if (m_pDockBar != NULL && OnToolHitTest(pt, NULL) == -1)
  618.     {
  619.         // start the drag
  620.         ASSERT(m_pDockContext != NULL);
  621.         m_pDockContext->ToggleDocking();
  622.     }
  623.     else
  624.     {
  625.         CWnd::OnLButtonDblClk(nFlags, pt);
  626.     }
  627. }
  628.  
  629. LRESULT CControlBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
  630. {
  631.     // handle delay hide/show
  632.     BOOL bVis = GetStyle() & WS_VISIBLE;
  633.     UINT swpFlags = 0;
  634.     if ((m_nStateFlags & delayHide) && bVis)
  635.         swpFlags = SWP_HIDEWINDOW;
  636.     else if ((m_nStateFlags & delayShow) && !bVis)
  637.         swpFlags = SWP_SHOWWINDOW;
  638.     m_nStateFlags &= ~(delayShow|delayHide);
  639.     if (swpFlags != 0)
  640.     {
  641.         SetWindowPos(NULL, 0, 0, 0, 0, swpFlags|
  642.             SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  643.     }
  644.  
  645.     // the style must be visible and if it is docked
  646.     // the dockbar style must also be visible
  647.     if ((GetStyle() & WS_VISIBLE) &&
  648.         (m_pDockBar == NULL || (m_pDockBar->GetStyle() & WS_VISIBLE)))
  649.     {
  650.         CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  651.         if (pTarget == NULL || !pTarget->IsFrameWnd())
  652.             pTarget = GetParentFrame();
  653.         if (pTarget != NULL)
  654.             OnUpdateCmdUI(pTarget, (BOOL)wParam);
  655.     }
  656.     return 0L;
  657. }
  658.  
  659. void CControlBar::OnInitialUpdate()
  660. {
  661.     // update the indicators before becoming visible
  662.     OnIdleUpdateCmdUI(TRUE, 0L);
  663. }
  664.  
  665. DWORD CControlBar::RecalcDelayShow(AFX_SIZEPARENTPARAMS* lpLayout)
  666. {
  667.     ASSERT(lpLayout != NULL);
  668.  
  669.     // resize and reposition this control bar based on styles
  670.     DWORD dwStyle = (m_dwStyle & (CBRS_ALIGN_ANY|CBRS_BORDER_ANY)) |
  671.         (GetStyle() & WS_VISIBLE);
  672.  
  673.     // handle delay hide/show
  674.     if (m_nStateFlags & (delayHide|delayShow))
  675.     {
  676.         UINT swpFlags = 0;
  677.         if (m_nStateFlags & delayHide)
  678.         {
  679.             ASSERT((m_nStateFlags & delayShow) == 0);
  680.             if (dwStyle & WS_VISIBLE)
  681.                 swpFlags = SWP_HIDEWINDOW;
  682.         }
  683.         else
  684.         {
  685.             ASSERT(m_nStateFlags & delayShow);
  686.             if ((dwStyle & WS_VISIBLE) == 0)
  687.                 swpFlags = SWP_SHOWWINDOW;
  688.         }
  689.         if (swpFlags != 0)
  690.         {
  691.             // make the window seem visible/hidden
  692.             dwStyle ^= WS_VISIBLE;
  693.             if (lpLayout->hDWP != NULL)
  694.             {
  695.                 // clear delay flags
  696.                 m_nStateFlags &= ~(delayShow|delayHide);
  697.                 // hide/show the window if actually doing layout
  698.                 lpLayout->hDWP = ::DeferWindowPos(lpLayout->hDWP, m_hWnd, NULL,
  699.                     0, 0, 0, 0, swpFlags|
  700.                     SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  701.             }
  702.         }
  703.         else
  704.         {
  705.             // clear delay flags -- window is already in correct state
  706.             m_nStateFlags &= ~(delayShow|delayHide);
  707.         }
  708.     }
  709.     return dwStyle; // return new style
  710. }
  711.  
  712. LRESULT CControlBar::OnSizeParent(WPARAM, LPARAM lParam)
  713. {
  714.     AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
  715.     DWORD dwStyle = RecalcDelayShow(lpLayout);
  716.  
  717.     if ((dwStyle & WS_VISIBLE) && (dwStyle & CBRS_ALIGN_ANY) != 0)
  718.     {
  719.         // align the control bar
  720.         CRect rect;
  721.         rect.CopyRect(&lpLayout->rect);
  722.  
  723.         CSize sizeAvail = rect.Size();  // maximum size available
  724.  
  725.         // get maximum requested size
  726.         DWORD dwMode = lpLayout->bStretch ? LM_STRETCH : 0;
  727.         if ((m_dwStyle & CBRS_SIZE_DYNAMIC) && m_dwStyle & CBRS_FLOATING)
  728.             dwMode |= LM_HORZ | LM_MRUWIDTH;
  729.         else if (dwStyle & CBRS_ORIENT_HORZ)
  730.             dwMode |= LM_HORZ | LM_HORZDOCK;
  731.         else
  732.             dwMode |=  LM_VERTDOCK;
  733.  
  734.         CSize size = CalcDynamicLayout(-1, dwMode);
  735.  
  736.         size.cx = min(size.cx, sizeAvail.cx);
  737.         size.cy = min(size.cy, sizeAvail.cy);
  738.  
  739.         if (dwStyle & CBRS_ORIENT_HORZ)
  740.         {
  741.             lpLayout->sizeTotal.cy += size.cy;
  742.             lpLayout->sizeTotal.cx = max(lpLayout->sizeTotal.cx, size.cx);
  743.             if (dwStyle & CBRS_ALIGN_TOP)
  744.                 lpLayout->rect.top += size.cy;
  745.             else if (dwStyle & CBRS_ALIGN_BOTTOM)
  746.             {
  747.                 rect.top = rect.bottom - size.cy;
  748.                 lpLayout->rect.bottom -= size.cy;
  749.             }
  750.         }
  751.         else if (dwStyle & CBRS_ORIENT_VERT)
  752.         {
  753.             lpLayout->sizeTotal.cx += size.cx;
  754.             lpLayout->sizeTotal.cy = max(lpLayout->sizeTotal.cy, size.cy);
  755.             if (dwStyle & CBRS_ALIGN_LEFT)
  756.                 lpLayout->rect.left += size.cx;
  757.             else if (dwStyle & CBRS_ALIGN_RIGHT)
  758.             {
  759.                 rect.left = rect.right - size.cx;
  760.                 lpLayout->rect.right -= size.cx;
  761.             }
  762.         }
  763.         else
  764.         {
  765.             ASSERT(FALSE);      // can never happen
  766.         }
  767.  
  768.         rect.right = rect.left + size.cx;
  769.         rect.bottom = rect.top + size.cy;
  770.  
  771. #ifdef _MAC
  772.         // account for the Macintosh grow box, if there is one
  773.         CWnd* pWnd = GetParentFrame();
  774.         if (pWnd != NULL)
  775.         {
  776.             DWORD dwWndStyle = pWnd->GetStyle();
  777.             DWORD dwExStyle = pWnd->GetExStyle();
  778.  
  779.             if (!(dwExStyle & (WS_EX_MDIFRAME|WS_EX_FORCESIZEBOX)) &&
  780.                 !(dwWndStyle & (WS_VSCROLL|WS_HSCROLL)))
  781.             {
  782.                 CRect rectParent;
  783.                 pWnd->GetClientRect(rectParent);
  784.  
  785.                 if (dwStyle & CBRS_ALIGN_BOTTOM)
  786.                 {
  787.                     if (rect.bottom > rectParent.bottom - afxData.cxVScroll + 1)
  788.                         rect.right -= (afxData.cxVScroll - 1);
  789.                 }
  790.                 else if (dwStyle & CBRS_ALIGN_RIGHT)
  791.                 {
  792.                     if (rect.bottom > rectParent.bottom - afxData.cyHScroll + 1)
  793.                         rect.bottom -= (afxData.cxVScroll - 1);
  794.                 }
  795.             }
  796.         }
  797. #endif
  798.  
  799.         // only resize the window if doing layout and not just rect query
  800.         if (lpLayout->hDWP != NULL)
  801.             AfxRepositionWindow(lpLayout, m_hWnd, &rect);
  802.     }
  803.     return 0;
  804. }
  805.  
  806. void CControlBar::DelayShow(BOOL bShow)
  807. {
  808.     m_nStateFlags &= ~(delayHide|delayShow);
  809.     if (bShow && (GetStyle() & WS_VISIBLE) == 0)
  810.         m_nStateFlags |= delayShow;
  811.     else if (!bShow && (GetStyle() & WS_VISIBLE) != 0)
  812.         m_nStateFlags |= delayHide;
  813. }
  814.  
  815. BOOL CControlBar::IsVisible() const
  816. {
  817.     if (m_nStateFlags & delayHide)
  818.         return FALSE;
  819.  
  820.     if ((m_nStateFlags & delayShow) || ((GetStyle() & WS_VISIBLE) != 0))
  821.         return TRUE;
  822.  
  823.     return FALSE;
  824. }
  825.  
  826. void CControlBar::DoPaint(CDC* pDC)
  827. {
  828.     ASSERT_VALID(this);
  829.     ASSERT_VALID(pDC);
  830.  
  831.     // paint inside client area
  832.     CRect rect;
  833.     GetClientRect(rect);
  834.     DrawBorders(pDC, rect);
  835. }
  836.  
  837. void CControlBar::DrawBorders(CDC* pDC, CRect& rect)
  838. {
  839.     ASSERT_VALID(this);
  840.     ASSERT_VALID(pDC);
  841.  
  842.     DWORD dwStyle = m_dwStyle;
  843.     if (!(dwStyle & CBRS_BORDER_ANY))
  844.         return;
  845.  
  846.     // prepare for dark lines
  847.     ASSERT(rect.top == 0 && rect.left == 0);
  848.     CRect rect1, rect2;
  849.     rect1 = rect;
  850.     rect2 = rect;
  851.     COLORREF clr = afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
  852.  
  853.     // draw dark line one pixel back/up
  854.     if (dwStyle & CBRS_BORDER_3D)
  855.     {
  856.         rect1.right -= CX_BORDER;
  857.         rect1.bottom -= CY_BORDER;
  858.     }
  859.     if (dwStyle & CBRS_BORDER_TOP)
  860.         rect2.top += afxData.cyBorder2;
  861.     if (dwStyle & CBRS_BORDER_BOTTOM)
  862.         rect2.bottom -= afxData.cyBorder2;
  863.  
  864.     // draw left and top
  865.     if (dwStyle & CBRS_BORDER_LEFT)
  866.         pDC->FillSolidRect(0, rect2.top, CX_BORDER, rect2.Height(), clr);
  867.     if (dwStyle & CBRS_BORDER_TOP)
  868.         pDC->FillSolidRect(0, 0, rect.right, CY_BORDER, clr);
  869.  
  870.     // draw right and bottom
  871.     if (dwStyle & CBRS_BORDER_RIGHT)
  872.         pDC->FillSolidRect(rect1.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
  873.     if (dwStyle & CBRS_BORDER_BOTTOM)
  874.         pDC->FillSolidRect(0, rect1.bottom, rect.right, -CY_BORDER, clr);
  875.  
  876.     if (dwStyle & CBRS_BORDER_3D)
  877.     {
  878.         // prepare for hilite lines
  879.         clr = afxData.clrBtnHilite;
  880.  
  881.         // draw left and top
  882.         if (dwStyle & CBRS_BORDER_LEFT)
  883.             pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
  884.         if (dwStyle & CBRS_BORDER_TOP)
  885.             pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);
  886.  
  887.         // draw right and bottom
  888.         if (dwStyle & CBRS_BORDER_RIGHT)
  889.             pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
  890.         if (dwStyle & CBRS_BORDER_BOTTOM)
  891.             pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
  892.     }
  893.  
  894.     if (dwStyle & CBRS_BORDER_LEFT)
  895.         rect.left += afxData.cxBorder2;
  896.     if (dwStyle & CBRS_BORDER_TOP)
  897.         rect.top += afxData.cyBorder2;
  898.     if (dwStyle & CBRS_BORDER_RIGHT)
  899.         rect.right -= afxData.cxBorder2;
  900.     if (dwStyle & CBRS_BORDER_BOTTOM)
  901.         rect.bottom -= afxData.cyBorder2;
  902. }
  903.  
  904. // input CRect should be client rectangle size
  905. void CControlBar::CalcInsideRect(CRect& rect, BOOL bHorz) const
  906. {
  907.     ASSERT_VALID(this);
  908.     DWORD dwStyle = m_dwStyle;
  909.  
  910.     if (dwStyle & CBRS_BORDER_LEFT)
  911.         rect.left += afxData.cxBorder2;
  912.     if (dwStyle & CBRS_BORDER_TOP)
  913.         rect.top += afxData.cyBorder2;
  914.     if (dwStyle & CBRS_BORDER_RIGHT)
  915.         rect.right -= afxData.cxBorder2;
  916.     if (dwStyle & CBRS_BORDER_BOTTOM)
  917.         rect.bottom -= afxData.cyBorder2;
  918.  
  919.     // inset the top and bottom.
  920.     if (bHorz)
  921.     {
  922.         rect.left += m_cxLeftBorder;
  923.         rect.top += m_cyTopBorder;
  924.         rect.right -= m_cxRightBorder;
  925.         rect.bottom -= m_cyBottomBorder;
  926.     }
  927.     else
  928.     {
  929.         rect.left += m_cyTopBorder;
  930.         rect.top += m_cxLeftBorder;
  931.         rect.right -= m_cyBottomBorder;
  932.         rect.bottom -= m_cxRightBorder;
  933.     }
  934. }
  935.  
  936. /////////////////////////////////////////////////////////////////////////////
  937. // CControlBar diagnostics
  938.  
  939. #ifdef _DEBUG
  940. void CControlBar::AssertValid() const
  941. {
  942.     CWnd::AssertValid();
  943.  
  944.     ASSERT(m_nCount == 0 || m_pData != NULL);
  945. }
  946.  
  947. void CControlBar::Dump(CDumpContext& dc) const
  948. {
  949.     CWnd::Dump(dc);
  950.  
  951.     dc << "\nm_cxLeftBorder = " << m_cxLeftBorder;
  952.     dc << "\nm_cxRightBorder = " << m_cxRightBorder;
  953.     dc << "\nm_cyTopBorder = " << m_cyTopBorder;
  954.     dc << "\nm_cyBottomBorder = " << m_cyBottomBorder;
  955.     dc << "\nm_cxDefaultGap = " << m_cxDefaultGap;
  956.     dc << "\nm_nCount = " << m_nCount;
  957.     dc << "\nm_bAutoDelete = " << m_bAutoDelete;
  958.  
  959.     dc << "\n";
  960. }
  961. #endif
  962.  
  963. /////////////////////////////////////////////////////////////////////////////
  964. // Macintosh specifics
  965.  
  966. #ifdef _MAC
  967. void CControlBar::OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/)
  968. {
  969.     OnReposition();
  970. }
  971.  
  972. BOOL CControlBar::OnEraseBkgnd(CDC* pDC)
  973. {
  974.     if (!m_bMonochrome)
  975.         return (BOOL)Default();
  976.  
  977.     CRect rect;
  978.     GetClientRect(rect);
  979.     pDC->FillSolidRect(rect, RGB(0xFF, 0xFF, 0xFF));
  980.     return TRUE;
  981. }
  982.  
  983. LRESULT CControlBar::OnMacintosh(WPARAM wParam, LPARAM)
  984. {
  985.     // The ancestor of the control bar may have moved from one monitor to
  986.     //  another, so we need to redetermine whether to draw in monochrome
  987.     //  or color.
  988.     if (LOWORD(wParam) == WLM_CHILDOFFSET)
  989.         OnReposition();
  990.  
  991.     return Default();
  992. }
  993.  
  994. void CControlBar::OnSysColorChange()
  995. {
  996.     Default();  // toolbar control must be notified also
  997.     m_bMonochrome = CheckMonochrome();
  998. }
  999.  
  1000. void CControlBar::OnMove(int, int)
  1001. {
  1002.     OnReposition();
  1003. }
  1004.  
  1005. void CControlBar::OnReposition()
  1006. {
  1007.     if (CheckMonochrome() != m_bMonochrome)
  1008.     {
  1009.         SendMessage(WM_SYSCOLORCHANGE, 0, 0);
  1010.         RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
  1011.     }
  1012. }
  1013.  
  1014. BOOL CControlBar::CheckMonochrome()
  1015. {
  1016.     RECT rectClient;
  1017.     GetClientRect(&rectClient);
  1018.     MapWindowPoints(GetDesktopWindow(), &rectClient);
  1019.     return AfxCheckMonochrome(&rectClient);
  1020. }
  1021.  
  1022. BOOL AFXAPI AfxCheckMonochrome(const RECT* pRect)
  1023. {
  1024.     long versionQD;
  1025.     if (Gestalt(gestaltQuickdrawVersion, &versionQD) != noErr ||
  1026.             versionQD < gestalt8BitQD)
  1027.         return TRUE;
  1028.  
  1029.     // We draw all toolbars in monochrome if the main monitor is monochrome
  1030.     // because the main monitor is what determines the button face color
  1031.     // and button shadow color, and if those aren't grays, we won't get
  1032.     // reasonable output no matter how deep a monitor we're drawing on.
  1033.     if (GetSysColor(COLOR_BTNFACE) == RGB(255, 255, 255))
  1034.         return TRUE;
  1035.  
  1036.     Rect rectMacClient;
  1037.     rectMacClient.top = (short)pRect->top;
  1038.     rectMacClient.left = (short)pRect->left;
  1039.     rectMacClient.bottom = (short)pRect->bottom;
  1040.     rectMacClient.right = (short)pRect->right;
  1041.  
  1042.     for (GDHandle hgd = GetDeviceList(); hgd != NULL; hgd = GetNextDevice(hgd))
  1043.     {
  1044.         if (!TestDeviceAttribute(hgd, screenDevice) ||
  1045.                 !TestDeviceAttribute(hgd, screenActive))
  1046.             continue;
  1047.  
  1048.         // ignore devices that the toolbar isn't drawn on
  1049.         Rect rect;
  1050.         if (!SectRect(&rectMacClient, &(*hgd)->gdRect, &rect))
  1051.             continue;
  1052.  
  1053.         // we require 2-bit grayscale or 4-bit color to draw in color
  1054.         int pixelSize = (*(*hgd)->gdPMap)->pixelSize;
  1055.         if (pixelSize == 1 || (pixelSize == 2 &&
  1056.                 TestDeviceAttribute(hgd, gdDevType)))
  1057.             return TRUE;
  1058.     }
  1059.  
  1060.     return FALSE;
  1061. }
  1062.  
  1063. #if USESCODEFRAGMENTS
  1064. #undef PtInRect
  1065. #define MacPtInRect PtInRect
  1066. extern "C" pascal Boolean PtInRect(Point pt, const Rect *r);
  1067. #endif
  1068. GDHandle AFXAPI _AfxFindDevice(int x, int y)
  1069. {
  1070.     long lResult;
  1071.     Point pt;
  1072.     GDHandle hgd;
  1073.  
  1074.     if (Gestalt(gestaltQuickdrawVersion, &lResult) != noErr ||
  1075.             lResult < gestalt8BitQD)
  1076.         return NULL;
  1077.  
  1078.     pt.h = (short) x;
  1079.     pt.v = (short) y;
  1080.  
  1081.     hgd = GetDeviceList();
  1082.     while (hgd != NULL)
  1083.     {
  1084.         if (MacPtInRect(pt, &(*hgd)->gdRect))
  1085.             return hgd;
  1086.  
  1087.         hgd = GetNextDevice(hgd);
  1088.     }
  1089.  
  1090.     return NULL;
  1091. }
  1092. #if USESCODEFRAGMENTS
  1093. #define PtInRect AfxPtInRect
  1094. #endif
  1095. #endif //_MAC
  1096.  
  1097. /////////////////////////////////////////////////////////////////////////////
  1098.