1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/tbar95.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && !defined(__SMARTPHONE__) 
  29 #include "wx/toolbar.h" 
  32     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  33     #include "wx/dynarray.h" 
  37     #include "wx/settings.h" 
  38     #include "wx/bitmap.h" 
  39     #include "wx/dcmemory.h" 
  40     #include "wx/control.h" 
  41     #include "wx/app.h"         // for GetComCtl32Version 
  45 #include "wx/sysopt.h" 
  47 #include "wx/msw/private.h" 
  50 #include "wx/msw/uxtheme.h" 
  53 // this define controls whether the code for button colours remapping (only 
  54 // useful for 16 or 256 colour images) is active at all, it's always turned off 
  55 // for CE where it doesn't compile (and is probably not needed anyhow) and may 
  56 // also be turned off for other systems if you always use 24bpp images and so 
  59     #define wxREMAP_BUTTON_COLOURS 
  60 #endif // !__WXWINCE__ 
  62 // ---------------------------------------------------------------------------- 
  64 // ---------------------------------------------------------------------------- 
  66 // these standard constants are not always defined in compilers headers 
  70     #define TBSTYLE_LIST            0x1000 
  71     #define TBSTYLE_FLAT            0x0800 
  74 #ifndef TBSTYLE_TRANSPARENT 
  75     #define TBSTYLE_TRANSPARENT     0x8000 
  78 #ifndef TBSTYLE_TOOLTIPS 
  79     #define TBSTYLE_TOOLTIPS        0x0100 
  84     #define TB_SETSTYLE             (WM_USER + 56) 
  85     #define TB_GETSTYLE             (WM_USER + 57) 
  89     #define TB_HITTEST              (WM_USER + 69) 
  93     #define TB_GETMAXSIZE           (WM_USER + 83) 
  96 // these values correspond to those used by comctl32.dll 
  97 #define DEFAULTBITMAPX   16 
  98 #define DEFAULTBITMAPY   15 
 100 // ---------------------------------------------------------------------------- 
 102 // ---------------------------------------------------------------------------- 
 104 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
) 
 116         style ( wxNO_BORDER | wxTB_HORIZONTAL) 
 125 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 126     EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent
) 
 127     EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged
) 
 128     EVT_ERASE_BACKGROUND(wxToolBar::OnEraseBackground
) 
 131 // ---------------------------------------------------------------------------- 
 133 // ---------------------------------------------------------------------------- 
 135 class wxToolBarTool 
: public wxToolBarToolBase
 
 138     wxToolBarTool(wxToolBar 
*tbar
, 
 140                   const wxString
& label
, 
 141                   const wxBitmap
& bmpNormal
, 
 142                   const wxBitmap
& bmpDisabled
, 
 144                   wxObject 
*clientData
, 
 145                   const wxString
& shortHelp
, 
 146                   const wxString
& longHelp
) 
 147         : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 148                             clientData
, shortHelp
, longHelp
) 
 153     wxToolBarTool(wxToolBar 
*tbar
, wxControl 
*control
) 
 154         : wxToolBarToolBase(tbar
, control
) 
 159     virtual void SetLabel(const wxString
& label
) 
 161         if ( label 
== m_label 
) 
 164         wxToolBarToolBase::SetLabel(label
); 
 166         // we need to update the label shown in the toolbar because it has a 
 167         // pointer to the internal buffer of the old label 
 169         // TODO: use TB_SETBUTTONINFO 
 172     // set/get the number of separators which we use to cover the space used by 
 173     // a control in the toolbar 
 174     void SetSeparatorsCount(size_t count
) { m_nSepCount 
= count
; } 
 175     size_t GetSeparatorsCount() const { return m_nSepCount
; } 
 180     DECLARE_NO_COPY_CLASS(wxToolBarTool
) 
 183 // ============================================================================ 
 185 // ============================================================================ 
 187 // ---------------------------------------------------------------------------- 
 189 // ---------------------------------------------------------------------------- 
 191 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 192                                          const wxString
& label
, 
 193                                          const wxBitmap
& bmpNormal
, 
 194                                          const wxBitmap
& bmpDisabled
, 
 196                                          wxObject 
*clientData
, 
 197                                          const wxString
& shortHelp
, 
 198                                          const wxString
& longHelp
) 
 200     return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 201                              clientData
, shortHelp
, longHelp
); 
 204 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 206     return new wxToolBarTool(this, control
); 
 209 // ---------------------------------------------------------------------------- 
 210 // wxToolBar construction 
 211 // ---------------------------------------------------------------------------- 
 213 void wxToolBar::Init() 
 216     m_disabledImgList 
= NULL
; 
 220     m_defaultWidth 
= DEFAULTBITMAPX
; 
 221     m_defaultHeight 
= DEFAULTBITMAPY
; 
 226 bool wxToolBar::Create(wxWindow 
*parent
, 
 231                        const wxString
& name
) 
 233     // common initialisation 
 234     if ( !CreateControl(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) ) 
 237     // MSW-specific initialisation 
 238     if ( !MSWCreateToolbar(pos
, size
) ) 
 241     wxSetCCUnicodeFormat(GetHwnd()); 
 243     // workaround for flat toolbar on Windows XP classic style: we have to set 
 244     // the style after creating the control; doing it at creation time doesn't work 
 246     if ( style 
& wxTB_FLAT 
) 
 248         LRESULT style 
= GetMSWToolbarStyle(); 
 250         if ( !(style 
& TBSTYLE_FLAT
) ) 
 251             ::SendMessage(GetHwnd(), TB_SETSTYLE
, 0, style 
| TBSTYLE_FLAT
); 
 253 #endif // wxUSE_UXTHEME 
 258 bool wxToolBar::MSWCreateToolbar(const wxPoint
& pos
, const wxSize
& size
) 
 260     if ( !MSWCreateControl(TOOLBARCLASSNAME
, wxEmptyString
, pos
, size
) ) 
 263     // toolbar-specific post initialisation 
 264     ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0); 
 269 void wxToolBar::Recreate() 
 271     const HWND hwndOld 
