This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / UIFlatBar.cpp
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.
5 //
6 // CFlatToolBar implements dockable flat-style toolbars with "grippers"
7 //
8 #include "StdAfx.h"
9 #include "UIFlatBar.h"
10 #include "UIModulVer.h"
11
12 // if you want to see extra TRACE diagnostics, set below to TRUE
13 BOOL CFlatToolBar::bTRACE   = FALSE;
14
15 #ifdef _DEBUG
16 #define FBTRACEFN                       \
17         CTraceFn __fooble;      \
18         if (bTRACE)                             \
19                 TRACE
20 #define FBTRACE                 \
21         if (bTRACE)                   \
22                 TRACE
23 #else
24 #define FBTRACEFN TRACE
25 #define FBTRACE   TRACE
26 #endif
27
28 /////////////////
29 // One of these for each drop-down button
30 //
31 struct DROPDOWNBUTTON {
32         DROPDOWNBUTTON* next;
33         UINT idButton;                                                           // command ID of button
34         UINT idMenu;                                                             // popup menu to display
35 };
36
37 // these define size of grippers
38 const GRIP_WIDTH   = 3;
39 const GRIP_MARGIN  = 5;
40
41 // flags stored in item data
42 #define ITEMF_INITIALIZED       0x01 // item data initialized
43 #define ITEMF_CHECKED           0x02 // item is checked
44
45 #ifdef _DEBUG
46 #define new DEBUG_NEW
47 #undef THIS_FILE
48 static char THIS_FILE[] = __FILE__;
49 #endif
50
51 ////////////////////////////////////////////////////////////////
52 // CFlatToolBar--does flat tool bar in MFC.
53 //
54 IMPLEMENT_DYNAMIC(CFlatToolBar, CFlatToolBarBase)
55
56 BEGIN_MESSAGE_MAP(CFlatToolBar, CFlatToolBarBase)
57         ON_NOTIFY_REFLECT(TBN_DROPDOWN,  OnTbnDropDown)
58         ON_WM_WINDOWPOSCHANGING()
59         ON_WM_WINDOWPOSCHANGED()
60         ON_WM_NCCALCSIZE()
61         ON_WM_ERASEBKGND()
62         ON_WM_NCCREATE()
63         ON_WM_PAINT()
64         ON_WM_CREATE()
65 END_MESSAGE_MAP()
66
67 CFlatToolBar::CFlatToolBar()
68 {
69         FBTRACE(_T("CFlatToolBar::CFlatToolBar, comctl32 version = %d\n"),
70                 iVerComCtl32);
71
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;
76         m_bNoEntry = FALSE;
77 }
78
79 CFlatToolBar::~CFlatToolBar()
80 {
81         while (m_pDropDownButtons) {
82                 DROPDOWNBUTTON* pnext = m_pDropDownButtons->next;
83                 delete m_pDropDownButtons;
84                 m_pDropDownButtons = pnext;
85         }
86 }
87
88 /////////////////
89 // Create handler: set flat style by default
90 //
91 int CFlatToolBar::OnCreate(LPCREATESTRUCT lpcs)
92 {
93         if (CFlatToolBarBase::OnCreate(lpcs) == -1)
94                 return -1;
95         ModifyStyle(0, TBSTYLE_FLAT);
96         return 0;  // OK
97 }
98
99 ////////////////
100 // Load function sets flat style after loading buttons.
101 //
102 BOOL CFlatToolBar::LoadToolBar(LPCTSTR lpszResourceName)
103 {
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.
107         //
108         DWORD dwStyle = GetStyle();
109         ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
110         BOOL bRet = CFlatToolBarBase::LoadToolBar(lpszResourceName);
111         SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
112         return bRet;
113 }
114
115 //////////////////
116 // Calcluate size of client area. Adds room for grippers
117 //
118 void CFlatToolBar::OnNcCalcSize(BOOL bCalc, NCCALCSIZE_PARAMS*  pncp)
119 {
120         if (m_bInCoolBar) { // if I am in a coolbar (rebar):
121                 Default();                // ..bypass CToolBar/CControlBar
122
123         } else {
124                 CRect& rc = (CRect&)pncp->rgrc[0]; // rect to return
125
126                 // copied from MFC below:
127                 CRect rcMargin(0,0,0,0);
128                 CControlBar::CalcInsideRect(rcMargin, m_dwStyle & CBRS_ORIENT_HORZ);
129
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;
135         }
136 }
137
138 //////////////////
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
143 // backgrounds).
144 // 
145 void CFlatToolBar::OnWindowPosChanging(LPWINDOWPOS lpwp)
146 {
147         if (m_bInCoolBar)
148                 // inside coolbars, don't do MFC thing
149                 Default();
150         else {
151                 CFlatToolBarBase::OnWindowPosChanging(lpwp);
152                 if (!(lpwp->flags & SWP_NOMOVE))
153                         GetWindowRect(&m_rcOldPos);              // remember old position
154         }
155 }
156
157 //////////////////
158 // Now toolbar has really moved: repaint area beneath old position
159 //
160 void CFlatToolBar::OnWindowPosChanged(LPWINDOWPOS lpwp)
161 {
162         if (m_bInCoolBar) {
163                 Default();
164         } else {
165                 CFlatToolBarBase::OnWindowPosChanged(lpwp);
166                 if (!(lpwp->flags & SWP_NOMOVE)) {       // if moved:
167                         InvalidateOldPos(m_rcOldPos);            // invalidate area of old position
168
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);
172                 }
173         }
174 }
175
176 //////////////////
177 // Invalidate toolbar rectangle. Because flat toolbars are transparent,
178 // this requires invalidating parent and all siblings that intersect the
179 // rectangle.
180 //
181 void CFlatToolBar::InvalidateOldPos(const CRect& rcInvalid)
182 {
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
189
190         // now do same for each sibling too
191         for (CWnd* pSib = pParent->GetWindow(GW_CHILD);
192                   pSib;
193                   pSib=pSib->GetNextWindow(GW_HWNDNEXT)) {
194
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!
201                 }
202         }
203 }
204
205 ////////////////
206 // Override to avoid MFC in case I'm inside a coolbar
207 //
208 BOOL CFlatToolBar::OnEraseBkgnd(CDC* pDC)
209 {
210         return m_bInCoolBar ? Default() : CFlatToolBarBase::OnEraseBkgnd(pDC);
211 }
212
213 //////////////////
214 // If toolbar is inside a coolbar, need to make the parent frame
215 // my owner so it will get notifications.
216 //
217 BOOL CFlatToolBar::OnNcCreate(LPCREATESTRUCT lpcs)
218 {
219         CWnd* pParent = GetParent();
220         ASSERT(pParent);
221         TCHAR classname[64];
222         GetClassName(pParent->m_hWnd, classname, countof(classname));
223         if (_tcscmp(classname, REBARCLASSNAME)==0) {
224                 CFrameWnd* pFrame = GetParentFrame();
225                 ASSERT_VALID(pFrame);
226                 SetOwner(pFrame);
227                 m_bInCoolBar = TRUE;
228         }
229         return CFlatToolBarBase::OnNcCreate(lpcs);
230 }
231
232 //////////////////
233 // Avoid MFC if I'm inside a coolbar
234 //
235 void CFlatToolBar::OnPaint()
236 {
237         if (m_bInCoolBar)
238                 Default();      // bypass CToolBar/CControlBar
239         else
240                 CFlatToolBarBase::OnPaint();
241 }
242
243 ////////////////////////////////////////////////////////////////
244 // Stuff for handling drop-down buttons in toobars
245 //
246
247 //////////////////
248 // Add dropdown buttons.
249 // The manager takes care of setting appropriate styles, etc.
250 //
251 // Args:
252 //              - array of LONGs: MAKELONG(commandID, menuID)
253 //              - number of buttons
254 //
255 BOOL CFlatToolBar::AddDropDownButton(UINT nIDButton, UINT nIDMenu, BOOL bArrow)
256 {
257         ASSERT_VALID(this);
258
259         DROPDOWNBUTTON* pb = FindDropDownButton(nIDButton);
260         if (!pb) {
261                 pb = new DROPDOWNBUTTON;
262                 ASSERT(pb);
263                 pb->next = m_pDropDownButtons;
264                 m_pDropDownButtons = pb;
265         }
266         pb->idButton = nIDButton;
267         pb->idMenu   = nIDMenu;
268
269         int iButton = CommandToIndex(nIDButton);
270
271         DWORD dwStyle = GetButtonStyle(iButton);
272         dwStyle |= TBSTYLE_DROPDOWN;
273         SetButtonStyle(iButton, dwStyle);
274
275         if (bArrow)
276                 SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
277
278         return TRUE;
279 }
280
281 //////////////////
282 // Find buttons structure for given ID
283 //
284 DROPDOWNBUTTON* CFlatToolBar::FindDropDownButton(UINT nID)
285 {
286         for (DROPDOWNBUTTON* pb = m_pDropDownButtons; pb; pb = pb->next) {
287                 if (pb->idButton == nID)
288                         return pb;
289         }
290         return NULL;
291 }
292
293 //////////////////
294 // Handle TBN_DROPDOWN
295 // Default is to display the specified menu at the right place.
296 // You can override to generate dynamic menus
297 //
298 // Args:
299 //              - NMTOOLBAR struct from TBN_DROPDOWN
300 //              - command id of button
301 //              - point to display menu at
302 //
303 void CFlatToolBar::OnTbnDropDown(NMHDR* pNMHDR, LRESULT* pRes)
304 {
305         const NMTOOLBAR& nmtb = *(NMTOOLBAR*)pNMHDR;
306
307         // get location of button
308         CRect rc;
309         GetRect(nmtb.iItem, rc);
310         ClientToScreen(&rc);
311
312         // call virtual function to display dropdown menu
313         OnDropDownButton(nmtb, nmtb.iItem, rc);
314 }
315
316 /////////////////
317 // Virtual fn you can override to hand drop-down button
318 // events with more friendly args
319 //
320 void CFlatToolBar::OnDropDownButton(const NMTOOLBAR& nmtb, UINT nID, CRect rc)
321 {
322         DROPDOWNBUTTON* pb = FindDropDownButton(nmtb.iItem);
323         if (pb && pb->idMenu) {
324
325                 // load and display popup menu
326                 CMenu menu;
327                 VERIFY(menu.LoadMenu(pb->idMenu));
328                 CMenu* pPopup = menu.GetSubMenu(0);
329                 ASSERT(pPopup);
330                 pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
331                         rc.left, rc.bottom, GetOwner(), &rc);
332         }
333 }
334