1 ////////////////////////////////////////////////////////////////
2 // Copyright 1998 Paul DiLascia
3 // If this code works, it was written by Paul DiLascia.
4 // If not, I don't know who wrote it.
6 // CFlatToolBar implements dockable flat-style toolbars with "grippers"
10 #include "UIModulVer.h"
12 // if you want to see extra TRACE diagnostics, set below to TRUE
13 BOOL CFlatToolBar::bTRACE = FALSE;
24 #define FBTRACEFN TRACE
29 // One of these for each drop-down button
31 struct DROPDOWNBUTTON {
33 UINT idButton; // command ID of button
34 UINT idMenu; // popup menu to display
37 // these define size of grippers
39 const GRIP_MARGIN = 5;
41 // flags stored in item data
42 #define ITEMF_INITIALIZED 0x01 // item data initialized
43 #define ITEMF_CHECKED 0x02 // item is checked
48 static char THIS_FILE[] = __FILE__;
51 ////////////////////////////////////////////////////////////////
52 // CFlatToolBar--does flat tool bar in MFC.
54 IMPLEMENT_DYNAMIC(CFlatToolBar, CFlatToolBarBase)
56 BEGIN_MESSAGE_MAP(CFlatToolBar, CFlatToolBarBase)
57 ON_NOTIFY_REFLECT(TBN_DROPDOWN, OnTbnDropDown)
58 ON_WM_WINDOWPOSCHANGING()
59 ON_WM_WINDOWPOSCHANGED()
67 CFlatToolBar::CFlatToolBar()
69 FBTRACE(_T("CFlatToolBar::CFlatToolBar, comctl32 version = %d\n"),
72 m_bDrawDisabledButtonsInColor = FALSE; // don't use color
73 m_bInCoolBar = FALSE; // assume not inside coolbar
74 m_pDropDownButtons = NULL; // list of drop-down buttons
75 m_bShowDropdownArrowWhenVertical = TRUE;
79 CFlatToolBar::~CFlatToolBar()
81 while (m_pDropDownButtons) {
82 DROPDOWNBUTTON* pnext = m_pDropDownButtons->next;
83 delete m_pDropDownButtons;
84 m_pDropDownButtons = pnext;
89 // Create handler: set flat style by default
91 int CFlatToolBar::OnCreate(LPCREATESTRUCT lpcs)
93 if (CFlatToolBarBase::OnCreate(lpcs) == -1)
95 ModifyStyle(0, TBSTYLE_FLAT);
100 // Load function sets flat style after loading buttons.
102 BOOL CFlatToolBar::LoadToolBar(LPCTSTR lpszResourceName)
104 // Set transparent/flat style before loading buttons to allow zero-height
105 // border. This required because of bug in comctl32.dll that always adds
106 // a border, unless flat/transparent.
108 DWORD dwStyle = GetStyle();
109 ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
110 BOOL bRet = CFlatToolBarBase::LoadToolBar(lpszResourceName);
111 SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
116 // Calcluate size of client area. Adds room for grippers
118 void CFlatToolBar::OnNcCalcSize(BOOL bCalc, NCCALCSIZE_PARAMS* pncp)
120 if (m_bInCoolBar) { // if I am in a coolbar (rebar):
121 Default(); // ..bypass CToolBar/CControlBar
124 CRect& rc = (CRect&)pncp->rgrc[0]; // rect to return
126 // copied from MFC below:
127 CRect rcMargin(0,0,0,0);
128 CControlBar::CalcInsideRect(rcMargin, m_dwStyle & CBRS_ORIENT_HORZ);
130 // adjust non-client area for border space
131 rc.left += rcMargin.left;
132 rc.top += rcMargin.top; // MFC has -2 here, bug for newer comctl32
133 rc.right += rcMargin.right;
134 rc.bottom+= rcMargin.bottom;
139 // MFC doesn't handle moving a TBSTYLE_FLAT toolbar correctly. The simplest
140 // way to fix it is to repaint whatever was underneath whenever the toolbar
141 // moves. This is done in this and the following function. All this stuff is
142 // only required because flat toolbars paint transparently (don't paint their
145 void CFlatToolBar::OnWindowPosChanging(LPWINDOWPOS lpwp)
148 // inside coolbars, don't do MFC thing
151 CFlatToolBarBase::OnWindowPosChanging(lpwp);
152 if (!(lpwp->flags & SWP_NOMOVE))
153 GetWindowRect(&m_rcOldPos); // remember old position
158 // Now toolbar has really moved: repaint area beneath old position
160 void CFlatToolBar::OnWindowPosChanged(LPWINDOWPOS lpwp)
165 CFlatToolBarBase::OnWindowPosChanged(lpwp);
166 if (!(lpwp->flags & SWP_NOMOVE)) { // if moved:
167 InvalidateOldPos(m_rcOldPos); // invalidate area of old position
169 // Now paint my non-client area at the new location.
170 // Without this, you will still have a partial display bug (try it!)
171 SendMessage(WM_NCPAINT);
177 // Invalidate toolbar rectangle. Because flat toolbars are transparent,
178 // this requires invalidating parent and all siblings that intersect the
181 void CFlatToolBar::InvalidateOldPos(const CRect& rcInvalid)
183 // make parent paint the area beneath rectangle
184 CWnd* pParent = GetParent(); // parent (dock bar/frame) window
185 ASSERT_VALID(pParent); // check
186 CRect rc = rcInvalid; // copy rectangle
187 pParent->ScreenToClient(&rc); // convert to parent client coords
188 pParent->InvalidateRect(&rc); // invalidate
190 // now do same for each sibling too
191 for (CWnd* pSib = pParent->GetWindow(GW_CHILD);
193 pSib=pSib->GetNextWindow(GW_HWNDNEXT)) {
195 CRect rc; // window rect of sibling
196 pSib->GetWindowRect(&rc); // ...
197 if (rc.IntersectRect(rc, rcInvalid)) { // if intersects invalid rect
198 pSib->ScreenToClient(&rc); // convert to sibling coords
199 pSib->InvalidateRect(&rc); // invalidate
200 pSib->SendMessage(WM_NCPAINT); // nonclient area too!
206 // Override to avoid MFC in case I'm inside a coolbar
208 BOOL CFlatToolBar::OnEraseBkgnd(CDC* pDC)
210 return m_bInCoolBar ? Default() : CFlatToolBarBase::OnEraseBkgnd(pDC);
214 // If toolbar is inside a coolbar, need to make the parent frame
215 // my owner so it will get notifications.
217 BOOL CFlatToolBar::OnNcCreate(LPCREATESTRUCT lpcs)
219 CWnd* pParent = GetParent();
222 GetClassName(pParent->m_hWnd, classname, countof(classname));
223 if (_tcscmp(classname, REBARCLASSNAME)==0) {
224 CFrameWnd* pFrame = GetParentFrame();
225 ASSERT_VALID(pFrame);
229 return CFlatToolBarBase::OnNcCreate(lpcs);
233 // Avoid MFC if I'm inside a coolbar
235 void CFlatToolBar::OnPaint()
238 Default(); // bypass CToolBar/CControlBar
240 CFlatToolBarBase::OnPaint();
243 ////////////////////////////////////////////////////////////////
244 // Stuff for handling drop-down buttons in toobars
248 // Add dropdown buttons.
249 // The manager takes care of setting appropriate styles, etc.
252 // - array of LONGs: MAKELONG(commandID, menuID)
253 // - number of buttons
255 BOOL CFlatToolBar::AddDropDownButton(UINT nIDButton, UINT nIDMenu, BOOL bArrow)
259 DROPDOWNBUTTON* pb = FindDropDownButton(nIDButton);
261 pb = new DROPDOWNBUTTON;
263 pb->next = m_pDropDownButtons;
264 m_pDropDownButtons = pb;
266 pb->idButton = nIDButton;
267 pb->idMenu = nIDMenu;
269 int iButton = CommandToIndex(nIDButton);
271 DWORD dwStyle = GetButtonStyle(iButton);
272 dwStyle |= TBSTYLE_DROPDOWN;
273 SetButtonStyle(iButton, dwStyle);
276 SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
282 // Find buttons structure for given ID
284 DROPDOWNBUTTON* CFlatToolBar::FindDropDownButton(UINT nID)
286 for (DROPDOWNBUTTON* pb = m_pDropDownButtons; pb; pb = pb->next) {
287 if (pb->idButton == nID)
294 // Handle TBN_DROPDOWN
295 // Default is to display the specified menu at the right place.
296 // You can override to generate dynamic menus
299 // - NMTOOLBAR struct from TBN_DROPDOWN
300 // - command id of button
301 // - point to display menu at
303 void CFlatToolBar::OnTbnDropDown(NMHDR* pNMHDR, LRESULT* pRes)
305 const NMTOOLBAR& nmtb = *(NMTOOLBAR*)pNMHDR;
307 // get location of button
309 GetRect(nmtb.iItem, rc);
312 // call virtual function to display dropdown menu
313 OnDropDownButton(nmtb, nmtb.iItem, rc);
317 // Virtual fn you can override to hand drop-down button
318 // events with more friendly args
320 void CFlatToolBar::OnDropDownButton(const NMTOOLBAR& nmtb, UINT nID, CRect rc)
322 DROPDOWNBUTTON* pb = FindDropDownButton(nmtb.iItem);
323 if (pb && pb->idMenu) {
325 // load and display popup menu
327 VERIFY(menu.LoadMenu(pb->idMenu));
328 CMenu* pPopup = menu.GetSubMenu(0);
330 pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
331 rc.left, rc.bottom, GetOwner(), &rc);