= GetHwnd(); 
 274         // we haven't been created yet, no need to recreate 
 278     // get the position and size before unsubclassing the old toolbar 
 279     const wxPoint pos 
= GetPosition(); 
 280     const wxSize size 
= GetSize(); 
 284     if ( !MSWCreateToolbar(pos
, size
) ) 
 287         wxFAIL_MSG( _T("recreating the toolbar failed") ); 
 292     // reparent all our children under the new toolbar 
 293     for ( wxWindowList::compatibility_iterator node 
= m_children
.GetFirst(); 
 295           node 
= node
->GetNext() ) 
 297         wxWindow 
*win 
= node
->GetData(); 
 298         if ( !win
->IsTopLevel() ) 
 299             ::SetParent(GetHwndOf(win
), GetHwnd()); 
 302     // only destroy the old toolbar now -- 
 303     // after all the children had been reparented 
 304     ::DestroyWindow(hwndOld
); 
 306     // it is for the old bitmap control and can't be used with the new one 
 309         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 313     if ( m_disabledImgList 
) 
 315         delete m_disabledImgList
; 
 316         m_disabledImgList 
= NULL
; 
 322 wxToolBar::~wxToolBar() 
 324     // we must refresh the frame size when the toolbar is deleted but the frame 
 325     // is not - otherwise toolbar leaves a hole in the place it used to occupy 
 326     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
 327     if ( frame 
&& !frame
->IsBeingDeleted() ) 
 328         frame
->SendSizeEvent(); 
 331         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 333     delete m_disabledImgList
; 
 336 wxSize 
wxToolBar::DoGetBestSize() const 
 341     if ( !::SendMessage(GetHwnd(), TB_GETMAXSIZE
, 0, (LPARAM
)&size
) ) 
 343         // maybe an old (< 0x400) Windows version? try to approximate the 
 344         // toolbar size ourselves 
 345         sizeBest 
= GetToolSize(); 
 346         sizeBest
.y 
+= 2 * ::GetSystemMetrics(SM_CYBORDER
); // Add borders 
 347         sizeBest
.x 
*= GetToolsCount(); 
 349         // reverse horz and vertical components if necessary 
 350         if ( HasFlag(wxTB_VERTICAL
) ) 
 353             sizeBest
.x 
= sizeBest
.y
; 
 359         sizeBest
.x 
= size
.cx
; 
 360         sizeBest
.y 
= size
.cy
; 
 363     CacheBestSize(sizeBest
); 
 368 WXDWORD 
wxToolBar::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 370     // toolbars never have border, giving one to them results in broken 
 372     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 374                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 377     if ( !(style 
& wxTB_NO_TOOLTIPS
) ) 
 378         msStyle 
|= TBSTYLE_TOOLTIPS
; 
 380     if ( style 
& (wxTB_FLAT 
| wxTB_HORZ_LAYOUT
) ) 
 382         // static as it doesn't change during the program lifetime 
 383         static const int s_verComCtl 
= wxApp::GetComCtl32Version(); 
 385         // comctl32.dll 4.00 doesn't support the flat toolbars and using this 
 386         // style with 6.00 (part of Windows XP) leads to the toolbar with 
 387         // incorrect background colour - and not using it still results in the 
 388         // correct (flat) toolbar, so don't use it there 
 389         if ( s_verComCtl 
> 400 && s_verComCtl 
< 600 ) 
 390             msStyle 
|= TBSTYLE_FLAT 
| TBSTYLE_TRANSPARENT
; 
 392         if ( s_verComCtl 
>= 470 && style 
& wxTB_HORZ_LAYOUT 
) 
 393             msStyle 
|= TBSTYLE_LIST
; 
 396     if ( style 
& wxTB_NODIVIDER 
) 
 397         msStyle 
|= CCS_NODIVIDER
; 
 399     if ( style 
& wxTB_NOALIGN 
) 
 400         msStyle 
|= CCS_NOPARENTALIGN
; 
 402     if ( style 
& wxTB_VERTICAL 
) 
 405     if( style 
& wxTB_BOTTOM 
) 
 406         msStyle 
|= CCS_BOTTOM
; 
 411 // ---------------------------------------------------------------------------- 
 412 // adding/removing tools 
 413 // ---------------------------------------------------------------------------- 
 415 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 417     // nothing special to do here - we really create the toolbar buttons in 
 421     InvalidateBestSize(); 
 425 bool wxToolBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 427     // the main difficulty we have here is with the controls in the toolbars: 
 428     // as we (sometimes) use several separators to cover up the space used by 
 429     // them, the indices are not the same for us and the toolbar 
 431     // first determine the position of the first button to delete: it may be 
 432     // different from pos if we use several separators to cover the space used 
 434     wxToolBarToolsList::compatibility_iterator node
; 
 435     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 437         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 440             // let node point to the next node in the list 
 441             node 
= node
->GetNext(); 
 446         if ( tool2
->IsControl() ) 
 447             pos 
+= ((wxToolBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 450     // now determine the number of buttons to delete and the area taken by them 
 451     size_t nButtonsToDelete 
= 1; 
 453     // get the size of the button we're going to delete 
 455     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 457         wxLogLastError(_T("TB_GETITEMRECT")); 
 460     int width 
= r
.right 
- r
.left
; 
 462     if ( tool
->IsControl() ) 
 464         nButtonsToDelete 
= ((wxToolBarTool 
*)tool
)->GetSeparatorsCount(); 
 465         width 
*= nButtonsToDelete
; 
 466         tool
->GetControl()->Destroy(); 
 469     // do delete all buttons 
 470     m_nButtons 
-= nButtonsToDelete
; 
 471     while ( nButtonsToDelete
-- > 0 ) 
 473         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 475             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 483     // and finally reposition all the controls after this button (the toolbar 
 484     // takes care of all normal items) 
 485     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 487         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 488         if ( tool2
->IsControl() ) 
 491             wxControl 
*control 
= tool2
->GetControl(); 
 492             control
->GetPosition(&x
, NULL
); 
 493             control
->Move(x 
- width
, wxDefaultCoord
); 
 497     InvalidateBestSize(); 
 502 void wxToolBar::CreateDisabledImageList() 
 504     if (m_disabledImgList 
!= NULL
) 
 506         delete m_disabledImgList
; 
 507         m_disabledImgList 
= NULL
; 
 510     // as we can't use disabled image list with older versions of comctl32.dll, 
 511     // don't even bother creating it 
 512     if ( wxApp::GetComCtl32Version() >= 470 ) 
 514         // search for the first disabled button img in the toolbar, if any 
 515         for ( wxToolBarToolsList::compatibility_iterator
 
 516                 node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 518             wxToolBarToolBase 
*tool 
= node
->GetData(); 
 519             wxBitmap bmpDisabled 
= tool
->GetDisabledBitmap(); 
 520             if ( bmpDisabled
.Ok() ) 
 522                 m_disabledImgList 
= new wxImageList
 
 526                                             bmpDisabled
.GetMask() != NULL
, 
 533         // we don't have any disabled bitmaps 
 537 bool wxToolBar::Realize() 
 539     const size_t nTools 
= GetToolsCount(); 
 544     const bool isVertical 
= HasFlag(wxTB_VERTICAL
); 
 546 #ifdef wxREMAP_BUTTON_COLOURS 
 547     // don't change the values of these constants, they can be set from the 
 548     // user code via wxSystemOptions 
 557     // the user-specified option overrides anything, but if it wasn't set, only 
 558     // remap the buttons on 8bpp displays as otherwise the bitmaps usually look 
 559     // much worse after remapping 
 560     static const wxChar 
*remapOption 
= wxT("msw.remap"); 
 561     const int remapValue 
= wxSystemOptions::HasOption(remapOption
) 
 562                                 ? wxSystemOptions::GetOptionInt(remapOption
) 
 563                                 : wxDisplayDepth() <= 8 ? Remap_Buttons
 
 566 #endif // wxREMAP_BUTTON_COLOURS 
 568     // delete all old buttons, if any 
 569     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 571         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 573             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 577     // First, add the bitmap: we use one bitmap for all toolbar buttons 
 578     // ---------------------------------------------------------------- 
 580     wxToolBarToolsList::compatibility_iterator node
; 
 584     if ( HasFlag(wxTB_NOICONS
) ) 
 586         // no icons, don't leave space for them 
 590     else // do show icons 
 592         // if we already have a bitmap, we'll replace the existing one -- 
 593         // otherwise we'll install a new one 
 594         HBITMAP oldToolBarBitmap 
= (HBITMAP
)m_hBitmap
; 
 596         sizeBmp
.x 
= m_defaultWidth
; 
 597         sizeBmp
.y 
= m_defaultHeight
; 
 599         const wxCoord totalBitmapWidth  
= m_defaultWidth 
* 
 600                                           wx_truncate_cast(wxCoord
, nTools
), 
 601                       totalBitmapHeight 
= m_defaultHeight
; 
 603         // Create a bitmap and copy all the tool bitmaps into it 
 604         wxMemoryDC dcAllButtons
; 
 605         wxBitmap 
bitmap(totalBitmapWidth
, totalBitmapHeight
); 
 606         dcAllButtons
.SelectObject(bitmap
); 
 608 #ifdef wxREMAP_BUTTON_COLOURS 
 609         if ( remapValue 
!= Remap_TransparentBg 
) 
 610 #endif // wxREMAP_BUTTON_COLOURS 
 612             // VZ: why do we hardcode grey colour for CE? 
 613             dcAllButtons
.SetBackground(wxBrush( 
 615                                         wxColour(0xc0, 0xc0, 0xc0) 
 616 #else // !__WXWINCE__ 
 617                                         GetBackgroundColour() 
 618 #endif // __WXWINCE__/!__WXWINCE__ 
 620             dcAllButtons
.Clear(); 
 623         m_hBitmap 
= bitmap
.GetHBITMAP(); 
 624         HBITMAP hBitmap 
= (HBITMAP
)m_hBitmap
; 
 626 #ifdef wxREMAP_BUTTON_COLOURS 
 627         if ( remapValue 
== Remap_Bg 
) 
 629             dcAllButtons
.SelectObject(wxNullBitmap
); 
 631             // Even if we're not remapping the bitmap 
 632             // content, we still have to remap the background. 
 633             hBitmap 
= (HBITMAP
)MapBitmap((WXHBITMAP
) hBitmap
, 
 634                 totalBitmapWidth
, totalBitmapHeight
); 
 636             dcAllButtons
.SelectObject(bitmap
); 
 638 #endif // wxREMAP_BUTTON_COLOURS 
 640         // the button position 
 643         // the number of buttons (not separators) 
 646         CreateDisabledImageList(); 
 647         for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 649             wxToolBarToolBase 
*tool 
= node
->GetData(); 
 650             if ( tool
->IsButton() ) 
 652                 const wxBitmap
& bmp 
= tool
->GetNormalBitmap(); 
 654                 const int w 
= bmp
.GetWidth(); 
 655                 const int h 
= bmp
.GetHeight(); 
 659                     int xOffset 
= wxMax(0, (m_defaultWidth 
- w
)/2); 
 660                     int yOffset 
= wxMax(0, (m_defaultHeight 
- h
)/2); 
 662                     // notice the last parameter: do use mask 
 663                     dcAllButtons
.DrawBitmap(bmp
, x 
+ xOffset
, yOffset
, true); 
 667                     wxFAIL_MSG( _T("invalid tool button bitmap") ); 
 670                 // also deal with disabled bitmap if we want to use them 
 671                 if ( m_disabledImgList 
) 
 673                     wxBitmap bmpDisabled 
= tool
->GetDisabledBitmap(); 
 674 #if wxUSE_IMAGE && wxUSE_WXDIB 
 675                     if ( !bmpDisabled
.Ok() ) 
 677                         // no disabled bitmap specified but we still need to 
 678                         // fill the space in the image list with something, so 
 679                         // we grey out the normal bitmap 
 681                         wxCreateGreyedImage(bmp
.ConvertToImage(), imgGreyed
); 
 683 #ifdef wxREMAP_BUTTON_COLOURS 
 684                         if ( remapValue 
== Remap_Buttons 
) 
 686                             // we need to have light grey background colour for 
 687                             // MapBitmap() to work correctly 
 688                             for ( int y 
= 0; y 
< h
; y
++ ) 
 690                                 for ( int x 
= 0; x 
< w
; x
++ ) 
 692                                     if ( imgGreyed
.IsTransparent(x
, y
) ) 
 693                                         imgGreyed
.SetRGB(x
, y
, 
 695                                                          wxLIGHT_GREY
->Green(), 
 696                                                          wxLIGHT_GREY
->Blue()); 
 700 #endif // wxREMAP_BUTTON_COLOURS 
 702                         bmpDisabled 
= wxBitmap(imgGreyed
); 
 704 #endif // wxUSE_IMAGE 
 706 #ifdef wxREMAP_BUTTON_COLOURS 
 707                     if ( remapValue 
== Remap_Buttons 
) 
 708                         MapBitmap(bmpDisabled
.GetHBITMAP(), w
, h
); 
 709 #endif // wxREMAP_BUTTON_COLOURS 
 711                     m_disabledImgList
->Add(bmpDisabled
); 
 714                 // still inc width and number of buttons because otherwise the 
 715                 // subsequent buttons will all be shifted which is rather confusing 
 716                 // (and like this you'd see immediately which bitmap was bad) 
 722         dcAllButtons
.SelectObject(wxNullBitmap
); 
 724         // don't delete this HBITMAP! 
 725         bitmap
.SetHBITMAP(0); 
 727 #ifdef wxREMAP_BUTTON_COLOURS 
 728         if ( remapValue 
== Remap_Buttons 
) 
 730             // Map to system colours 
 731             hBitmap 
= (HBITMAP
)MapBitmap((WXHBITMAP
) hBitmap
, 
 732                                          totalBitmapWidth
, totalBitmapHeight
); 
 734 #endif // wxREMAP_BUTTON_COLOURS 
 736         bool addBitmap 
= true; 
 738         if ( oldToolBarBitmap 
) 
 740 #ifdef TB_REPLACEBITMAP 
 741             if ( wxApp::GetComCtl32Version() >= 400 ) 
 743                 TBREPLACEBITMAP replaceBitmap
; 
 744                 replaceBitmap
.hInstOld 
= NULL
; 
 745                 replaceBitmap
.hInstNew 
= NULL
; 
 746                 replaceBitmap
.nIDOld 
= (UINT
) oldToolBarBitmap
; 
 747                 replaceBitmap
.nIDNew 
= (UINT
) hBitmap
; 
 748                 replaceBitmap
.nButtons 
= nButtons
; 
 749                 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP
, 
 750                                     0, (LPARAM
) &replaceBitmap
) ) 
 752                     wxFAIL_MSG(wxT("Could not replace the old bitmap")); 
 755                 ::DeleteObject(oldToolBarBitmap
); 
 761 #endif // TB_REPLACEBITMAP 
 763                 // we can't replace the old bitmap, so we will add another one 
 764                 // (awfully inefficient, but what else to do?) and shift the bitmap 
 765                 // indices accordingly 
 768                 bitmapId 
= m_nButtons
; 
 772         if ( addBitmap 
) // no old bitmap or we can't replace it 
 774             TBADDBITMAP addBitmap
; 
 776             addBitmap
.nID 
= (UINT
) hBitmap
; 
 777             if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP
, 
 778                                (WPARAM
) nButtons
, (LPARAM
)&addBitmap
) == -1 ) 
 780                 wxFAIL_MSG(wxT("Could not add bitmap to toolbar")); 
 784         if ( m_disabledImgList 
) 
 786             HIMAGELIST oldImageList 
= (HIMAGELIST
) 
 787                 ::SendMessage(GetHwnd(), 
 788                               TB_SETDISABLEDIMAGELIST
, 
 790                               (LPARAM
)GetHimagelistOf(m_disabledImgList
)); 
 792             // delete previous image list if any 
 794                 ::DeleteObject( oldImageList 
); 
 798     // don't call SetToolBitmapSize() as we don't want to change the values of 
 799     // m_defaultWidth/Height 
 800     if ( !::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, 
 801                         MAKELONG(sizeBmp
.x
, sizeBmp
.y
)) ) 
 803         wxLogLastError(_T("TB_SETBITMAPSIZE")); 
 806     // Next add the buttons and separators 
 807     // ----------------------------------- 
 809     TBBUTTON 
*buttons 
= new TBBUTTON
[nTools
]; 
 811     // this array will hold the indices of all controls in the toolbar 
 812     wxArrayInt controlIds
; 
 814     bool lastWasRadio 
= false; 
 816     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 818         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 820         // don't add separators to the vertical toolbar with old comctl32.dll 
 821         // versions as they didn't handle this properly 
 822         if ( isVertical 
&& tool
->IsSeparator() && 
 823                 wxApp::GetComCtl32Version() <= 472 ) 
 828         TBBUTTON
& button 
= buttons
[i
]; 
 830         wxZeroMemory(button
); 
 832         bool isRadio 
= false; 
 833         switch ( tool
->GetStyle() ) 
 835             case wxTOOL_STYLE_CONTROL
: 
 836                 button
.idCommand 
= tool
->GetId(); 
 837                 // fall through: create just a separator too 
 839             case wxTOOL_STYLE_SEPARATOR
: 
 840                 button
.fsState 
= TBSTATE_ENABLED
; 
 841                 button
.fsStyle 
= TBSTYLE_SEP
; 
 844             case wxTOOL_STYLE_BUTTON
: 
 845                 if ( !HasFlag(wxTB_NOICONS
) ) 
 846                     button
.iBitmap 
= bitmapId
; 
 848                 if ( HasFlag(wxTB_TEXT
) ) 
 850                     const wxString
& label 
= tool
->GetLabel(); 
 851                     if ( !label
.empty() ) 
 852                         button
.iString 
= (int)label
.c_str(); 
 855                 button
.idCommand 
= tool
->GetId(); 
 857                 if ( tool
->IsEnabled() ) 
 858                     button
.fsState 
|= TBSTATE_ENABLED
; 
 859                 if ( tool
->IsToggled() ) 
 860                     button
.fsState 
|= TBSTATE_CHECKED
; 
 862                 switch ( tool
->GetKind() ) 
 865                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 869                             // the first item in the radio group is checked by 
 870                             // default to be consistent with wxGTK and the menu 
 872                             button
.fsState 
|= TBSTATE_CHECKED
; 
 874                             if (tool
->Toggle(true)) 
 876                                 DoToggleTool(tool
, true); 
 879                         else if (tool
->IsToggled()) 
 881                             wxToolBarToolsList::compatibility_iterator nodePrev 
= node
->GetPrevious(); 
 882                             int prevIndex 
= i 
- 1; 
 885                                 TBBUTTON
& prevButton 
= buttons
[prevIndex
]; 
 886                                 wxToolBarToolBase 
*tool 
= nodePrev
->GetData(); 
 887                                 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO 
) 
 890                                 if ( tool
->Toggle(false) ) 
 891                                     DoToggleTool(tool
, false); 
 893                                 prevButton
.fsState 
= TBSTATE_ENABLED
; 
 894                                 nodePrev 
= nodePrev
->GetPrevious(); 
 903                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 907                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 911                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 912                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 920         lastWasRadio 
= isRadio
; 
 925     if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS
, (WPARAM
)i
, (LPARAM
)buttons
) ) 
 927         wxLogLastError(wxT("TB_ADDBUTTONS")); 
 932     // Deal with the controls finally 
 933     // ------------------------------ 
 935     // adjust the controls size to fit nicely in the toolbar 
 938     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext(), index
++ ) 
 940         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 942         // we calculate the running y coord for vertical toolbars so we need to 
 943         // get the items size for all items but for the horizontal ones we 
 944         // don't need to deal with the non controls 
 945         bool isControl 
= tool
->IsControl(); 
 946         if ( !isControl 
&& !isVertical 
) 
 949         // note that we use TB_GETITEMRECT and not TB_GETRECT because the 
 950         // latter only appeared in v4.70 of comctl32.dll 
 952         if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, 
 953                             index
, (LPARAM
)(LPRECT
)&r
) ) 
 955             wxLogLastError(wxT("TB_GETITEMRECT")); 
 960             // can only be control if isVertical 
 961             y 
+= r
.bottom 
- r
.top
; 
 966         wxControl 
*control 
= tool
->GetControl(); 
 967         wxSize size 
= control
->GetSize(); 
 969         // the position of the leftmost controls corner 
 970         int left 
= wxDefaultCoord
; 
 972         // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+ 
 973 #ifdef TB_SETBUTTONINFO 
 974         // available in headers, now check whether it is available now 
 976         if ( wxApp::GetComCtl32Version() >= 471 ) 
 978             // set the (underlying) separators width to be that of the 
 981             tbbi
.cbSize 
= sizeof(tbbi
); 
 982             tbbi
.dwMask 
= TBIF_SIZE
; 
 983             tbbi
.cx 
= (WORD
)size
.x
; 
 984             if ( !::SendMessage(GetHwnd(), TB_SETBUTTONINFO
, 
 985                                 tool
->GetId(), (LPARAM
)&tbbi
) ) 
 987                 // the id is probably invalid? 
 988                 wxLogLastError(wxT("TB_SETBUTTONINFO")); 
 992 #endif // comctl32.dll 4.71 
 993         // TB_SETBUTTONINFO unavailable 
 995             // try adding several separators to fit the controls width 
 996             int widthSep 
= r
.right 
- r
.left
; 
1002             tbb
.fsState 
= TBSTATE_ENABLED
; 
1003             tbb
.fsStyle 
= TBSTYLE_SEP
; 
1005             size_t nSeparators 
= size
.x 
/ widthSep
; 
1006             for ( size_t nSep 
= 0; nSep 
< nSeparators
; nSep
++ ) 
1008                 if ( !::SendMessage(GetHwnd(), TB_INSERTBUTTON
, 
1009                                     index
, (LPARAM
)&tbb
) ) 
1011                     wxLogLastError(wxT("TB_INSERTBUTTON")); 
1017             // remember the number of separators we used - we'd have to 
1018             // delete all of them later 
1019             ((wxToolBarTool 
*)tool
)->SetSeparatorsCount(nSeparators
); 
1021             // adjust the controls width to exactly cover the separators 
1022             control
->SetSize((nSeparators 
+ 1)*widthSep
, wxDefaultCoord
); 
1025         // position the control itself correctly vertically 
1026         int height 
= r
.bottom 
- r
.top
; 
1027         int diff 
= height 
- size
.y
; 
1030             // the control is too high, resize to fit 
1031             control
->SetSize(wxDefaultCoord
, height 
- 2); 
1042             y 
+= height 
+ 2 * GetMargins().y
; 
1044         else // horizontal toolbar 
1046             if ( left 
== wxDefaultCoord 
) 
1052         control
->Move(left
, top 
+ (diff 
+ 1) / 2); 
1055     // the max index is the "real" number of buttons - i.e. counting even the 
1056     // separators which we added just for aligning the controls 
1061         if ( m_maxRows 
== 0 ) 
1062             // if not set yet, only one row 
1065     else if ( m_nButtons 
> 0 ) // vertical non empty toolbar 
1067         if ( m_maxRows 
== 0 ) 
1068             // if not set yet, have one column 
1069             SetRows(m_nButtons
); 
1072     InvalidateBestSize(); 
1078 // ---------------------------------------------------------------------------- 
1080 // ---------------------------------------------------------------------------- 
1082 bool wxToolBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id
) 
1084     wxToolBarToolBase 
*tool 
= FindById((int)id
); 
1088     bool toggled 
= false; // just to suppress warnings 
1090     if ( tool
->CanBeToggled() ) 
1092         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
1093         toggled 
= (state 
& TBSTATE_CHECKED
) != 0; 
1095         // ignore the event when a radio button is released, as this doesn't 
1096         // seem to happen at all, and is handled otherwise 
1097         if ( tool
->GetKind() == wxITEM_RADIO 
&& !toggled 
) 
1100         tool
->Toggle(toggled
); 
1101         UnToggleRadioGroup(tool
); 
1104     // OnLeftClick() can veto the button state change - for buttons which 
1105     // may be toggled only, of couse 
1106     if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
1109         tool
->Toggle(!toggled
); 
1111         ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(!toggled
, 0)); 
1117 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl
), 
1119                             WXLPARAM 
*WXUNUSED(result
)) 
1121     if( !HasFlag(wxTB_NO_TOOLTIPS
) ) 
1124         // First check if this applies to us 
1125         NMHDR 
*hdr 
= (NMHDR 
*)lParam
; 
1127         // the tooltips control created by the toolbar is sometimes Unicode, even 
1128         // in an ANSI application - this seems to be a bug in comctl32.dll v5 
1129         UINT code 
= hdr
->code
; 
1130         if ( (code 
!= (UINT
) TTN_NEEDTEXTA
) && (code 
!= (UINT
) TTN_NEEDTEXTW
) ) 
1133         HWND toolTipWnd 
= (HWND
)::SendMessage(GetHwnd(), TB_GETTOOLTIPS
, 0, 0); 
1134         if ( toolTipWnd 
!= hdr
->hwndFrom 
) 
1137         LPTOOLTIPTEXT ttText 
= (LPTOOLTIPTEXT
)lParam
; 
1138         int id 
= (int)ttText
->hdr
.idFrom
; 
1140         wxToolBarToolBase 
*tool 
= FindById(id
); 
1142             return HandleTooltipNotify(code
, lParam
, tool
->GetShortHelp()); 
1144         wxUnusedVar(lParam
); 
1151 // ---------------------------------------------------------------------------- 
1153 // ---------------------------------------------------------------------------- 
1155 void wxToolBar::SetToolBitmapSize(const wxSize
& size
) 
1157     wxToolBarBase::SetToolBitmapSize(size
); 
1159     ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, MAKELONG(size
.x
, size
.y
)); 
1162 void wxToolBar::SetRows(int nRows
) 
1164     if ( nRows 
== m_maxRows 
) 
1166         // avoid resizing the frame uselessly 
1170     // TRUE in wParam means to create at least as many rows, FALSE - 
1173     ::SendMessage(GetHwnd(), TB_SETROWS
, 
1174                   MAKEWPARAM(nRows
, !(GetWindowStyle() & wxTB_VERTICAL
)), 
1182 // The button size is bigger than the bitmap size 
1183 wxSize 
wxToolBar::GetToolSize() const 
1185     // TB_GETBUTTONSIZE is supported from version 4.70 
1186 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ 
1187     && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) \ 
1188     && !defined (__DIGITALMARS__) 
1189     if ( wxApp::GetComCtl32Version() >= 470 ) 
1191         DWORD dw 
= ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE
, 0, 0); 
1193         return wxSize(LOWORD(dw
), HIWORD(dw
)); 
1196 #endif // comctl32.dll 4.70+ 
1199         return wxSize(m_defaultWidth 
+ 8, m_defaultHeight 
+ 7); 
1204 wxToolBarToolBase 
*GetItemSkippingDummySpacers(const wxToolBarToolsList
& tools
, 
1207     wxToolBarToolsList::compatibility_iterator current 
= tools
.GetFirst(); 
1209     for ( ; current 
; current 
= current
->GetNext() ) 
1212             return current
->GetData(); 
1214         wxToolBarTool 
*tool 
= (wxToolBarTool 
*)current
->GetData(); 
1215         size_t separators 
= tool
->GetSeparatorsCount(); 
1217         // if it is a normal button, sepcount == 0, so skip 1 item (the button) 
1218         // otherwise, skip as many items as the separator count, plus the 
1220         index 
-= separators 
? separators 
+ 1 : 1; 
1226 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord x
, wxCoord y
) const 
1231     int index 
= (int)::SendMessage(GetHwnd(), TB_HITTEST
, 0, (LPARAM
)&pt
); 
1233     // MBN: when the point ( x, y ) is close to the toolbar border 
1234     //      TB_HITTEST returns m_nButtons ( not -1 ) 
1235     if ( index 
< 0 || (size_t)index 
>= m_nButtons 
) 
1236         // it's a separator or there is no tool at all there 
1237         return (wxToolBarToolBase 
*)NULL
; 
1239     // when TB_SETBUTTONINFO is available (both during compile- and run-time), 
1240     // we don't use the dummy separators hack 
1241 #ifdef TB_SETBUTTONINFO 
1242     if ( wxApp::GetComCtl32Version() >= 471 ) 
1244         return m_tools
.Item((size_t)index
)->GetData(); 
1247 #endif // TB_SETBUTTONINFO 
1249         return GetItemSkippingDummySpacers( m_tools
, (size_t) index 
); 
1253 void wxToolBar::UpdateSize() 
1255     wxPoint pos 
= GetPosition(); 
1256     ::SendMessage(GetHwnd(), TB_AUTOSIZE
, 0, 0); 
1257     if (pos 
!= GetPosition()) 
1260     // In case Realize is called after the initial display (IOW the programmer 
1261     // may have rebuilt the toolbar) give the frame the option of resizing the 
1262     // toolbar to full width again, but only if the parent is a frame and the 
1263     // toolbar is managed by the frame.  Otherwise assume that some other 
1264     // layout mechanism is controlling the toolbar size and leave it alone. 
1265     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
1266     if ( frame 
&& frame
->GetToolBar() == this ) 
1268         frame
->SendSizeEvent(); 
1272 // ---------------------------------------------------------------------------- 
1274 // --------------------------------------------------------------------------- 
1276 // get the TBSTYLE of the given toolbar window 
1277 long wxToolBar::GetMSWToolbarStyle() const 
1279     return ::SendMessage(GetHwnd(), TB_GETSTYLE
, 0, 0L); 
1282 void wxToolBar::SetWindowStyleFlag(long style
) 
1284     // the style bits whose changes force us to recreate the toolbar 
1285     static const long MASK_NEEDS_RECREATE 
= wxTB_TEXT 
| wxTB_NOICONS
; 
1287     const long styleOld 
= GetWindowStyle(); 
1289     wxToolBarBase::SetWindowStyleFlag(style
); 
1291     // don't recreate an empty toolbar: not only this is unnecessary, but it is 
1292     // also fatal as we'd then try to recreate the toolbar when it's just being 
1294     if ( GetToolsCount() && 
1295             (style 
& MASK_NEEDS_RECREATE
) != (styleOld 
& MASK_NEEDS_RECREATE
) ) 
1297         // to remove the text labels, simply re-realizing the toolbar is enough 
1298         // but I don't know of any way to add the text to an existing toolbar 
1299         // other than by recreating it entirely 
1304 // ---------------------------------------------------------------------------- 
1306 // ---------------------------------------------------------------------------- 
1308 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*tool
, bool enable
) 
1310     ::SendMessage(GetHwnd(), TB_ENABLEBUTTON
, 
1311                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(enable
, 0)); 
1314 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*tool
, bool toggle
) 
1316     ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, 
1317                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(toggle
, 0)); 
1320 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
1322     // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or 
1323     //     without, so we really need to delete the button and recreate it here 
1324     wxFAIL_MSG( _T("not implemented") ); 
1327 // ---------------------------------------------------------------------------- 
1329 // ---------------------------------------------------------------------------- 
1331 // Responds to colour changes, and passes event on to children. 
1332 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
1334     wxRGBToColour(m_backgroundColour
, ::GetSysColor(COLOR_BTNFACE
)); 
1336     // Remap the buttons 
1339     // Relayout the toolbar 
1340     int nrows 
= m_maxRows
; 
1341     m_maxRows 
= 0;      // otherwise SetRows() wouldn't do anything 
1346     // let the event propagate further 
1350 void wxToolBar::OnMouseEvent(wxMouseEvent
& event
) 
1352     if (event
.Leaving() && m_pInTool
) 
1359     if ( event
.RightDown() ) 
1361         // find the tool under the mouse 
1362         wxCoord x 
= 0, y 
= 0; 
1363         event
.GetPosition(&x
, &y
); 
1365         wxToolBarToolBase 
*tool 
= FindToolForPosition(x
, y
); 
1366         OnRightClick(tool 
? tool
->GetId() : -1, x
, y
); 
1374 // This handler is required to allow the toolbar to be set to a non-default 
1375 // colour: for example, when it must blend in with a notebook page. 
1376 void wxToolBar::OnEraseBackground(wxEraseEvent
& event
) 
1378     RECT rect 
= wxGetClientRect(GetHwnd()); 
1379     HDC hdc 
= GetHdcOf((*event
.GetDC())); 
1382     // we may need to draw themed colour so that we appear correctly on 
1383     // e.g. notebook page under XP with themes but only do it if the parent 
1384     // draws themed background itself 
1385     if ( !UseBgCol() && !GetParent()->UseBgCol() ) 
1387         wxUxThemeEngine 
*theme 
= wxUxThemeEngine::GetIfActive(); 
1391                 hr 
= theme
->DrawThemeParentBackground(GetHwnd(), hdc
, &rect
); 
1395             // it can also return S_FALSE which seems to simply say that it 
1396             // didn't draw anything but no error really occurred 
1398                 wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr
); 
1401 #endif // wxUSE_UXTHEME 
1403     if ( UseBgCol() || (GetMSWToolbarStyle() & TBSTYLE_TRANSPARENT
) ) 
1405         // do draw our background 
1407         // notice that this 'dumb' implementation may cause flicker for some of 
1408         // the controls in which case they should intercept wxEraseEvent and 
1409         // process it themselves somehow 
1410         AutoHBRUSH 
hBrush(wxColourToRGB(GetBackgroundColour())); 
1412         wxCHANGE_HDC_MAP_MODE(hdc
, MM_TEXT
); 
1413         ::FillRect(hdc
, &rect
, hBrush
); 
1415     else // we have no non default background colour 
1417         // let the system do it for us 
1422 bool wxToolBar::HandleSize(WXWPARAM 
WXUNUSED(wParam
), WXLPARAM lParam
) 
1424     // calculate our minor dimension ourselves - we're confusing the standard 
1425     // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks 
1427     if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT
, 0, (LPARAM
)&r
) ) 
1431         if ( GetWindowStyle() & wxTB_VERTICAL 
) 
1433             w 
= r
.right 
- r
.left
; 
1436                 w 
*= (m_nButtons 
+ m_maxRows 
- 1)/m_maxRows
; 
1443             if (HasFlag( wxTB_FLAT 
)) 
1444                 h 
= r
.bottom 
- r
.top 
- 3; 
1446                 h 
= r
.bottom 
- r
.top
; 
1449                 // FIXME: hardcoded separator line height... 
1450                 h 
+= HasFlag(wxTB_NODIVIDER
) ? 4 : 6; 
1455         if ( MAKELPARAM(w
, h
) != lParam 
) 
1457             // size really changed 
1461         // message processed 
1468 bool wxToolBar::HandlePaint(WXWPARAM wParam
, WXLPARAM lParam
) 
1470     // erase any dummy separators which were used 
1471     // for aligning the controls if any here 
1473     // first of all, are there any controls at all? 
1474     wxToolBarToolsList::compatibility_iterator node
; 
1475     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
1477         if ( node
->GetData()->IsControl() ) 
1482         // no controls, nothing to erase 
1485     // prepare the DC on which we'll be drawing 
1486     wxClientDC 
dc(this); 
1487     dc
.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID
)); 
1488     dc
.SetPen(*wxTRANSPARENT_PEN
); 
1491     if ( !::GetUpdateRect(GetHwnd(), &r
, FALSE
) ) 
1492         // nothing to redraw anyhow 
1496     wxCopyRECTToRect(r
, rectUpdate
); 
1498     dc
.SetClippingRegion(rectUpdate
); 
1500     // draw the toolbar tools, separators &c normally 
1501     wxControl::MSWWindowProc(WM_PAINT
, wParam
, lParam
); 
1503     // for each control in the toolbar find all the separators intersecting it 
1506     // NB: this is really the only way to do it as we don't know if a separator 
1507     //     corresponds to a control (i.e. is a dummy one) or a real one 
1509     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
1511         wxToolBarToolBase 
*tool 
= node
->GetData(); 
1512         if ( tool
->IsControl() ) 
1514             // get the control rect in our client coords 
1515             wxControl 
*control 
= tool
->GetControl(); 
1516             wxRect rectCtrl 
= control
->GetRect(); 
1518             // iterate over all buttons 
1520             int count 
= ::SendMessage(GetHwnd(), TB_BUTTONCOUNT
, 0, 0); 
1521             for ( int n 
= 0; n 
< count
; n
++ ) 
1523                 // is it a separator? 
1524                 if ( !::SendMessage(GetHwnd(), TB_GETBUTTON
, 
1527                     wxLogDebug(_T("TB_GETBUTTON failed?")); 
1532                 if ( tbb
.fsStyle 
!= TBSTYLE_SEP 
) 
1535                 // get the bounding rect of the separator 
1537                 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, 
1540                     wxLogDebug(_T("TB_GETITEMRECT failed?")); 
1545                 // does it intersect the control? 
1547                 wxCopyRECTToRect(r
, rectItem
); 
1548                 if ( rectCtrl
.Intersects(rectItem
) ) 
1550                     // yes, do erase it! 
1551                     dc
.DrawRectangle(rectItem
); 
1553                     // Necessary in case we use a no-paint-on-size 
1554                     // style in the parent: the controls can disappear 
1555                     control
->Refresh(false); 
1564 void wxToolBar::HandleMouseMove(WXWPARAM 
WXUNUSED(wParam
), WXLPARAM lParam
) 
1566     wxCoord x 
= GET_X_LPARAM(lParam
), 
1567             y 
= GET_Y_LPARAM(lParam
); 
1568     wxToolBarToolBase
* tool 
= FindToolForPosition( x
, y 
); 
1570     // cursor left current tool 
1571     if ( tool 
!= m_pInTool 
&& !tool 
) 
1577     // cursor entered a tool 
1578     if ( tool 
!= m_pInTool 
&& tool 
) 
1581         OnMouseEnter( tool
->GetId() ); 
1585 WXLRESULT 
wxToolBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1590             // we don't handle mouse moves, so always pass the message to 
1591             // wxControl::MSWWindowProc (HandleMouseMove just calls OnMouseEnter) 
1592             HandleMouseMove(wParam
, lParam
); 
1596             if ( HandleSize(wParam
, lParam
) ) 
1602             if ( HandlePaint(wParam
, lParam
) ) 
1610     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
1613 // ---------------------------------------------------------------------------- 
1614 // private functions 
1615 // ---------------------------------------------------------------------------- 
1617 #ifdef wxREMAP_BUTTON_COLOURS 
1619 WXHBITMAP 
wxToolBar::MapBitmap(WXHBITMAP bitmap
, int width
, int height
) 
1625         wxLogLastError(_T("CreateCompatibleDC")); 
1630     SelectInHDC 
bmpInHDC(hdcMem
, (HBITMAP
)bitmap
); 
1634         wxLogLastError(_T("SelectObject")); 
1639     wxCOLORMAP 
*cmap 
= wxGetStdColourMap(); 
1641     for ( int i 
= 0; i 
< width
; i
++ ) 
1643         for ( int j 
= 0; j 
< height
; j
++ ) 
1645             COLORREF pixel 
= ::GetPixel(hdcMem
, i
, j
); 
1647             for ( size_t k 
= 0; k 
< wxSTD_COL_MAX
; k
++ ) 
1649                 COLORREF col 
= cmap
[k
].from
; 
1650                 if ( abs(GetRValue(pixel
) - GetRValue(col
)) < 10 && 
1651                      abs(GetGValue(pixel
) - GetGValue(col
)) < 10 && 
1652                      abs(GetBValue(pixel
) - GetBValue(col
)) < 10 ) 
1654                     if ( cmap
[k
].to 
!= pixel 
) 
1655                         ::SetPixel(hdcMem
, i
, j
, cmap
[k
].to
); 
1665 #endif // wxREMAP_BUTTON_COLOURS 
1667 #endif // wxUSE_TOOLBAR